summary refs log tree commit diff
path: root/html.c
diff options
context:
space:
mode:
Diffstat (limited to 'html.c')
-rw-r--r--html.c218
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] &middot; [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);
 }