summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Makefile1
-rw-r--r--archive.h2
-rw-r--r--export.c86
-rw-r--r--parse.c104
4 files changed, 108 insertions, 85 deletions
diff --git a/Makefile b/Makefile
index bdb5986..8e63376 100644
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,7 @@ OBJS += export.o
 OBJS += html.o
 OBJS += imap.o
 OBJS += mbox.o
+OBJS += parse.o
 OBJS += template.o
 
 dev: tags all
diff --git a/archive.h b/archive.h
index 83f2e76..b43fe87 100644
--- a/archive.h
+++ b/archive.h
@@ -64,6 +64,8 @@ static inline void envelopeFree(struct Envelope envelope) {
 	free(envelope.bcc.addrs);
 }
 
+void parseEnvelope(struct Envelope *envelope, struct List list);
+
 bool exportFetch(FILE *imap, enum Atom tag, struct List threads);
 void exportData(struct List items);
 
diff --git a/export.c b/export.c
index 6e3554c..c563c3f 100644
--- a/export.c
+++ b/export.c
@@ -78,90 +78,6 @@ bool exportFetch(FILE *imap, enum Atom tag, struct List threads) {
 	return true;
 }
 
-static struct Address parseAddress(struct List list) {
-	if (list.len < 4) {
-		errx(EX_PROTOCOL, "missing address structure fields");
-	}
-	struct Address addr = {0};
-	if (list.ptr[0].type == String) {
-		// TODO: Decode UTF-8 in name.
-		addr.name = strdup(list.ptr[0].string);
-		if (!addr.name) err(EX_OSERR, "strdup");
-	}
-	if (list.ptr[2].type == String) addr.mailbox = list.ptr[2].string;
-	if (list.ptr[3].type == String) addr.host = list.ptr[3].string;
-	return addr;
-}
-
-static struct AddressList parseAddressList(struct List list) {
-	struct Address *addrs = calloc(list.len, sizeof(*addrs));
-	if (!addrs) err(EX_OSERR, "calloc");
-	for (size_t i = 0; i < list.len; ++i) {
-		addrs[i] = parseAddress(dataCheck(list.ptr[i], List).list);
-	}
-	return (struct AddressList) { list.len, addrs };
-}
-
-static char *parseID(char *id) {
-	size_t len = strlen(id);
-	if (id[0] != '<' || !len || id[len - 1] != '>') {
-		errx(EX_PROTOCOL, "invalid message ID");
-	}
-	id[len - 1] = '\0';
-	return &id[1];
-}
-
-static struct Envelope parseEnvelope(struct List list) {
-	enum {
-		Date, Subject, From, Sender, ReplyTo,
-		To, Cc, Bcc, InReplyTo, MessageID,
-		EnvelopeLen,
-	};
-	if (list.len < EnvelopeLen) {
-		errx(EX_PROTOCOL, "missing envelope structure fields");
-	}
-	struct Envelope envelope = {0};
-
-	const char *date = dataCheck(list.ptr[Date], String).string;
-	date = strptime(date, "%a, %e %b %Y %H:%M:%S %z", &envelope.date);
-	if (!date) errx(EX_PROTOCOL, "invalid envelope date format");
-
-	envelope.date.tm_isdst = -1;
-	envelope.utc = mktime(&envelope.date);
-
-	// TODO: Decode UTF-8 in subject.
-	envelope.subject = strdup(dataCheck(list.ptr[Subject], String).string);
-	if (!envelope.subject) err(EX_OSERR, "strdup");
-
-	for (size_t i = From; i <= Bcc; ++i) {
-		if (list.ptr[i].type == List) continue;
-		if (list.ptr[i].type == Atom && list.ptr[i].atom == AtomNil) {
-			list.ptr[i].type = List;
-			list.ptr[i].list = (struct List) {0};
-			continue;
-		}
-		errx(EX_PROTOCOL, "invalid envelope address field");
-	}
-	for (size_t i = From; i <= ReplyTo; ++i) {
-		if (!list.ptr[i].list.len || list.ptr[i].list.ptr[0].type != List) {
-			errx(EX_PROTOCOL, "invalid envelope address field");
-		}
-	}
-	envelope.from = parseAddress(list.ptr[From].list.ptr[0].list);
-	envelope.sender = parseAddress(list.ptr[Sender].list.ptr[0].list);
-	envelope.replyTo = parseAddress(list.ptr[ReplyTo].list.ptr[0].list);
-	envelope.to = parseAddressList(list.ptr[To].list);
-	envelope.cc = parseAddressList(list.ptr[Cc].list);
-	envelope.bcc = parseAddressList(list.ptr[Bcc].list);
-
-	if (list.ptr[InReplyTo].type == String) {
-		envelope.inReplyTo = parseID(list.ptr[InReplyTo].string);
-	}
-	envelope.messageID = parseID(dataCheck(list.ptr[MessageID], String).string);
-
-	return envelope;
-}
-
 void exportData(struct List items) {
 	uint32_t uid = 0;
 	struct Envelope envelope = {0};
@@ -188,7 +104,7 @@ void exportData(struct List items) {
 		} else if (name == AtomUID) {
 			uid = dataCheck(items.ptr[i + 1], Number).number;
 		} else if (name == AtomEnvelope) {
-			envelope = parseEnvelope(dataCheck(items.ptr[i + 1], List).list);
+			parseEnvelope(&envelope, dataCheck(items.ptr[i + 1], List).list);
 		} else if (name == AtomHeaderFields) {
 			header = dataCheck(items.ptr[i + 1], String).string;
 		} else if (name == AtomText) {
diff --git a/parse.c b/parse.c
new file mode 100644
index 0000000..d3c907f
--- /dev/null
+++ b/parse.c
@@ -0,0 +1,104 @@
+/* Copyright (C) 2020  C. McEnroe <june@causal.agency>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+
+#include "archive.h"
+#include "imap.h"
+
+static struct Address parseAddress(struct List list) {
+	if (list.len < 4) {
+		errx(EX_PROTOCOL, "missing address structure fields");
+	}
+	struct Address addr = {0};
+	if (list.ptr[0].type == String) {
+		// TODO: Decode UTF-8 in name.
+		addr.name = strdup(list.ptr[0].string);
+		if (!addr.name) err(EX_OSERR, "strdup");
+	}
+	if (list.ptr[2].type == String) addr.mailbox = list.ptr[2].string;
+	if (list.ptr[3].type == String) addr.host = list.ptr[3].string;
+	return addr;
+}
+
+static struct AddressList parseAddressList(struct List list) {
+	struct Address *addrs = calloc(list.len, sizeof(*addrs));
+	if (!addrs) err(EX_OSERR, "calloc");
+	for (size_t i = 0; i < list.len; ++i) {
+		addrs[i] = parseAddress(dataCheck(list.ptr[i], List).list);
+	}
+	return (struct AddressList) { list.len, addrs };
+}
+
+static char *parseID(char *id) {
+	size_t len = strlen(id);
+	if (id[0] != '<' || !len || id[len - 1] != '>') {
+		errx(EX_PROTOCOL, "invalid message ID");
+	}
+	id[len - 1] = '\0';
+	return &id[1];
+}
+
+void parseEnvelope(struct Envelope *envelope, struct List list) {
+	enum {
+		Date, Subject, From, Sender, ReplyTo,
+		To, Cc, Bcc, InReplyTo, MessageID,
+		EnvelopeLen,
+	};
+	if (list.len < EnvelopeLen) {
+		errx(EX_PROTOCOL, "missing envelope structure fields");
+	}
+
+	const char *date = dataCheck(list.ptr[Date], String).string;
+	date = strptime(date, "%a, %e %b %Y %H:%M:%S %z", &envelope->date);
+	if (!date) errx(EX_PROTOCOL, "invalid envelope date format");
+
+	envelope->date.tm_isdst = -1;
+	envelope->utc = mktime(&envelope->date);
+
+	// TODO: Decode UTF-8 in subject.
+	envelope->subject = strdup(dataCheck(list.ptr[Subject], String).string);
+	if (!envelope->subject) err(EX_OSERR, "strdup");
+
+	for (size_t i = From; i <= Bcc; ++i) {
+		if (list.ptr[i].type == List) continue;
+		if (list.ptr[i].type == Atom && list.ptr[i].atom == AtomNil) {
+			list.ptr[i].type = List;
+			list.ptr[i].list = (struct List) {0};
+			continue;
+		}
+		errx(EX_PROTOCOL, "invalid envelope address field");
+	}
+	for (size_t i = From; i <= ReplyTo; ++i) {
+		if (!list.ptr[i].list.len || list.ptr[i].list.ptr[0].type != List) {
+			errx(EX_PROTOCOL, "invalid envelope address field");
+		}
+	}
+	envelope->from = parseAddress(list.ptr[From].list.ptr[0].list);
+	envelope->sender = parseAddress(list.ptr[Sender].list.ptr[0].list);
+	envelope->replyTo = parseAddress(list.ptr[ReplyTo].list.ptr[0].list);
+	envelope->to = parseAddressList(list.ptr[To].list);
+	envelope->cc = parseAddressList(list.ptr[Cc].list);
+	envelope->bcc = parseAddressList(list.ptr[Bcc].list);
+
+	if (list.ptr[InReplyTo].type == String) {
+		envelope->inReplyTo = parseID(list.ptr[InReplyTo].string);
+	}
+	envelope->messageID = parseID(dataCheck(list.ptr[MessageID], String).string);
+}