diff options
Diffstat (limited to '')
-rw-r--r-- | html.c | 218 |
1 files changed, 127 insertions, 91 deletions
diff --git a/html.c b/html.c index d6bf723..090bfab 100644 --- a/html.c +++ b/html.c @@ -24,161 +24,197 @@ #include "archive.h" static int htmlAddress(FILE *file, const char *class, struct Address addr) { - struct Variable vars[] = { - { "class", class }, - { "name", addressName(addr) }, - { "mailbox", addr.mailbox }, - {0}, - }; + const char *template; if (addr.host) { - return templateRender( - file, - TEMPLATE(<li><address class="[class]">[name]</address></li>), - vars, - escapeXML + template = TEMPLATE( + <li><address class="[class]">[name]</address></li> ); } else if (addr.mailbox) { - return templateRender( - file, - TEMPLATE(<li><address class="[class] group">[mailbox]<ul>), - vars, - escapeXML + template = TEMPLATE( + <li> + <address class="[class] group">[mailbox]</address> + <ul class="group"> ); } else { - return templateRender( - file, - TEMPLATE(</ul></address></li>), - vars, - escapeXML + template = TEMPLATE( + </ul> + </li> ); } + struct Variable vars[] = { + { "class", class }, + { "name", addressName(addr) }, + { "mailbox", addr.mailbox }, + {0}, + }; + return templateRender(file, template, vars, escapeXML); } static int htmlAddressList(FILE *file, const char *class, struct AddressList list) { if (!list.len) return 0; + const char *template = TEMPLATE( + <ul class="[class]"> + ); struct Variable vars[] = { { "class", class }, {0}, }; - int error = templateRender( - file, TEMPLATE(<ul class="[class]">), vars, escapeXML - ); + int error = templateRender(file, template, vars, escapeXML); if (error) return error; for (size_t i = 0; i < list.len; ++i) { error = htmlAddress(file, class, list.addrs[i]); if (error) return error; } - return templateRender(file, TEMPLATE(</ul>), vars, escapeXML); + return templateRender(file, TEMPLATE(</ul>), NULL, NULL); } -int htmlMessageHead(FILE *file, const struct Envelope *envelope) { - struct Variable urlVars[] = { - { "mailbox", envelope->replyTo.mailbox }, - { "host", envelope->replyTo.host }, +static char *htmlMailto(const struct Envelope *envelope) { + const char *template = { + "mailto:[mailbox]@[host]?subject=[re][subject]&In-Reply-To=[messageID]" + }; + struct Variable vars[] = { + { "mailbox", envelope->from.mailbox }, + { "host", envelope->from.host }, { "re", (strncmp(envelope->subject, "Re: ", 4) ? "Re: " : "") }, { "subject", envelope->subject }, { "messageID", envelope->messageID }, - { "pathID", pathSafe(envelope->messageID) }, {0}, }; - char *fragment = templateURL("#[messageID]", urlVars); - char *mailto = templateURL( - "mailto:[mailbox]@[host]?subject=[re][subject]&In-Reply-To=[messageID]", - urlVars - ); - char *mbox = templateURL("../message/[pathID].mbox", urlVars); + return templateURL(template, vars); +} + +static char *htmlFragment(const struct Envelope *envelope) { + struct Variable vars[] = { + { "messageID", envelope->messageID }, + {0}, + }; + return templateURL("#[messageID]", vars); +} +static char *htmlMbox(const struct Envelope *envelope) { + struct Variable vars[] = { + { "name", pathSafe(envelope->messageID) }, + {0}, + }; + return templateURL("../message/[name].mbox", vars); +} + +int htmlMessageOpen(FILE *file, const struct Envelope *envelope) { + // TODO: Conditionally include mailto: link. + const char *template1 = TEMPLATE( + <article class="message" id="[messageID]"> + <header> + <h2>[subject]</h2> + <address class="from"> + <a href="[mailto]">[from]</a> + </address> + <time datetime="[utc]">[date]</time> + ); + const char *template2 = TEMPLATE( + <nav> + <ul> + <li><a href="[fragment]">permalink</a></li> + <li><a href="[mbox]">mbox</a></li> + </ul> + </nav> + </header> + ); + char *mailto = htmlMailto(envelope); char utc[sizeof("0000-00-00T00:00:00Z")]; strftime(utc, sizeof(utc), "%FT%TZ", gmtime(&envelope->time)); + char *fragment = htmlFragment(envelope); + char *mbox = htmlMbox(envelope); struct Variable vars[] = { { "messageID", envelope->messageID }, - { "fragment", fragment }, { "subject", envelope->subject }, { "mailto", mailto }, { "from", addressName(envelope->from) }, - { "date", envelope->date }, { "utc", utc }, + { "date", envelope->date }, + { "fragment", fragment }, { "mbox", mbox }, {0}, }; - const char *Summary = TEMPLATE( - <details class="message" id="[messageID]"> - <summary> - <a class="subject" href="[fragment]">[subject]</a> - <address class="from"><a href="[mailto]">[from]</a></address> - <time datetime="[utc]">[date]</time> - <a class="mbox" href="[mbox]">mbox</a> - </summary> - ); - int error = templateRender(file, Summary, vars, escapeXML); - free(fragment); + int error = 0 + || templateRender(file, template1, vars, escapeXML) + || htmlAddressList(file, "to", envelope->to) + || htmlAddressList(file, "cc", envelope->cc) + || templateRender(file, template2, vars, escapeXML); free(mailto); + free(fragment); free(mbox); - if (error) return error; - - return 0 - || htmlAddressList(file, "to", envelope->to) - || htmlAddressList(file, "cc", envelope->cc); + return error; } -int htmlMessageTail(FILE *file) { - int n = fprintf(file, "</details>\n"); - return (n < 0 ? n : 0); +int htmlMessageClose(FILE *file) { + return templateRender(file, TEMPLATE(</article>), NULL, NULL); } -int htmlThreadHead(FILE *file, const struct Envelope *envelope) { - struct Variable urlVars[] = { - { "pathID", pathSafe(envelope->messageID) }, - {0}, - }; - char *path = templateURL("[pathID]", urlVars); +const char *htmlTitle; +static char *htmlThreadURL(const struct Envelope *envelope) { struct Variable vars[] = { - { "subject", envelope->subject }, - { "path", path }, + { "name", pathSafe(envelope->messageID) }, {0}, }; - const char *Head = TEMPLATE( + return templateURL("[name]", vars); +} + +int htmlThreadHead(FILE *file, const struct Envelope *envelope) { + const char *template = 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> + <title>[subject] · [title]</title> + <link rel="alternate" type="application/atom+xml" href="[url].atom"> + <link rel="alternate" type="application/mbox" href="[url].mbox"> ); - int error = templateRender(file, Head, vars, escapeXML); - free(path); + char *url = htmlThreadURL(envelope); + struct Variable vars[] = { + { "subject", envelope->subject }, + { "title", htmlTitle }, + { "url", url }, + {0}, + }; + int error = templateRender(file, template, vars, escapeXML); + free(url); return error; } -int htmlThreadHeader(FILE *file, const struct Envelope *envelope) { +int htmlThreadOpen(FILE *file, const struct Envelope *envelope) { + const char *template = TEMPLATE( + <header class="thread"> + <h1>[subject]</h1> + <nav> + <ul> + <li><a href="[url].atom">Atom</a></li> + <li><a href="[url].mbox">mbox</a></li> + </ul> + </nav> + </header> + <main class="thread"> + ); + char *url = htmlThreadURL(envelope); struct Variable vars[] = { { "subject", envelope->subject }, + { "url", url }, {0}, }; - const char *Header = TEMPLATE( - <h1>[subject]</h1> - ); - return templateRender(file, Header, vars, escapeXML); + int error = templateRender(file, template, vars, escapeXML); + free(url); + return error; } -int htmlThreadOpen(FILE *file) { - int n = fprintf(file, TEMPLATE(<section class="thread">)); - return (n < 0 ? n : 0); +int htmlSubthreadOpen(FILE *file) { + return templateRender( + file, TEMPLATE(<section class="subthread">), NULL, NULL + ); } -int htmlThreadClose(FILE *file) { - int n = fprintf(file, TEMPLATE(</section>)); - return (n < 0 ? n : 0); +int htmlSubthreadClose(FILE *file) { + return templateRender(file, TEMPLATE(</section>), NULL, NULL); } -int htmlThreadTail(FILE *file) { - return 0; +int htmlThreadClose(FILE *file) { + return templateRender(file, TEMPLATE(</main>), NULL, NULL); } |