about summary refs log tree commit diff
path: root/export.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-04-14 17:21:43 -0400
committerJune McEnroe <june@causal.agency>2020-04-14 17:21:43 -0400
commit2b8d8d0ffd83b9e0e6e9372b599381498c8d2cf1 (patch)
treedfe74fcb48604630b77772487e9375f7f91a35a2 /export.c
parentAdd bodyPartType helper (diff)
downloadbubger-2b8d8d0ffd83b9e0e6e9372b599381498c8d2cf1.tar.gz
bubger-2b8d8d0ffd83b9e0e6e9372b599381498c8d2cf1.zip
Find text content for Atom in multipart/mixed and /alternative
Diffstat (limited to 'export.c')
-rw-r--r--export.c78
1 files changed, 45 insertions, 33 deletions
diff --git a/export.c b/export.c
index 952f72e..5647086 100644
--- a/export.c
+++ b/export.c
@@ -75,7 +75,7 @@ static void exportMbox(
 
 static void exportAtom(
 	uint32_t uid, const struct Envelope *envelope,
-	const struct BodyPart *structure, const char *body
+	const struct BodyPart *structure, struct Data body
 ) {
 	const char *path = pathUID(uid, "atom");
 	FILE *file = fopen(path, "w");
@@ -84,14 +84,25 @@ static void exportAtom(
 	int error = atomEntryOpen(file, envelope);
 	if (error) err(EX_IOERR, "%s", path);
 
-	if (
-		!structure->multipart &&
-		!strcmp(structure->type, "TEXT") &&
-		!strcmp(structure->subtype, "PLAIN")
-	) {
+	const struct BodyPart *part = structure;
+	if (bodyPartType(part, "multipart", "mixed")) {
+		part = &part->parts.ptr[0];
+		body = dataCheck(body, List).list.ptr[0];
+	}
+	if (bodyPartType(part, "multipart", "alternative")) {
+		for (size_t i = 0; i < part->parts.len; ++i) {
+			if (bodyPartType(&part->parts.ptr[i], "text", "plain")) {
+				part = &part->parts.ptr[i];
+				body = dataCheck(body, List).list.ptr[i];
+				break;
+			}
+		}
+	}
+	if (bodyPartType(part, "text", "plain")) {
+		const char *content = dataCheck(body, String).string;
 		error = 0
 			|| atomContentOpen(file)
-			|| decodeContent(file, escapeXML, structure, body)
+			|| decodeContent(file, escapeXML, structure, content)
 			|| atomContentClose(file);
 		if (error) err(EX_IOERR, "%s", path);
 	}
@@ -131,8 +142,8 @@ bool exportData(FILE *imap, enum Atom tag, struct List items) {
 	uint32_t uid = 0;
 	struct Envelope envelope = {0};
 	struct BodyPart structure = {0};
-	const char *bodyHeader = NULL;
-	const char *bodyText = NULL;
+	struct Data bodyHeader = {0};
+	struct Data bodyText = {0};
 	struct Data bodyParts = {0};
 
 	for (size_t i = 0; i + 1 < items.len; i += 2) {
@@ -160,9 +171,9 @@ bool exportData(FILE *imap, enum Atom tag, struct List items) {
 		if (section.ptr[0].type == Atom) {
 			name = section.ptr[0].atom;
 			if (name == AtomHeaderFields) {
-				bodyHeader = dataCheck(data, String).string;
+				bodyHeader = data;
 			} else if (name == AtomText) {
-				bodyText = dataCheck(data, String).string;
+				bodyText = data;
 			}
 			continue;
 		}
@@ -172,7 +183,9 @@ bool exportData(FILE *imap, enum Atom tag, struct List items) {
 		for (size_t i = 0; i < section.len; ++i) {
 			if (section.ptr[i].type != Number) continue;
 			uint32_t num = section.ptr[i].number;
-			*dest = (struct Data) { .type = List };
+			if (dest->type != List) {
+				*dest = (struct Data) { .type = List };
+			}
 			while (dest->list.len < num) {
 				listPush(&dest->list, (struct Data) {0});
 			}
@@ -184,34 +197,33 @@ bool exportData(FILE *imap, enum Atom tag, struct List items) {
 	if (!uid) {
 		errx(EX_PROTOCOL, "missing UID data item");
 	}
+	if (!envelope.subject) {
+		errx(EX_PROTOCOL, "missing ENVELOPE data item");
+	}
 	if (!structure.subtype) {
 		errx(EX_PROTOCOL, "missing BODYSTRUCTURE data item");
 	}
 
+	if (bodyHeader.type == String && bodyText.type == String) {
+		exportMbox(uid, &envelope, bodyHeader.string, bodyText.string);
+	}
+
 	bool fetch = false;
-	if (envelope.subject) {
-		if (!bodyHeader) {
-			errx(EX_PROTOCOL, "missing BODY[HEADER.FIELDS] data item");
-		}
-		if (!bodyText) {
-			errx(EX_PROTOCOL, "missing BODY[TEXT] data item");
-		}
-		exportMbox(uid, &envelope, bodyHeader, bodyText);
+	if (!structure.multipart) {
 		exportAtom(uid, &envelope, &structure, bodyText);
-
-		if (structure.multipart) {
-			fetch = true;
-			fprintf(
-				imap, "%s UID FETCH %" PRIu32 " (UID BODYSTRUCTURE",
-				Atoms[tag], uid
-			);
-			struct List parts = {0};
-			exportFetchParts(imap, &parts, &structure);
-			listFree(parts);
-			fprintf(imap, ")\r\n");
-		}
+	} else if (bodyParts.type == List) {
+		// TODO: Validate that bodyParts is parallel to structure.
+		exportAtom(uid, &envelope, &structure, bodyParts);
 	} else {
-		// TODO: Correlate body parts to body data.
+		fetch = true;
+		fprintf(
+			imap, "%s UID FETCH %" PRIu32 " (UID ENVELOPE BODYSTRUCTURE",
+			Atoms[tag], uid
+		);
+		struct List parts = {0};
+		exportFetchParts(imap, &parts, &structure);
+		listFree(parts);
+		fprintf(imap, ")\r\n");
 	}
 
 	envelopeFree(envelope);