From 8d72b2e967c36c2117a9ad9ffd46d42515996403 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Mon, 13 Apr 2020 17:19:13 -0400 Subject: Fetch multipart body parts --- export.c | 114 +++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 33 deletions(-) diff --git a/export.c b/export.c index 54178f6..52f6f88 100644 --- a/export.c +++ b/export.c @@ -101,54 +101,102 @@ static void exportAtom( if (error) err(EX_IOERR, "%s", path); } +static void exportFetchParts( + FILE *imap, struct List *parts, const struct BodyPart *structure +) { + if (structure->multipart) { + for (size_t i = 0; i < structure->parts.len; ++i) { + struct Data part = { .type = Number, .number = 1 + i }; + listPush(parts, part); + exportFetchParts(imap, parts, &structure->parts.ptr[i]); + parts->len--; + } + } else if (structure->message.structure) { + exportFetchParts(imap, parts, structure->message.structure); + } else { + fprintf(imap, " BODY["); + for (size_t i = 0; i < parts->len; ++i) { + fprintf(imap, "%s%" PRIu32, (i ? "." : ""), parts->ptr[i].number); + } + fprintf(imap, "]"); + } +} + bool exportData(FILE *imap, enum Atom tag, struct List items) { uint32_t uid = 0; struct Envelope envelope = {0}; struct BodyPart structure = {0}; const char *header = NULL; - const char *body = NULL; + const char *text = NULL; for (size_t i = 0; i + 1 < items.len; i += 2) { - enum Atom name; - if (items.ptr[i].type == Atom) { - name = items.ptr[i].atom; - } else if ( - items.ptr[i].type == List && - items.ptr[i].list.len && - items.ptr[i].list.ptr[0].type == Atom - ) { - name = items.ptr[i].list.ptr[0].atom; - } else { - errx(EX_PROTOCOL, "invalid data item name"); + enum Atom name = dataCheck(items.ptr[i], Atom).atom; + struct Data data = items.ptr[i + 1]; + if (name == AtomUID) { + uid = dataCheck(data, Number).number; + } else if (name == AtomEnvelope) { + parseEnvelope(&envelope, dataCheck(data, List).list); + } else if (name == AtomBodyStructure) { + parseBodyPart(&structure, dataCheck(data, List).list); } + if (name != AtomBody) continue; - struct Data data = items.ptr[i + 1]; - switch (name) { - break; case AtomBody: - i--; - break; case AtomUID: - uid = dataCheck(data, Number).number; - break; case AtomEnvelope: - parseEnvelope(&envelope, dataCheck(data, List).list); - break; case AtomBodyStructure: - parseBodyPart(&structure, dataCheck(data, List).list); - break; case AtomHeaderFields: + struct List section = dataCheck(data, List).list; + if (!section.len) { + errx(EX_PROTOCOL, "missing body data item section"); + } + if (i + 2 >= items.len) { + errx(EX_PROTOCOL, "missing body data item value"); + } + data = items.ptr[++i + 1]; + + if (section.ptr[0].type == Atom) { + name = section.ptr[0].atom; + if (name == AtomHeaderFields) { header = dataCheck(data, String).string; - break; case AtomText: - body = dataCheck(data, String).string; - break; default:; + } else if (name == AtomText) { + text = dataCheck(data, String).string; + } + continue; } + + // TODO: Build a structure of body data parallel to structure. } - if (!uid) errx(EX_PROTOCOL, "missing UID data item"); - if (!envelope.subject) errx(EX_PROTOCOL, "missing ENVELOPE data item"); - if (!header) errx(EX_PROTOCOL, "missing BODY[HEADER.FIELDS] data item"); - if (!body) errx(EX_PROTOCOL, "missing BODY[TEXT] data item"); + if (!uid) { + errx(EX_PROTOCOL, "missing UID data item"); + } + if (!structure.subtype) { + errx(EX_PROTOCOL, "missing BODYSTRUCTURE data item"); + } - exportMbox(uid, &envelope, header, body); - exportAtom(uid, &envelope, &structure, body); + bool fetch = false; + if (envelope.subject) { + if (!header) { + errx(EX_PROTOCOL, "missing BODY[HEADER.FIELDS] data item"); + } + if (!text) { + errx(EX_PROTOCOL, "missing BODY[TEXT] data item"); + } + exportMbox(uid, &envelope, header, text); + exportAtom(uid, &envelope, &structure, text); + + 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 { + // TODO: Correlate body parts to body data. + } envelopeFree(envelope); bodyPartFree(structure); - return false; + return fetch; } -- cgit 1.4.1