summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--archive.h29
-rw-r--r--concat.c32
-rw-r--r--export.c11
3 files changed, 39 insertions, 33 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);
 
diff --git a/concat.c b/concat.c
index a3b4bac..8da5a7a 100644
--- a/concat.c
+++ b/concat.c
@@ -37,37 +37,9 @@
 #include "archive.h"
 #include "imap.h"
 
-static 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 void compressRoots(FILE *imap, struct List threads) {
-	uint32_t base = 0;
-	uint32_t prev = 0;
-	for (size_t i = 0; i < threads.len; ++i) {
-		uint32_t root = threadRoot(dataCheck(threads.ptr[i], List).list);
-		if (!base) {
-			fprintf(imap, "%" PRIu32, root);
-			base = prev = root;
-		} else if (root == prev + 1) {
-			prev = root;
-		} else {
-			if (prev > base) fprintf(imap, ":%" PRIu32, prev);
-			fprintf(imap, ",%" PRIu32, root);
-			base = prev = root;
-		}
-	}
-	if (prev > base) fprintf(imap, ":%" PRIu32, prev);
-}
-
 void concatFetch(FILE *imap, enum Atom tag, struct List threads) {
 	fprintf(imap, "%s UID FETCH ", Atoms[tag]);
-	compressRoots(imap, threads);
+	compressUIDs(imap, threads);
 	fprintf(imap, " (UID ENVELOPE)\r\n");
 }
 
@@ -75,7 +47,7 @@ void concatSearch(
 	FILE *imap, enum Atom tag, struct List threads, const char *expr
 ) {
 	fprintf(imap, "%s UID SEARCH CHARSET UTF-8 UID ", Atoms[tag]);
-	compressRoots(imap, threads);
+	compressUIDs(imap, threads);
 	fprintf(imap, " %s\r\n", expr);
 }
 
diff --git a/export.c b/export.c
index bebd524..b7420fb 100644
--- a/export.c
+++ b/export.c
@@ -48,6 +48,12 @@ static char *exportPath(uint32_t uid, const char *type) {
 	return templateString(PATH_UID, vars, escapePath);
 }
 
+static int numberCompare(const void *_a, const void *_b) {
+	const struct Data *a = _a;
+	const struct Data *b = _b;
+	return (a->number > b->number) - (a->number < b->number);
+}
+
 bool exportFetch(FILE *imap, enum Atom tag, struct List threads) {
 	struct List uids = {0};
 	listFlatten(&uids, threads);
@@ -69,11 +75,10 @@ bool exportFetch(FILE *imap, enum Atom tag, struct List threads) {
 		listFree(uids);
 		return false;
 	}
+	qsort(uids.ptr, uids.len, sizeof(*uids.ptr), numberCompare);
 
 	fprintf(imap, "%s UID FETCH ", Atoms[tag]);
-	for (size_t i = 0; i < uids.len; ++i) {
-		fprintf(imap, "%s%" PRIu32, (i ? "," : ""), uids.ptr[i].number);
-	}
+	compressUIDs(imap, uids);
 	listFree(uids);
 	fprintf(
 		imap,