summary refs log tree commit diff
path: root/archive.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2021-06-12 19:20:47 -0400
committerJune McEnroe <june@causal.agency>2021-06-12 19:20:47 -0400
commit9b09a5ff483aef05dc5b4d9ab0fd0243d21cb1d3 (patch)
tree2a2be7ddda0e4161833e0e35cdf8585aa8016fc7 /archive.c
parentAdd margin between header navs (diff)
downloadbubger-9b09a5ff483aef05dc5b4d9ab0fd0243d21cb1d3.tar.gz
bubger-9b09a5ff483aef05dc5b4d9ab0fd0243d21cb1d3.zip
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.
Diffstat (limited to '')
-rw-r--r--archive.c76
1 files changed, 24 insertions, 52 deletions
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;