about summary refs log tree commit diff
path: root/archive.h
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2021-06-13 11:17:21 -0400
committerJune McEnroe <june@causal.agency>2021-06-13 11:17:21 -0400
commit2d048a0c5a7be72038d70e7473b84f19cacc85fa (patch)
tree9d6f7549740f9f7bf7d278cc6e5ce39256cb0c7d /archive.h
parentCompress thread root UID sets with ranges (diff)
downloadbubger-2d048a0c5a7be72038d70e7473b84f19cacc85fa.tar.gz
bubger-2d048a0c5a7be72038d70e7473b84f19cacc85fa.zip
Sort and compress export fetch UIDs
Diffstat (limited to 'archive.h')
-rw-r--r--archive.h29
1 files changed, 29 insertions, 0 deletions
diff --git a/archive.h b/archive.h
index d6b9608..921ae06 100644
--- a/archive.h
+++ b/archive.h
@@ -218,6 +218,35 @@ char *decodeHeader(const char *header);
 char *decodeToString(const struct BodyPart *part, const char *content);
 int decodeToFile(FILE *file, const struct BodyPart *part, const char *content);
 
+static inline uint32_t threadRoot(struct List thread) {
+	if (!thread.len) errx(EX_PROTOCOL, "empty thread");
+	while (thread.ptr[0].type == List) {
+		thread = thread.ptr[0].list;
+		if (!thread.len) errx(EX_PROTOCOL, "empty subthread");
+	}
+	return dataCheck(thread.ptr[0], Number).number;
+}
+
+static inline void compressUIDs(FILE *imap, struct List uids) {
+	uint32_t base = 0, prev = 0;
+	for (size_t i = 0; i < uids.len; ++i) {
+		uint32_t uid = uids.ptr[i].type == List
+			? threadRoot(uids.ptr[i].list)
+			: dataCheck(uids.ptr[i], Number).number;
+		if (!base) {
+			fprintf(imap, "%" PRIu32, uid);
+			base = prev = uid;
+		} else if (uid == prev + 1) {
+			prev = uid;
+		} else {
+			if (prev > base) fprintf(imap, ":%" PRIu32, prev);
+			fprintf(imap, ",%" PRIu32, uid);
+			base = prev = uid;
+		}
+	}
+	if (prev > base) fprintf(imap, ":%" PRIu32, prev);
+}
+
 bool exportFetch(FILE *imap, enum Atom tag, struct List threads);
 bool exportData(FILE *imap, enum Atom tag, struct List items);