about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-04-26 15:57:07 -0400
committerJune McEnroe <june@causal.agency>2020-04-26 16:04:43 -0400
commit7953ea0aef6d6d7110c95f368c07c1ac8b6223b8 (patch)
treeb10d55b0e940dd8a287cb5b51b732c0faef25ae5
parentGenerate XHTML content in Atom entries (diff)
downloadbubger-7953ea0aef6d6d7110c95f368c07c1ac8b6223b8.tar.gz
bubger-7953ea0aef6d6d7110c95f368c07c1ac8b6223b8.zip
Generate index.atom
-rw-r--r--archive.c9
-rw-r--r--archive.h11
-rw-r--r--atom.c58
-rw-r--r--concat.c29
-rw-r--r--html.c8
5 files changed, 81 insertions, 34 deletions
diff --git a/archive.c b/archive.c
index af0329a..7aa6028 100644
--- a/archive.c
+++ b/archive.c
@@ -29,6 +29,9 @@
 
 #define ENV_PASSWORD "BUBGER_IMAP_PASSWORD"
 
+const char *baseURL = "";
+const char *baseTitle;
+
 static uint32_t uidRead(const char *path) {
 	FILE *file = fopen(path, "r");
 	if (!file) return 0;
@@ -72,8 +75,8 @@ int main(int argc, char *argv[]) {
 			break; case 'h': concatHead = optarg;
 			break; case 'p': port = optarg;
 			break; case 's': search = optarg;
-			break; case 't': htmlTitle = optarg;
-			break; case 'u': atomBaseURL = optarg;
+			break; case 't': baseTitle = optarg;
+			break; case 'u': baseURL = optarg;
 			break; case 'v': imapVerbose = true;
 			break; case 'w': passPath = optarg;
 		}
@@ -84,7 +87,7 @@ int main(int argc, char *argv[]) {
 
 	if (!host) errx(EX_USAGE, "host required");
 	if (!user) errx(EX_USAGE, "user required");
-	if (!htmlTitle) htmlTitle = mailbox;
+	if (!baseTitle) baseTitle = mailbox;
 
 	char *pass = NULL;
 	if (passPath) {
diff --git a/archive.h b/archive.h
index 136723b..9a0de12 100644
--- a/archive.h
+++ b/archive.h
@@ -188,14 +188,17 @@ int mboxFrom(FILE *file);
 int mboxHeader(FILE *file, const char *header);
 int mboxBody(FILE *file, const char *body);
 
-extern const char *atomBaseURL;
+extern const char *baseURL;
+extern const char *baseTitle;
+
 int atomEntryOpen(FILE *file, const struct Envelope *envelope);
 int atomContent(FILE *file, const char *content);
 int atomEntryClose(FILE *file);
-int atomFeedOpen(FILE *file, const struct Envelope *envelope);
-int atomFeedClose(FILE *file);
+int atomThreadOpen(FILE *file, const struct Envelope *envelope);
+int atomThreadClose(FILE *file);
+int atomIndexOpen(FILE *file);
+int atomIndexClose(FILE *file);
 
-extern const char *htmlTitle;
 int htmlMessageOpen(FILE *file, const struct Envelope *envelope);
 int htmlInline(FILE *file, const struct BodyPart *part, const char *content);
 int htmlAttachmentOpen(FILE *file);
diff --git a/atom.c b/atom.c
index b0ee921..85393c9 100644
--- a/atom.c
+++ b/atom.c
@@ -22,8 +22,6 @@
 
 #include "archive.h"
 
-const char *atomBaseURL;
-
 static char *atomID(const struct Envelope *envelope) {
 	struct Variable vars[] = {
 		{ "messageID", envelope->messageID },
@@ -33,7 +31,6 @@ static char *atomID(const struct Envelope *envelope) {
 }
 
 static int atomAuthor(FILE *file, struct Address addr) {
-	// TODO: Conditionally include <email>.
 	const char *template = TEMPLATE(
 		<author>
 			<name>[name]</name>
@@ -51,11 +48,12 @@ static int atomAuthor(FILE *file, struct Address addr) {
 
 static char *atomEntryURL(const struct Envelope *envelope) {
 	struct Variable vars[] = {
+		{ "base", baseURL },
 		{ "messageID", envelope->messageID },
 		{ "type", "mbox" },
 		{0},
 	};
-	return templateURL("/" PATH_MESSAGE, vars);
+	return templateURL("[base]/" PATH_MESSAGE, vars);
 }
 
 int atomEntryOpen(FILE *file, const struct Envelope *envelope) {
@@ -64,7 +62,7 @@ int atomEntryOpen(FILE *file, const struct Envelope *envelope) {
 		<id>[id]</id>
 		<title>[title]</title>
 		<updated>[updated]</updated>
-		<link rel="alternate" type="application/mbox" href="[base][url]"/>
+		<link rel="alternate" type="application/mbox" href="[url]"/>
 	);
 	char *id = atomID(envelope);
 	char updated[sizeof("0000-00-00T00:00:00Z")];
@@ -74,7 +72,6 @@ int atomEntryOpen(FILE *file, const struct Envelope *envelope) {
 		{ "id", id },
 		{ "title", envelope->subject },
 		{ "updated", updated },
-		{ "base", (atomBaseURL ? atomBaseURL : "") },
 		{ "url", url },
 		{0},
 	};
@@ -105,39 +102,39 @@ int atomEntryClose(FILE *file) {
 	return templateRender(file, TEMPLATE(</entry>), NULL, NULL);
 }
 
-static char *atomFeedURL(const struct Envelope *envelope, const char *type) {
+static char *atomThreadURL(const struct Envelope *envelope, const char *type) {
 	struct Variable vars[] = {
+		{ "base", baseURL },
 		{ "messageID", envelope->messageID },
 		{ "type", type },
 		{0},
 	};
-	return templateURL("/" PATH_THREAD, vars);
+	return templateURL("[base]/" PATH_THREAD, vars);
 }
 
-int atomFeedOpen(FILE *file, const struct Envelope *envelope) {
+int atomThreadOpen(FILE *file, const struct Envelope *envelope) {
 	const char *template = TEMPLATE(
 		<[q]xml version="1.0" encoding="utf-8"[q]>
 		<feed xmlns="http://www.w3.org/2005/Atom">
 		<id>[id]</id>
 		<title>[title]</title>
 		<updated>[updated]</updated>
-		<link rel="self" href="[base][atom]"/>
-		<link rel="alternate" type="text/html" href="[base][html]"/>
-		<link rel="alternate" type="application/mbox" href="[base][mbox]"/>
+		<link rel="self" href="[atom]"/>
+		<link rel="alternate" type="text/html" href="[html]"/>
+		<link rel="alternate" type="application/mbox" href="[mbox]"/>
 	);
 	char *id = atomID(envelope);
 	time_t now = time(NULL);
 	char updated[sizeof("0000-00-00T00:00:00Z")];
 	strftime(updated, sizeof(updated), "%FT%TZ", gmtime(&now));
-	char *atom = atomFeedURL(envelope, "atom");
-	char *html = atomFeedURL(envelope, "html");
-	char *mbox = atomFeedURL(envelope, "mbox");
+	char *atom = atomThreadURL(envelope, "atom");
+	char *html = atomThreadURL(envelope, "html");
+	char *mbox = atomThreadURL(envelope, "mbox");
 	struct Variable vars[] = {
 		{ "q", "?" },
 		{ "id", id },
 		{ "title", envelope->subject },
 		{ "updated", updated },
-		{ "base", (atomBaseURL ? atomBaseURL : "") },
 		{ "atom", atom },
 		{ "html", html },
 		{ "mbox", mbox },
@@ -153,6 +150,33 @@ int atomFeedOpen(FILE *file, const struct Envelope *envelope) {
 	return error;
 }
 
-int atomFeedClose(FILE *file) {
+int atomThreadClose(FILE *file) {
+	return templateRender(file, TEMPLATE(</feed>), NULL, NULL);
+}
+
+int atomIndexOpen(FILE *file) {
+	const char *template = TEMPLATE(
+		<[q]xml version="1.0" encoding="utf-8"[q]>
+		<feed xmlns="http://www.w3.org/2005/Atom">
+		<id>[base]</id>
+		<title>[title]</title>
+		<updated>[updated]</updated>
+		<link rel="self" href="[base]/index.atom"/>
+		<link rel="alternate" type="text/html" href="[base]/index.html"/>
+	);
+	time_t now = time(NULL);
+	char updated[sizeof("0000-00-00T00:00:00Z")];
+	strftime(updated, sizeof(updated), "%FT%TZ", gmtime(&now));
+	struct Variable vars[] = {
+		{ "q", "?" },
+		{ "base", (baseURL ? baseURL : "") },
+		{ "title", baseTitle },
+		{ "updated", updated },
+		{0},
+	};
+	return templateRender(file, template, vars, escapeXML);
+}
+
+int atomIndexClose(FILE *file) {
 	return templateRender(file, TEMPLATE(</feed>), NULL, NULL);
 }
diff --git a/concat.c b/concat.c
index 8e165d2..7be35e0 100644
--- a/concat.c
+++ b/concat.c
@@ -169,7 +169,7 @@ static void concatThread(struct List thread, const struct Envelope *envelope) {
 		FILE *file = fopen(path, "w");
 		if (!file) err(EX_CANTCREAT, "%s", path);
 
-		error = atomFeedOpen(file, envelope);
+		error = atomThreadOpen(file, envelope);
 		if (error) err(EX_IOERR, "%s", path);
 
 		for (size_t i = 0; i < flat.len; ++i) {
@@ -178,7 +178,7 @@ static void concatThread(struct List thread, const struct Envelope *envelope) {
 			if (error) err(EX_IOERR, "%s", path);
 		}
 
-		error = atomFeedClose(file) || fclose(file);
+		error = atomThreadClose(file) || fclose(file);
 		if (error) err(EX_IOERR, "%s", path);
 	}
 
@@ -230,6 +230,25 @@ static int compar(const void *_a, const void *_b) {
 }
 
 void concatIndex(struct List threads, const struct Envelope *envelopes) {
+	const char *path = "index.atom";
+	FILE *file = fopen(path, "w");
+	if (!file) err(EX_CANTCREAT, "%s", path);
+
+	int error = atomIndexOpen(file);
+	if (error) err(EX_IOERR, "%s", path);
+
+	struct List flat = {0};
+	listFlatten(&flat, threads);
+	for (size_t i = flat.len - 1; i < flat.len; --i) {
+		uint32_t uid = dataCheck(flat.ptr[i], Number).number;
+		error = concatFile(file, uidPath(uid, "atom"));
+		if (error) err(EX_IOERR, "%s", path);
+	}
+	listFree(flat);
+
+	error = atomIndexClose(file) || fclose(file);
+	if (error) err(EX_IOERR, "%s", path);
+
 	struct Sort *order = calloc(threads.len, sizeof(*order));
 	if (!order) err(EX_OSERR, "calloc");
 
@@ -245,11 +264,11 @@ void concatIndex(struct List threads, const struct Envelope *envelopes) {
 	}
 	qsort(order, threads.len, sizeof(*order), compar);
 
-	const char *path = "index.html";
-	FILE *file = fopen(path, "w");
+	path = "index.html";
+	file = fopen(path, "w");
 	if (!file) err(EX_CANTCREAT, "%s", path);
 
-	int error = htmlIndexHead(file);
+	error = htmlIndexHead(file);
 	if (error) err(EX_IOERR, "%s", path);
 
 	if (concatHead) {
diff --git a/html.c b/html.c
index 8f349e5..3bd192a 100644
--- a/html.c
+++ b/html.c
@@ -296,8 +296,6 @@ int htmlMessageClose(FILE *file) {
 	return templateRender(file, TEMPLATE(</article>), NULL, NULL);
 }
 
-const char *htmlTitle;
-
 static char *htmlThreadURL(const struct Envelope *envelope, const char *type) {
 	struct Variable vars[] = {
 		{ "messageID", envelope->messageID },
@@ -319,7 +317,7 @@ int htmlThreadHead(FILE *file, const struct Envelope *envelope) {
 	char *mbox = htmlThreadURL(envelope, "mbox");
 	struct Variable vars[] = {
 		{ "subject", envelope->subject },
-		{ "title", htmlTitle },
+		{ "title", baseTitle },
 		{ "atom", atom },
 		{ "mbox", mbox },
 		{0},
@@ -421,7 +419,7 @@ int htmlIndexHead(FILE *file) {
 		<link rel="alternate" type="application/atom+xml" href="index.atom">
 	);
 	struct Variable vars[] = {
-		{ "title", htmlTitle },
+		{ "title", baseTitle },
 		{0},
 	};
 	return templateRender(file, template, vars, escapeXML);
@@ -441,7 +439,7 @@ int htmlIndexOpen(FILE *file) {
 			<ol>
 	);
 	struct Variable vars[] = {
-		{ "title", htmlTitle },
+		{ "title", baseTitle },
 		{0},
 	};
 	return templateRender(file, template, vars, escapeXML);