summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--archive.h5
-rw-r--r--atom.c6
-rw-r--r--concat.c40
-rw-r--r--export.c42
-rw-r--r--html.c12
-rw-r--r--template.c27
6 files changed, 66 insertions, 66 deletions
diff --git a/archive.h b/archive.h
index a4278ff..3328340 100644
--- a/archive.h
+++ b/archive.h
@@ -187,11 +187,10 @@ int templateRender(
 	FILE *file, const char *template,
 	const struct Variable vars[], EscapeFn *escape
 );
-char *templateBuffer(
-	char *buf, size_t cap, const char *template,
+char *templateString(
+	const char *template,
 	const struct Variable vars[], EscapeFn *escape
 );
-char *templateURL(const char *template, const struct Variable vars[]);
 
 extern const char *baseURL;
 extern const char *baseTitle;
diff --git a/atom.c b/atom.c
index 3ecebbc..ddfb3f6 100644
--- a/atom.c
+++ b/atom.c
@@ -38,7 +38,7 @@ static char *atomID(const struct Envelope *envelope) {
 		{ "messageID", envelope->messageID },
 		{0},
 	};
-	return templateURL("mid:[messageID]", vars);
+	return templateString("mid:[messageID]", vars, escapeURL);
 }
 
 static int atomAuthor(FILE *file, struct Address addr) {
@@ -63,7 +63,7 @@ static char *atomEntryURL(const struct Envelope *envelope) {
 		{ "type", "mbox" },
 		{0},
 	};
-	return templateURL("/" PATH_MESSAGE, vars);
+	return templateString("/" PATH_MESSAGE, vars, escapeURL);
 }
 
 static const char *atomUpdated(time_t time) {
@@ -123,7 +123,7 @@ static char *atomThreadURL(const struct Envelope *envelope, const char *type) {
 		{ "type", type },
 		{0},
 	};
-	return templateURL("/" PATH_THREAD, vars);
+	return templateString("/" PATH_THREAD, vars, escapeURL);
 }
 
 int atomThreadOpen(FILE *file, const struct Envelope *envelope) {
diff --git a/concat.c b/concat.c
index 3e0dec6..c59a828 100644
--- a/concat.c
+++ b/concat.c
@@ -27,7 +27,6 @@
 
 #include <err.h>
 #include <inttypes.h>
-#include <limits.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -82,8 +81,7 @@ void concatData(
 	errx(EX_TEMPFAIL, "no thread with root UID %" PRIu32, uid);
 }
 
-static const char *uidPath(uint32_t uid, const char *type) {
-	static char buf[PATH_MAX];
+static char *uidPath(uint32_t uid, const char *type) {
 	char str[32];
 	snprintf(str, sizeof(str), "%" PRIu32, uid);
 	struct Variable vars[] = {
@@ -91,18 +89,18 @@ static const char *uidPath(uint32_t uid, const char *type) {
 		{ "type", type },
 		{0},
 	};
-	templateBuffer(buf, sizeof(buf), PATH_UID, vars, escapePath);
-	return buf;
+	return templateString(PATH_UID, vars, escapePath);
 }
 
 static time_t uidNewest(struct List uids, const char *type) {
 	time_t newest = 0;
 	for (size_t i = 0; i < uids.len; ++i) {
-		const char *path = uidPath(dataCheck(uids.ptr[i], Number).number, type);
+		char *path = uidPath(dataCheck(uids.ptr[i], Number).number, type);
 		struct stat status;
 		int error = stat(path, &status);
 		if (error) err(EX_DATAERR, "%s", path);
 		if (status.st_mtime > newest) newest = status.st_mtime;
+		free(path);
 	}
 	return newest;
 }
@@ -129,22 +127,22 @@ static int concatHTML(FILE *file, struct List thread) {
 				|| htmlSubthreadClose(file);
 		} else {
 			uint32_t uid = dataCheck(thread.ptr[i], Number).number;
-			error = concatFile(file, uidPath(uid, "html"));
+			char *path = uidPath(uid, "html");
+			error = concatFile(file, path);
+			free(path);
 		}
 		if (error) return error;
 	}
 	return 0;
 }
 
