summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--imap.h7
-rw-r--r--imbox.c125
2 files changed, 65 insertions, 67 deletions
diff --git a/imap.h b/imap.h
index c6d96f5..2730d1a 100644
--- a/imap.h
+++ b/imap.h
@@ -157,6 +157,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/imbox.c b/imbox.c
index 8c4d351..f1ed24a 100644
--- a/imbox.c
+++ b/imbox.c
@@ -108,80 +108,71 @@ int main(int argc, char *argv[]) {
 	);
 	if (!pass) err(EX_UNAVAILABLE, "readpassphrase");
 
-	enum Atom login = 0;
-	enum Atom examine = atom("examine");
-
+	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)), resp.tag != login; respFree(resp));
+	respFree(resp);
 
-		if (resp.tag == login) {
-			fprintf(imap.w, "%s EXAMINE \"%s\"\r\n", Atoms[examine], mailbox);
-		}
-
-		if (resp.tag == examine) {
-			fprintf(imap.w, "%s SEARCH CHARSET UTF-8", Atoms[AtomSearch]);
-			if (subject) fprintf(imap.w, " SUBJECT \"%s\"", subject);
-			if (from) fprintf(imap.w, " FROM \"%s\"", from);
-			if (to) fprintf(imap.w, " TO \"%s\"", to);
-			if (cc) fprintf(imap.w, " CC \"%s\"", cc);
-			fprintf(imap.w, "\r\n");
-		}
-
-		if (resp.resp == AtomSearch) {
-			if (!resp.data.len) errx(EX_TEMPFAIL, "no matching messages");
-			fprintf(imap.w, "%s FETCH ", Atoms[AtomFetch]);
-			for (size_t i = 0; i < resp.data.len; ++i) {
-				uint32_t num = dataCheck(resp.data.ptr[i], Number).number;
-				fprintf(imap.w, "%s%" PRIu32, (i ? "," : ""), num);
-			}
-			fprintf(
-				imap.w,
-				" (BODY[HEADER.FIELDS (" FETCH_HEADERS ")] BODY[TEXT])\r\n"
-			);
-		}
+	enum Atom examine = atom("examine");
+	fprintf(imap.w, "%s EXAMINE \"%s\"\r\n", Atoms[examine], mailbox);
+	for (; resp = respOk(imapResp(&imap)), resp.tag != examine; respFree(resp));
+	respFree(resp);
+
+	struct List nums = {0};
+	enum Atom search = atom("search");
+	fprintf(imap.w, "%s SEARCH CHARSET UTF-8", Atoms[search]);
+	if (subject) fprintf(imap.w, " SUBJECT \"%s\"", subject);
+	if (from) fprintf(imap.w, " FROM \"%s\"", from);
+	if (to) fprintf(imap.w, " TO \"%s\"", to);
+	if (cc) fprintf(imap.w, " CC \"%s\"", cc);
+	fprintf(imap.w, "\r\n");
+	for (; resp = respOk(imapResp(&imap)), resp.tag != search; respFree(resp)) {
+		if (resp.resp != AtomSearch) continue;
+		if (!resp.data.len) errx(EX_TEMPFAIL, "no matching messages");
+		nums = resp.data;
+		resp.data = (struct List) {0};
+	}
+	respFree(resp);
 
-		if (resp.resp == AtomFetch) {
-			if (!resp.data.len) errx(EX_PROTOCOL, "missing fetch data");
-			struct List items = dataCheck(resp.data.ptr[0], List).list;
-			struct Data header = {0};
-			struct Data body = {0};
-			for (size_t i = 0; i < items.len; ++i) {
-				struct Data item = items.ptr[i];
-				if (item.type != List) continue;
-				if (!item.list.len) continue;
-				if (item.list.ptr[0].type != Atom) continue;
-				if (item.list.ptr[0].atom == AtomHeader) {
-					if (i + 1 < items.len) header = items.ptr[i + 1];
-				}
-				if (item.list.ptr[0].atom == AtomText) {
-					if (i + 1 < items.len) body = items.ptr[i + 1];
-				}
+	enum Atom fetch = atom("fetch");
+	fprintf(imap.w, "%s FETCH ", Atoms[fetch]);
+	for (size_t i = 0; i < nums.len; ++i) {
+		uint32_t num = dataCheck(nums.ptr[i], Number).number;
+		fprintf(imap.w, "%s%" PRIu32, (i ? "," : ""), num);
+	}
+	fprintf(
+		imap.w, " (BODY[HEADER.FIELDS (" FETCH_HEADERS ")] BODY[TEXT])\r\n"
+	);
+	for (; resp = respOk(imapResp(&imap)), resp.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;
+		struct Data header = {0};
+		struct Data body = {0};
+		for (size_t i = 0; i + 2 < items.len; ++i) {
+			struct Data item = items.ptr[i];
+			if (item.type != Atom || item.atom != AtomBody) continue;
+			if (items.ptr[i + 1].type != List) continue;
+			struct List sect = items.ptr[i + 1].list;
+			if (!sect.len || sect.ptr[0].type != Atom) continue;
+			if (sect.ptr[0].atom == AtomHeader) {
+				header = items.ptr[i + 2];
+			} else if (sect.ptr[0].atom == AtomText) {
+				body = items.ptr[i + 2];
 			}
-			mboxrd(
-				dataCheck(header, String).string,
-				dataCheck(body, String).string
-			);
-		}
-
-		if (resp.tag == AtomFetch) {
-			fprintf(imap.w, "ayy LOGOUT\r\n");
 		}
+		mboxrd(
+			dataCheck(header, String).string,
+			dataCheck(body, String).string
+		);
 	}
+	respFree(resp);
+
+	fprintf(imap.w, "ayy LOGOUT\r\n");
 	fclose(imap.r);
 	fclose(imap.w);
 }