diff options
-rw-r--r-- | archive.h | 5 | ||||
-rw-r--r-- | concat.c | 67 | ||||
-rw-r--r-- | html.c | 59 |
3 files changed, 113 insertions, 18 deletions
diff --git a/archive.h b/archive.h index addd94d..541c03c 100644 --- a/archive.h +++ b/archive.h @@ -184,6 +184,11 @@ int mboxBody(FILE *file, const char *body); int htmlMessageHead(FILE *file, const struct Envelope *envelope); int htmlMessageTail(FILE *file); +int htmlThreadHead(FILE *file, const struct Envelope *envelope); +int htmlThreadHeader(FILE *file, const struct Envelope *envelope); +int htmlThreadOpen(FILE *file); +int htmlThreadClose(FILE *file); +int htmlThreadTail(FILE *file); int atomEntryHead(FILE *file, const struct Envelope *envelope); int atomEntryTail(FILE *file); diff --git a/concat.c b/concat.c index a2b767a..6d0e507 100644 --- a/concat.c +++ b/concat.c @@ -77,6 +77,27 @@ static int concatFile(FILE *dst, const char *path) { return 0; } +static int concatHTML(FILE *file, struct List thread) { + static char path[PATH_MAX]; + int error; + for (size_t i = 0; i < thread.len; ++i) { + error = htmlThreadOpen(file); + if (error) return error; + if (thread.ptr[i].type == List) { + error = concatHTML(file, thread.ptr[i].list); + } else { + uint32_t uid = dataCheck(thread.ptr[i], Number).number; + error = concatFile(file, pathUID(path, uid, "html")); + } + if (error) return error; + } + for (size_t i = 0; i < thread.len; ++i) { + error = htmlThreadClose(file); + if (error) return error; + } + return 0; +} + void concatData(struct List threads, struct List items) { uint32_t uid = 0; struct Envelope envelope = {0}; @@ -99,43 +120,55 @@ void concatData(struct List threads, struct List items) { listFlatten(&flat, thread); int error; - struct stat file; + FILE *file; + struct stat status; char dst[PATH_MAX]; char src[PATH_MAX]; - pathThread(dst, envelope.messageID, "mbox"); - error = stat(dst, &file); - if (error || file.st_mtime < uidNewest(flat, "mbox")) { - FILE *mbox = fopen(dst, "w"); - if (!mbox) err(EX_CANTCREAT, "%s", dst); + error = stat(pathThread(dst, envelope.messageID, "mbox"), &status); + if (error || status.st_mtime < uidNewest(flat, "mbox")) { + file = fopen(dst, "w"); + if (!file) err(EX_CANTCREAT, "%s", dst); for (size_t i = 0; i < flat.len; ++i) { uint32_t uid = dataCheck(flat.ptr[i], Number).number; - error = concatFile(mbox, pathUID(src, uid, "mbox")); + error = concatFile(file, pathUID(src, uid, "mbox")); if (error) err(EX_IOERR, "%s", dst); } - error = fclose(mbox); + error = fclose(file); if (error) err(EX_IOERR, "%s", dst); } - pathThread(dst, envelope.messageID, "atom"); - error = stat(dst, &file); - if (error || file.st_mtime < uidNewest(flat, "atom")) { - FILE *atom = fopen(dst, "w"); - if (!atom) err(EX_CANTCREAT, "%s", dst); + error = stat(pathThread(dst, envelope.messageID, "atom"), &status); + if (error || status.st_mtime < uidNewest(flat, "atom")) { + FILE *file = fopen(dst, "w"); + if (!file) err(EX_CANTCREAT, "%s", dst); - error = atomFeedHead(atom, &envelope); + error = atomFeedHead(file, &envelope); if (error) err(EX_IOERR, "%s", dst); for (size_t i = 0; i < flat.len; ++i) { uint32_t uid = dataCheck(flat.ptr[i], Number).number; - error = concatFile(atom, pathUID(src, uid, "atom")); + error = concatFile(file, pathUID(src, uid, "atom")); if (error) err(EX_IOERR, "%s", dst); } - error = atomFeedTail(atom) - || fclose(atom); + error = atomFeedTail(file) || fclose(file); + if (error) err(EX_IOERR, "%s", dst); + } + + error = stat(pathThread(dst, envelope.messageID, "html"), &status); + if (error || status.st_mtime < uidNewest(flat, "html")) { + FILE *file = fopen(dst, "w"); + if (!file) err(EX_CANTCREAT, "%s", dst); + + error = 0 + || htmlThreadHead(file, &envelope) // TODO: Include -h file. + || htmlThreadHeader(file, &envelope) + || concatHTML(file, thread) + || htmlThreadTail(file) + || fclose(file); if (error) err(EX_IOERR, "%s", dst); } diff --git a/html.c b/html.c index de64ed8..e92ab0a 100644 --- a/html.c +++ b/html.c @@ -79,6 +79,7 @@ int htmlMessageHead(FILE *file, const struct Envelope *envelope) { { "re", (strncmp(envelope->subject, "Re: ", 4) ? "Re: " : "") }, { "subject", envelope->subject }, { "messageID", envelope->messageID }, + { "pathID", pathMangle(envelope->messageID) }, {0}, }; char *fragment = templateURL("#[messageID]", urlVars); @@ -86,7 +87,7 @@ int htmlMessageHead(FILE *file, const struct Envelope *envelope) { "mailto:[mailbox]@[host]?subject=[re][subject]&In-Reply-To=[messageID]", urlVars ); - char *mbox = templateURL("../message/[messageID].mbox", urlVars); + char *mbox = templateURL("../message/[pathID].mbox", urlVars); char date[256]; char utc[sizeof("0000-00-00T00:00:00Z")]; @@ -127,3 +128,59 @@ int htmlMessageTail(FILE *file) { int n = fprintf(file, "</details>\n"); return (n < 0 ? n : 0); } + +int htmlThreadHead(FILE *file, const struct Envelope *envelope) { + struct Variable urlVars[] = { + { "pathID", pathMangle(envelope->messageID) }, + {0}, + }; + char *path = templateURL("[pathID]", urlVars); + + struct Variable vars[] = { + { "subject", envelope->subject }, + { "path", path }, + {0}, + }; + const char *Head = TEMPLATE( + <!DOCTYPE html> + <meta charset="utf-8"> + <title>[subject]</title> + <link rel="alternate" type="application/atom+xml" href="[path].atom"> + <link rel="alternate" type="application/mbox" href="[path].mbox"> + <style> + address { display: inline; } + section.thread section.thread:not(:first-child) { + border-left: 1px solid gray; + padding-left: 2ch; + } + </style> + ); + int error = templateRender(file, Head, vars, escapeXML); + free(path); + return error; +} + +int htmlThreadHeader(FILE *file, const struct Envelope *envelope) { + struct Variable vars[] = { + { "subject", envelope->subject }, + {0}, + }; + const char *Header = TEMPLATE( + <h1>[subject]</h1> + ); + return templateRender(file, Header, vars, escapeXML); +} + +int htmlThreadOpen(FILE *file) { + int n = fprintf(file, TEMPLATE(<section class="thread">)); + return (n < 0 ? n : 0); +} + +int htmlThreadClose(FILE *file) { + int n = fprintf(file, TEMPLATE(</section>)); + return (n < 0 ? n : 0); +} + +int htmlThreadTail(FILE *file) { + return 0; +} |