From 67721f3dbd4ffeb1a03145170df40f616ee0a118 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Sat, 25 Apr 2020 14:22:41 -0400 Subject: Accumulate thread envelopes before concatenation --- archive.c | 10 ++++++++- archive.h | 6 ++++- concat.c | 76 ++++++++++++++++++++++++++++++++++++--------------------------- 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/archive.c b/archive.c index 64b234e..af0329a 100644 --- a/archive.c +++ b/archive.c @@ -123,6 +123,7 @@ int main(int argc, char *argv[]) { uint32_t uidNext = 0; struct List threads = {0}; + struct Envelope *envelopes = NULL; for (struct Resp resp; resp = imapResp(imapRead), resp.resp != AtomBye;) { if (resp.resp == AtomNo || resp.resp == AtomBad) { errx(EX_CONFIG, "%s %s", Atoms[resp.resp], resp.text); @@ -184,8 +185,12 @@ int main(int argc, char *argv[]) { createDir("attachment"); createDir("message"); createDir("thread"); + threads = resp.data; resp.data = (struct List) {0}; + envelopes = calloc(threads.len, sizeof(*envelopes)); + if (!envelopes) err(EX_OSERR, "calloc"); + if (exportFetch(imap, export, threads)) { exportTags = 1; state = Export; @@ -209,9 +214,12 @@ int main(int argc, char *argv[]) { break; case Concat: { if (resp.resp == AtomFetch) { if (!resp.data.len) errx(EX_PROTOCOL, "missing FETCH data"); - concatData(threads, dataCheck(resp.data.ptr[0], List).list); + struct Data items = dataTake(&resp.data.ptr[0]); + concatData(threads, envelopes, dataCheck(items, List).list); } if (resp.tag != concat) break; + concatThreads(threads, envelopes); + concatIndex(threads, envelopes); uidWrite("UIDNEXT", uidNext); fprintf(imap, "ayy LOGOUT\r\n"); state = Logout; diff --git a/archive.h b/archive.h index 23f27f1..65f8a84 100644 --- a/archive.h +++ b/archive.h @@ -140,7 +140,11 @@ bool exportData(FILE *imap, enum Atom tag, struct List items); extern const char *concatHead; void concatFetch(FILE *imap, enum Atom tag, struct List threads); -void concatData(struct List threads, struct List items); +void concatData( + struct List threads, struct Envelope *envelopes, struct List items +); +void concatThreads(struct List threads, const struct Envelope *envelopes); +void concatIndex(struct List threads, const struct Envelope *envelopes); #define TEMPLATE(...) #__VA_ARGS__ diff --git a/concat.c b/concat.c index 22645e4..e75c857 100644 --- a/concat.c +++ b/concat.c @@ -35,14 +35,6 @@ static uint32_t threadRoot(struct List thread) { return dataCheck(thread.ptr[0], Number).number; } -static struct List threadFind(struct List threads, uint32_t root) { - for (size_t i = 0; i < threads.len; ++i) { - struct List thread = dataCheck(threads.ptr[i], List).list; - if (threadRoot(thread) == root) return thread; - } - errx(EX_TEMPFAIL, "no thread with root UID %" PRIu32, root); -} - void concatFetch(FILE *imap, enum Atom tag, struct List threads) { fprintf(imap, "%s UID FETCH ", Atoms[tag]); for (size_t i = 0; i < threads.len; ++i) { @@ -52,6 +44,33 @@ void concatFetch(FILE *imap, enum Atom tag, struct List threads) { fprintf(imap, " (UID ENVELOPE)\r\n"); } +void concatData( + struct List threads, struct Envelope *envelopes, struct List items +) { + uint32_t uid = 0; + struct List envelope = {0}; + for (size_t i = 0; i + 1 < items.len; i += 2) { + enum Atom name = dataCheck(items.ptr[i], Atom).atom; + struct Data data = items.ptr[i + 1]; + switch (name) { + break; case AtomUID: uid = dataCheck(data, Number).number; + break; case AtomEnvelope: envelope = dataCheck(data, List).list; + break; default:; + } + } + if (!uid) errx(EX_PROTOCOL, "missing UID data item"); + if (!envelope.len) errx(EX_PROTOCOL, "missing ENVELOPE data item"); + + for (size_t i = 0; i < threads.len; ++i) { + struct List thread = dataCheck(threads.ptr[i], List).list; + if (threadRoot(thread) == uid) { + parseEnvelope(&envelopes[i], envelope); + return; + } + } + errx(EX_TEMPFAIL, "no thread with root UID %" PRIu32, uid); +} + static const char *uidPath(uint32_t uid, const char *type) { char str[32]; snprintf(str, sizeof(str), "%" PRIu32, uid); @@ -119,24 +138,7 @@ static const char *threadPath(const char *messageID, const char *type) { const char *concatHead; -void concatData(struct List threads, struct List items) { - uint32_t uid = 0; - struct Envelope envelope = {0}; - for (size_t i = 0; i + 1 < items.len; i += 2) { - enum Atom name = dataCheck(items.ptr[i], Atom).atom; - struct Data data = items.ptr[i + 1]; - switch (name) { - break; case AtomUID: - uid = dataCheck(data, Number).number; - break; case AtomEnvelope: - parseEnvelope(&envelope, dataCheck(data, List).list); - break; default:; - } - } - if (!uid) errx(EX_PROTOCOL, "missing UID data item"); - if (!envelope.subject) errx(EX_PROTOCOL, "missing ENVELOPE data item"); - - struct List thread = threadFind(threads, uid); +static void concatThread(struct List thread, const struct Envelope *envelope) { struct List flat = {0}; listFlatten(&flat, thread); @@ -145,7 +147,7 @@ void concatData(struct List threads, struct List items) { const char *path; struct stat status; - path = threadPath(envelope.messageID, "mbox"); + path = threadPath(envelope->messageID, "mbox"); error = stat(path, &status); if (error || status.st_mtime < uidNewest(flat, "mbox")) { file = fopen(path, "w"); @@ -161,13 +163,13 @@ void concatData(struct List threads, struct List items) { if (error) err(EX_IOERR, "%s", path); } - path = threadPath(envelope.messageID, "atom"); + path = threadPath(envelope->messageID, "atom"); error = stat(path, &status); if (error || status.st_mtime < uidNewest(flat, "atom")) { FILE *file = fopen(path, "w"); if (!file) err(EX_CANTCREAT, "%s", path); - error = atomFeedOpen(file, &envelope); + error = atomFeedOpen(file, envelope); if (error) err(EX_IOERR, "%s", path); for (size_t i = 0; i < flat.len; ++i) { @@ -180,13 +182,13 @@ void concatData(struct List threads, struct List items) { if (error) err(EX_IOERR, "%s", path); } - path = threadPath(envelope.messageID, "html"); + path = threadPath(envelope->messageID, "html"); error = stat(path, &status); if (error || status.st_mtime < uidNewest(flat, "html")) { FILE *file = fopen(path, "w"); if (!file) err(EX_CANTCREAT, "%s", path); - error = htmlThreadHead(file, &envelope); + error = htmlThreadHead(file, envelope); if (error) err(EX_IOERR, "%s", path); if (concatHead) { @@ -195,7 +197,7 @@ void concatData(struct List threads, struct List items) { } error = 0 - || htmlThreadOpen(file, &envelope) + || htmlThreadOpen(file, envelope) || concatHTML(file, thread) || htmlThreadClose(file) || fclose(file); @@ -203,5 +205,13 @@ void concatData(struct List threads, struct List items) { } listFree(flat); - envelopeFree(envelope); +} + +void concatThreads(struct List threads, const struct Envelope *envelopes) { + for (size_t i = 0; i < threads.len; ++i) { + concatThread(dataCheck(threads.ptr[i], List).list, &envelopes[i]); + } +} + +void concatIndex(struct List threads, const struct Envelope *envelopes) { } -- cgit 1.4.1