about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--archive.c67
-rw-r--r--bubger.14
3 files changed, 46 insertions, 26 deletions
diff --git a/.gitignore b/.gitignore
index 0af5f60..e96af27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 *.o
 UID/
+UIDNEXT
 UIDVALIDITY
 bubger
 tags
diff --git a/archive.c b/archive.c
index 2e8bf31..97bb99a 100644
--- a/archive.c
+++ b/archive.c
@@ -29,27 +29,22 @@
 
 #define ENV_PASSWORD "BUBGER_IMAP_PASSWORD"
 
-static void checkValidity(uint32_t validity) {
-	FILE *file = fopen("UIDVALIDITY", "r");
-	if (file) {
-		uint32_t previous;
-		int n = fscanf(file, "%" SCNu32, &previous);
-		if (n < 1) errx(EX_DATAERR, "invalid UIDVALIDITY file");
-
-		if (validity != previous) {
-			errx(EX_TEMPFAIL, "UIDVALIDITY changed; fresh export required");
-		}
-
-	} else {
-		FILE *file = fopen("UIDVALIDITY", "w");
-		if (!file) err(EX_CANTCREAT, "UIDVALIDITY");
-
-		int n = fprintf(file, "%" PRIu32 "\n", validity);
-		if (n < 0) err(EX_IOERR, "UIDVALIDITY");
+static uint32_t uidRead(const char *path) {
+	FILE *file = fopen(path, "r");
+	if (!file) return 0;
+	uint32_t uid;
+	int n = fscanf(file, "%" SCNu32, &uid);
+	if (n < 1) errx(EX_DATAERR, "%s: invalid UID", path);
+	return uid;
+}
 
-		int error = fclose(file);
-		if (error) err(EX_IOERR, "UIDVALIDITY");
-	}
+static void uidWrite(const char *path, uint32_t uid) {
+	FILE *file = fopen(path, "w");
+	if (!file) err(EX_CANTCREAT, "%s", path);
+	int n = fprintf(file, "%" PRIu32 "\n", uid);
+	if (n < 0) err(EX_IOERR, "%s", path);
+	int error = fclose(file);
+	if (error) err(EX_IOERR, "%s", path);
 }
 
 int main(int argc, char *argv[]) {
@@ -129,13 +124,35 @@ int main(int argc, char *argv[]) {
 		if (
 			resp.resp == AtomOk &&
 			resp.code.len > 1 &&
-			resp.code.ptr[0].type == Atom &&
-			resp.code.ptr[0].atom == AtomUIDValidity
+			resp.code.ptr[0].type == Atom
 		) {
-			if (resp.code.ptr[1].type != Number) {
-				errx(EX_PROTOCOL, "invalid UIDVALIDITY");
+			enum Atom code = resp.code.ptr[0].atom;
+			if (code == AtomUIDValidity || code == AtomUIDNext) {
+				if (resp.code.ptr[1].type != Number) {
+					errx(EX_PROTOCOL, "invalid %s", Atoms[code]);
+				}
+			}
+			if (code == AtomUIDValidity) {
+				uint32_t validity = resp.code.ptr[1].number;
+				uint32_t previous = uidRead("UIDVALIDITY");
+				if (previous && validity != previous) {
+					errx(
+						EX_TEMPFAIL,
+						"UIDVALIDITY changed; fresh export required"
+					);
+				}
+				if (!previous) uidWrite("UIDVALIDITY", validity);
+			}
+			if (code == AtomUIDNext) {
+				uint32_t next = resp.code.ptr[1].number;
+				uint32_t prev = uidRead("UIDNEXT");
+				if (next == prev) {
+					examine = 0;
+					fprintf(imap, "ayy LOGOUT\r\n");
+				} else {
+					uidWrite("UIDNEXT", next);
+				}
 			}
-			checkValidity(resp.code.ptr[1].number);
 		}
 
 		if (resp.tag == examine) {
diff --git a/bubger.1 b/bubger.1
index 68a3adb..db93077 100644
--- a/bubger.1
+++ b/bubger.1
@@ -1,4 +1,4 @@
-.Dd April  9, 2020
+.Dd April 10, 2020
 .Dt BUBGER 1
 .Os
 .
@@ -104,6 +104,8 @@ The IMAP password.
 .Bl -tag -width Ds
 .It Pa UIDVALIDITY
 Stores the mailbox UID validity.
+.It Pa UIDNEXT
+Stores the next UID of the mailbox.
 .It Pa UID/*.atom , Pa UID/*.html , Pa UID/*.mbox
 Cached Atom, HTML and mboxrd fragments for each message.
 .It Pa thread/*.atom , Pa thread/*.html , Pa thread/*.mbox