From 9b09a5ff483aef05dc5b4d9ab0fd0243d21cb1d3 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Sat, 12 Jun 2021 19:20:47 -0400 Subject: Use SEARCH for a subset of thread roots This does way less duplicate work by fetching all threads and all thread root envelopes once, then doing searches for subsets of thread roots. --- archive.c | 76 ++++++++++++++++++++------------------------------------------- 1 file changed, 24 insertions(+), 52 deletions(-) (limited to 'archive.c') diff --git a/archive.c b/archive.c index 74491a1..20ea5d0 100644 --- a/archive.c +++ b/archive.c @@ -80,12 +80,7 @@ static void createDirs(void) { createDir("thread"); } -static struct Search { - size_t cap; - size_t len; - char **names; - char **exprs; -} search; +struct Search search; static void searchAdd(const char *name, const char *expr) { if (search.len == search.cap) { @@ -134,51 +129,24 @@ static void searchDefault(void) { searchAdd("index", "ALL"); } -static const char *algo = "REFERENCES"; - -static void -searchThreads(struct IMAP *imap, const char *name, const char *expr) { +static void searchThreads( + struct IMAP *imap, struct List threads, const struct Envelope *envelopes, + const char *name, const char *expr +) { struct Resp resp; - struct List threads = {0}; - struct List envelopeItems = {0}; - struct Envelope *envelopes = NULL; - - enum Atom thread = atom("thread"); - fprintf( - imap->w, "%s UID THREAD %s UTF-8 %s\r\n", - Atoms[thread], algo, expr - ); - for (; resp = respOk(imapResp(imap)), resp.tag != thread; respFree(resp)) { - if (resp.resp != AtomThread) continue; - threads = resp.data; - resp.data = (struct List) {0}; // prevent freeing threads with resp + struct List roots = {0}; + + enum Atom search = atom("search"); + concatSearch(imap->w, search, threads, expr); + for (; resp = respOk(imapResp(imap)), resp.tag != search; respFree(resp)) { + if (resp.resp != AtomSearch) continue; + roots = resp.data; + resp.data = (struct List) {0}; // prevent freeing roots with resp } respFree(resp); - if (!threads.len) goto concat; - enum Atom concat = atom("concat"); - envelopes = calloc(threads.len, sizeof(*envelopes)); - if (!envelopes) err(EX_OSERR, "calloc"); - concatFetch(imap->w, concat, threads); - for (; resp = respOk(imapResp(imap)), resp.tag != concat; respFree(resp)) { - if (resp.resp != AtomFetch) continue; - if (!resp.data.len) errx(EX_PROTOCOL, "missing FETCH data"); - // Prevent freeing data in envelopes with resp: - struct Data items = dataTake(&resp.data.ptr[0]); - concatData(threads, envelopes, dataCheck(items, List).list); - listPush(&envelopeItems, items); - } - respFree(resp); - -concat: - concatSearch(name, threads, envelopes, search.names, search.len); - - for (size_t i = 0; i < threads.len; ++i) { - envelopeFree(envelopes[i]); - } - free(envelopes); - listFree(envelopeItems); - listFree(threads); + concatIndex(name, roots, threads, envelopes); + listFree(roots); } int main(int argc, char *argv[]) { @@ -191,6 +159,7 @@ int main(int argc, char *argv[]) { bool idle = false; const char *mailbox = "Archive"; + const char *algo = "REFERENCES"; const char *searchPath = NULL; for ( @@ -198,7 +167,7 @@ int main(int argc, char *argv[]) { 0 < (opt = getopt(argc, argv, "A:C:H:S:T:a:h:im:p:qs:u:vw:y:")); ) { switch (opt) { - break; case 'A': concatSearchEntries = strtoul(optarg, NULL, 10); + break; case 'A': concatIndexEntries = strtoul(optarg, NULL, 10); break; case 'C': { int error = chdir(optarg); if (error) err(EX_NOINPUT, "%s", optarg); @@ -362,6 +331,13 @@ concat:; respFree(resp); concatThreads(threads, envelopes); + for (size_t i = 0; i < search.len; ++i) { + searchThreads( + &imap, threads, envelopes, + search.names[i], search.exprs[i] + ); + } + for (size_t i = 0; i < threads.len; ++i) { envelopeFree(envelopes[i]); } @@ -369,10 +345,6 @@ concat:; listFree(envelopeItems); listFree(threads); - for (size_t i = 0; i < search.len; ++i) { - searchThreads(&imap, search.names[i], search.exprs[i]); - } - fflush(stdout); uidWrite("UIDNEXT", uidNext); if (!idle) goto logout; -- cgit 1.4.1