-static const char *threadPath(const char *messageID, const char *type) {
-	static char buf[PATH_MAX];
+static char *threadPath(const char *messageID, const char *type) {
 	struct Variable vars[] = {
 		{ "messageID", messageID },
 		{ "type", type },
 		{0},
 	};
-	templateBuffer(buf, sizeof(buf), PATH_THREAD, vars, escapePath);
-	return buf;
+	return templateString(PATH_THREAD, vars, escapePath);
 }
 
 const char *concatHead;
@@ -155,7 +153,7 @@ static void concatThread(struct List thread, const struct Envelope *envelope) {
 
 	int error;
 	FILE *file;
-	const char *path;
+	char *path;
 	struct stat status;
 
 	path = threadPath(envelope->messageID, "mbox");
@@ -166,13 +164,16 @@ static void concatThread(struct List thread, const struct Envelope *envelope) {
 
 		for (size_t i = 0; i < flat.len; ++i) {
 			uint32_t uid = dataCheck(flat.ptr[i], Number).number;
-			error = concatFile(file, uidPath(uid, "mbox"));
+			char *src = uidPath(uid, "mbox");
+			error = concatFile(file, src);
 			if (error) err(EX_IOERR, "%s", path);
+			free(src);
 		}
 
 		error = fclose(file);
 		if (error) err(EX_IOERR, "%s", path);
 	}
+	free(path);
 
 	path = threadPath(envelope->messageID, "atom");
 	error = stat(path, &status);
@@ -185,13 +186,16 @@ static void concatThread(struct List thread, const struct Envelope *envelope) {
 
 		for (size_t i = 0; i < flat.len; ++i) {
 			uint32_t uid = dataCheck(flat.ptr[i], Number).number;
-			error = concatFile(file, uidPath(uid, "atom"));
+			char *src = uidPath(uid, "atom");
+			error = concatFile(file, src);
 			if (error) err(EX_IOERR, "%s", path);
+			free(src);
 		}
 
 		error = atomThreadClose(file) || fclose(file);
 		if (error) err(EX_IOERR, "%s", path);
 	}
+	free(path);
 
 	path = threadPath(envelope->messageID, "html");
 	error = stat(path, &status);
@@ -214,6 +218,7 @@ static void concatThread(struct List thread, const struct Envelope *envelope) {
 			|| fclose(file);
 		if (error) err(EX_IOERR, "%s", path);
 	}
+	free(path);
 
 	listFree(flat);
 }
@@ -252,8 +257,10 @@ void concatIndex(struct List threads, const struct Envelope *envelopes) {
 	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"));
+		char *src = uidPath(uid, "atom");
+		error = concatFile(file, src);
 		if (error) err(EX_IOERR, "%s", path);
+		free(src);
 	}
 	listFree(flat);
 
@@ -265,9 +272,10 @@ void concatIndex(struct List threads, const struct Envelope *envelopes) {
 
 	for (size_t i = 0; i < threads.len; ++i) {
 		struct stat status;
-		const char *path = threadPath(envelopes[i].messageID, "html");
+		char *path = threadPath(envelopes[i].messageID, "html");
 		int error = stat(path, &status);
 		if (error) err(EX_DATAERR, "%s", path);
+		free(path);
 
 		order[i].index = i;
 		order[i].created = envelopes[i].time;
diff --git a/export.c b/export.c
index f9f533e..2b579c3 100644
--- a/export.c
+++ b/export.c
@@ -28,7 +28,6 @@
 #include <err.h>
 #include <errno.h>
 #include <inttypes.h>
-#include <limits.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -40,8 +39,7 @@
 #include "archive.h"
 #include "imap.h"
 
-static const char *exportPath(uint32_t uid, const char *type) {
-	static char buf[PATH_MAX];
+static char *exportPath(uint32_t uid, const char *type) {
 	char str[32];
 	snprintf(str, sizeof(str), "%" PRIu32, uid);
 	struct Variable vars[] = {
@@ -49,8 +47,7 @@ static const char *exportPath(uint32_t uid, const char *type) {
 		{ "type", type },
 		{0},
 	};
-	templateBuffer(buf, sizeof(buf), PATH_UID, vars, escapePath);
-	return buf;
+	return templateString(PATH_UID, vars, escapePath);
 }
 
 bool exportFetch(FILE *imap, enum Atom tag, struct List threads) {
@@ -58,11 +55,17 @@ bool exportFetch(FILE *imap, enum Atom tag, struct List threads) {
 	listFlatten(&uids, threads);
 	for (size_t i = uids.len - 1; i < uids.len; --i) {
 		uint32_t uid = dataCheck(uids.ptr[i], Number).number;
+		char *atom = exportPath(uid, "atom");
+		char *html = exportPath(uid, "html");
+		char *mbox = exportPath(uid, "mbox");
 		int error = 0
-			|| access(exportPath(uid, "atom"), F_OK)
-			|| access(exportPath(uid, "html"), F_OK)
-			|| access(exportPath(uid, "mbox"), F_OK);
+			|| access(atom, F_OK)
+			|| access(html, F_OK)
+			|| access(mbox, F_OK);
 		if (!error) uids.ptr[i] = uids.ptr[--uids.len];
+		free(atom);
+		free(html);
+		free(mbox);
 	}
 	if (!uids.len) {
 		listFree(uids);
@@ -86,7 +89,7 @@ static void exportMbox(
 	uint32_t uid, const struct Envelope *envelope,
 	const char *header, const char *body
 ) {
-	const char *path = exportPath(uid, "mbox");
+	char *path = exportPath(uid, "mbox");
 	FILE *file = fopen(path, "w");
 	if (!file) err(EX_CANTCREAT, "%s", path);
 	int error = 0
@@ -96,17 +99,18 @@ static void exportMbox(
 		|| fclose(file);
 	if (error) err(EX_IOERR, "%s", path);
 
-	char buf[PATH_MAX];
 	struct Variable vars[] = {
 		{ "messageID", envelope->messageID },
 		{ "type", "mbox" },
 		{0},
 	};
-	templateBuffer(buf, sizeof(buf), PATH_MESSAGE, vars, escapePath);
+	char *dest = templateString(PATH_MESSAGE, vars, escapePath);
+	unlink(dest);
+	error = link(path, dest);
+	if (error) err(EX_CANTCREAT, "%s", dest);
 
-	unlink(buf);
-	error = link(path, buf);
-	if (error) err(EX_CANTCREAT, "%s", buf);
+	free(dest);
+	free(path);
 }
 
 static bool isInline(const struct BodyPart *part) {
@@ -124,7 +128,7 @@ static void exportAtom(
 	uint32_t uid, const struct Envelope *envelope,
 	const struct BodyPart *structure, struct Data body
 ) {
-	const char *path = exportPath(uid, "atom");
+	char *path = exportPath(uid, "atom");
 	FILE *file = fopen(path, "w");
 	if (!file) err(EX_CANTCREAT, "%s", path);
 
@@ -155,6 +159,7 @@ static void exportAtom(
 
 	error = atomEntryClose(file) || fclose(file);
 	if (error) err(EX_IOERR, "%s", path);
+	free(path);
 }
 
 static const char *sectionName(struct List section) {
@@ -181,7 +186,6 @@ static int exportHTMLAttachment(
 	const char *disposition = part->disposition.type;
 	if (!disposition) disposition = "INLINE";
 
-	char path[PATH_MAX];
 	struct Variable vars[] = {
 		{ "messageID", envelope->messageID },
 		{ "section", sectionName(section) },
@@ -191,7 +195,7 @@ static int exportHTMLAttachment(
 		{ "subtype", (name ? "" : part->subtype) },
 		{0},
 	};
-	templateBuffer(path, sizeof(path), PATH_ATTACHMENT, vars, escapePath);
+	char *path = templateString(PATH_ATTACHMENT, vars, escapePath);
 
 	for (char *ch = path; (ch = strchr(ch, '/')); ++ch) {
 		*ch = '\0';
@@ -207,6 +211,7 @@ static int exportHTMLAttachment(
 		|| decodeToFile(attachment, part, dataCheck(body, String).string)
 		|| fclose(attachment);
 	if (error) err(EX_IOERR, "%s", path);
+	free(path);
 
 	return htmlAttachment(file, part, vars);
 }
@@ -274,7 +279,7 @@ static void exportHTML(
 	uint32_t uid, const struct Envelope *envelope,
 	const struct BodyPart *structure, struct Data body
 ) {
-	const char *path = exportPath(uid, "html");
+	char *path = exportPath(uid, "html");
 	FILE *file = fopen(path, "w");
 	if (!file) err(EX_CANTCREAT, "%s", path);
 
@@ -288,6 +293,7 @@ static void exportHTML(
 
 	error = htmlMessageClose(file) || fclose(file);
 	if (error) err(EX_IOERR, "%s", path);
+	free(path);
 }
 
 static void fetchParts(
diff --git a/html.c b/html.c
index 6d9b6b2..d55e5bf 100644
--- a/html.c
+++ b/html.c
@@ -96,7 +96,7 @@ static char *htmlReply(const struct Envelope *envelope) {
 		{ ">", ">" },
 		{0},
 	};
-	return templateURL(template, vars);
+	return templateString(template, vars, escapeURL);
 }
 
 static char *htmlFragment(const char *messageID) {
@@ -104,7 +104,7 @@ static char *htmlFragment(const char *messageID) {
 		{ "messageID", messageID },
 		{0},
 	};
-	return templateURL("#[messageID]", vars);
+	return templateString("#[messageID]", vars, escapeURL);
 }
 
 static char *htmlMbox(const char *messageID) {
@@ -113,7 +113,7 @@ static char *htmlMbox(const char *messageID) {
 		{ "type", "mbox" },
 		{0},
 	};
-	return templateURL("../" PATH_MESSAGE, vars);
+	return templateString("../" PATH_MESSAGE, vars, escapeURL);
 }
 
 static int
@@ -353,7 +353,7 @@ int htmlAttachment(
 	const char *template = {
 		Q(<li><a href="[url]">[name][type][/][subtype]</a></li>)
 	};
-	char *url = templateURL("../" PATH_ATTACHMENT, path);
+	char *url = templateString("../" PATH_ATTACHMENT, path, escapeURL);
 	const char *name = paramGet(part->disposition.params, "filename");
 	if (!name) name = paramGet(part->params, "name");
 	struct Variable vars[] = {
@@ -383,7 +383,7 @@ static char *htmlThreadURL(const struct Envelope *envelope, const char *type) {
 		{ "type", type },
 		{0},
 	};
-	return templateURL("../" PATH_THREAD, vars);
+	return templateString("../" PATH_THREAD, vars, escapeURL);
 }
 
 int htmlThreadHead(FILE *file, const struct Envelope *envelope) {
@@ -553,7 +553,7 @@ static char *htmlIndexURL(const struct Envelope *envelope) {
 		{ "type", "html" },
 		{0},
 	};
-	return templateURL(PATH_THREAD, vars);
+	return templateString(PATH_THREAD, vars, escapeURL);
 }
 
 int htmlIndexThread(
diff --git a/template.c b/template.c
index b3ab00f..a47d9f5 100644
--- a/template.c
+++ b/template.c
@@ -135,30 +135,17 @@ int templateRender(
 	return 0;
 }
 
-char *templateBuffer(
-	char *buf, size_t cap, const char *template,
-	const struct Variable vars[], EscapeFn *escape
+char *templateString(
+	const char *template, const struct Variable vars[], EscapeFn *escape
 ) {
-	FILE *file = fmemopen(buf, cap, "w");
-	if (!file) err(EX_OSERR, "fmemopen");
+	char *buf;
+	size_t len;
+	FILE *file = open_memstream(&buf, &len);
+	if (!file) err(EX_OSERR, "open_memstream");
 
 	int error = templateRender(file, template, vars, escape)
 		|| fclose(file);
-	assert(!error);
+	if (error) err(EX_OSERR, "open_memstream");
 
-	// XXX: fmemopen only null-terminates if there is room.
-	buf[cap - 1] = '\0';
 	return buf;
 }
-
-char *templateURL(const char *template, const struct Variable vars[]) {
-	size_t cap = strlen(template) + 1;
-	for (const struct Variable *var = vars; var->name; ++var) {
-		cap += 3 * strlen(var->value);
-	}
-
-	char *buf = malloc(cap);
-	if (!buf) err(EX_OSERR, "malloc");
-
-	return templateBuffer(buf, cap, template, vars, escapeURL);
-}