about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--imap.h7
-rw-r--r--notemap.c196
2 files changed, 93 insertions, 110 deletions
diff --git a/imap.h b/imap.h
index 33dfd33..db4018e 100644
--- a/imap.h
+++ b/imap.h
@@ -154,6 +154,13 @@ struct Resp {
 	const char *text;
 };
 
+static inline struct Resp respOk(struct Resp resp) {
+	if (resp.resp == AtomNo || resp.resp == AtomBad || resp.resp == AtomBye) {
+		errx(EX_CONFIG, "%s: %s", Atoms[resp.tag], resp.text);
+	}
+	return resp;
+}
+
 static inline void respFree(struct Resp resp) {
 	listFree(resp.code);
 	listFree(resp.data);
diff --git a/notemap.c b/notemap.c
index a1d280c..997a410 100644
--- a/notemap.c
+++ b/notemap.c
@@ -214,150 +214,126 @@ int main(int argc, char *argv[]) {
 	FILE *map = fopen(path, "r");
 	if (!map) err(EX_NOINPUT, "%s", path);
 
-	size_t cap = 0;
-	char *entry = NULL;
-	char *uuid = NULL;
-	char *note = NULL;
-	uint32_t seq = 0;
-	char *message = NULL;
-
-	enum Atom login = 0;
-	enum Atom next = atom("next");
-	enum Atom create = atom("create");
-	enum Atom replace = atom("replace");
-
+	struct Resp resp;
 	struct IMAP imap = imapOpen(host, port);
-	for (
-		struct Resp resp;
-		resp = imapResp(&imap), resp.resp != AtomBye;
-		respFree(resp)
-	) {
-		if (resp.resp == AtomNo || resp.resp == AtomBad) {
-			errx(EX_CONFIG, "%s: %s", Atoms[resp.resp], resp.text);
-		}
+	respFree(respOk(imapResp(&imap)));
 
-		if (!login) {
-			login = atom("login");
-			fprintf(
-				imap.w, "%s LOGIN \"%s\" \"%s\"\r\n",
-				Atoms[login], user, pass
-			);
-		}
+	enum Atom login = atom("login");
+	fprintf(imap.w, "%s LOGIN \"%s\" \"%s\"\r\n", Atoms[login], user, pass);
+	for (; (resp = respOk(imapResp(&imap))).tag != login; respFree(resp));
+	respFree(resp);
 
-		if (resp.tag == login) {
-			fprintf(imap.w, "%s SELECT \"%s\"\r\n", Atoms[next], mailbox);
-		}
+	enum Atom select = atom("select");
+	fprintf(imap.w, "%s SELECT \"%s\"\r\n", Atoms[select], mailbox);
+	for (; (resp = respOk(imapResp(&imap))).tag != select; respFree(resp));
+	respFree(resp);
 
-		ssize_t len;
-		if (resp.tag == next) {
-next:
-			len = getline(&entry, &cap, map);
-			if (ferror(map)) err(EX_IOERR, "%s", path);
-			if (len < 1) {
-				fprintf(imap.w, "ayy LOGOUT\r\n");
-				continue;
-			}
-			if (entry[len - 1] == '\n') entry[len - 1] = '\0';
+	size_t cap = 0;
+	char *entry = NULL;
+	for (ssize_t len; 0 < (len = getline(&entry, &cap, map));) {
+		if (entry[len - 1] == '\n') entry[len - 1] = '\0';
 
-			note = entry;
-			uuid = strsep(&note, " ");
-			if (!note || !uuid || !uuidCheck(uuid)) {
-				errx(EX_CONFIG, "invalid map entry: %s", entry);
-			}
+		char *note = entry;
+		char *uuid = strsep(&note, " ");
+		if (!note || !uuid || !uuidCheck(uuid)) {
+			errx(EX_CONFIG, "invalid map entry: %s", entry);
+		}
 
-			if (argc) {
-				int i;
-				for (i = 0; i < argc; ++i) {
-					if (!argv[i]) continue;
-					if (strcmp(argv[i], note)) continue;
-					argv[i] = NULL;
-					break;
-				}
-				if (i == argc) goto next;
+		if (argc) {
+			int i;
+			for (i = 0; i < argc; ++i) {
+				if (!argv[i]) continue;
+				if (strcmp(argv[i], note)) continue;
+				argv[i] = NULL;
+				break;
 			}
-
-			fprintf(
-				imap.w,
-				"%s SEARCH HEADER X-Universally-Unique-Identifier \"%s\"\r\n",
-				Atoms[AtomSearch], uuid
-			);
-			continue;
+			if (i == argc) continue;
 		}
 
-		if (resp.resp == AtomSearch) {
+		uint32_t seq = 0;
+		enum Atom search = atom("search");
+		fprintf(
+			imap.w,
+			"%s SEARCH HEADER X-Universally-Unique-Identifier \"%s\"\r\n",
+			Atoms[search], uuid
+		);
+		for (; (resp = respOk(imapResp(&imap))).tag != search; respFree(resp)) {
+			if (resp.resp != AtomSearch) continue;
 			if (resp.data.len > 1) {
 				errx(EX_CONFIG, "multiple messages matching %s", uuid);
 			}
 			if (resp.data.len) {
 				seq = dataCheck(resp.data.ptr[0], Number).number;
-				fprintf(
-					imap.w, "%s FETCH %" PRIu32 " ENVELOPE\r\n",
-					Atoms[AtomFetch], seq
-				);
-			} else {
-				message = format(user, uuid, note);
-				fprintf(
-					imap.w, "%s APPEND %s (\\Seen) {%zu}\r\n",
-					Atoms[create], mailbox, strlen(message)
-				);
 			}
 		}
-		
-		if (resp.resp == AtomFetch) {
+		respFree(resp);
+
+		if (!seq) goto append;
+
+		struct tm date = {0};
+		enum Atom fetch = atom("fetch");
+		fprintf(
+			imap.w, "%s FETCH %" PRIu32 " ENVELOPE\r\n",
+			Atoms[fetch], seq
+		);
+		for (; (resp = respOk(imapResp(&imap))).tag != fetch; respFree(resp)) {
+			if (resp.resp != AtomFetch) continue;
 			if (!resp.data.len) errx(EX_PROTOCOL, "missing fetch data");
 			struct List items = dataCheck(resp.data.ptr[0], List).list;
 			if (items.len < 2) errx(EX_PROTOCOL, "missing fetch data items");
 			enum Atom item = dataCheck(items.ptr[0], Atom).atom;
 			if (item != AtomEnvelope) continue;
-
 			struct List envelope = dataCheck(items.ptr[1], List).list;
-			if (envelope.len < 1) errx(EX_PROTOCOL, "missing envelope date");
-
-			struct tm date = {0};
-			char *rest = strptime(
+			if (!envelope.len) errx(EX_PROTOCOL, "missing envelope date");
+			const char *rest = strptime(
 				dataCheck(envelope.ptr[0], String).string, DATE_FORMAT, &date
 			);
 			if (!rest) errx(EX_PROTOCOL, "invalid envelope date format");
-
-			struct stat status;
-			int error = stat(note, &status);
-			if (error) err(EX_NOINPUT, "%s", note);
-
-			if (!force && status.st_mtime < mktime(&date)) {
-				errx(
-					EX_TEMPFAIL,
-					"%s: note modified in mailbox; use -f to overwrite",
-					note
-				);
-			} else if (status.st_mtime == mktime(&date)) {
-				goto next;
-			}
-
-			message = format(user, uuid, note);
-			fprintf(
-				imap.w, "%s APPEND %s (\\Seen) {%zu}\r\n",
-				Atoms[replace], mailbox, strlen(message)
+		}
+		respFree(resp);
+
+		struct stat status;
+		int error = stat(note, &status);
+		if (error) err(EX_NOINPUT, "%s", note);
+		if (status.st_mtime < mktime(&date) && !force) {
+			errx(
+				EX_TEMPFAIL,
+				"%s: note modified in mailbox; use -f to overwrite", note
 			);
+		} else if (status.st_mtime == mktime(&date)) {
+			continue;
 		}
 
-		if (resp.tag == AtomContinue) {
-			fprintf(imap.w, "%s\r\n", message);
-			free(message);
+append:;
+		char *message = format(user, uuid, note);
+		enum Atom append = atom("append");
+		fprintf(
+			imap.w, "%s APPEND %s (\\Seen) {%zu}\r\n",
+			Atoms[append], mailbox, strlen(message)
+		);
+		for (; (resp = respOk(imapResp(&imap))).tag != append; respFree(resp)) {
+			if (resp.tag == AtomContinue) fprintf(imap.w, "%s\r\n", message);
 		}
+		respFree(resp);
+		free(message);
 
-		if (resp.tag == create) {
+		if (!seq) {
 			printf("+ %s\n", note);
-			goto next;
+			continue;
 		}
 
-		if (resp.tag == replace) {
-			printf("~ %s\n", note);
-			fprintf(
-				imap.w, "%s STORE %" PRIu32 " +FLAGS (\\Deleted)\r\n",
-				Atoms[next], seq
-			);
-		}
+		enum Atom delete = atom("delete");
+		fprintf(
+			imap.w, "%s STORE %" PRIu32 " +FLAGS (\\Deleted)\r\n",
+			Atoms[delete], seq
+		);
+		for (; (resp = respOk(imapResp(&imap))).tag != delete; respFree(resp));
+		respFree(resp);
+		printf("~ %s\n", note);
 	}
+	if (ferror(map)) err(EX_IOERR, "%s", path);
+
+	fprintf(imap.w, "ayy LOGOUT\r\n");
 	fclose(imap.r);
 	fclose(imap.w);