summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--imap.c107
-rw-r--r--imap.h13
-rw-r--r--notemap.c27
3 files changed, 79 insertions, 68 deletions
diff --git a/imap.c b/imap.c
index 54c02bf..8437a2c 100644
--- a/imap.c
+++ b/imap.c
@@ -81,7 +81,7 @@ static int imapClose(void *_tls) {
 	return error;
 }
 
-void imapOpen(FILE **read, FILE **write, const char *host, const char *port) {
+struct IMAP imapOpen(const char *host, const char *port) {
 	struct tls *client = tls_client();
 	if (!client) errx(EX_SOFTWARE, "tls_client");
 
@@ -95,96 +95,99 @@ void imapOpen(FILE **read, FILE **write, const char *host, const char *port) {
 	error = tls_connect(client, host, port);
 	if (error) errx(EX_NOHOST, "tls_connect: %s", tls_error(client));
 
-	*read = funopen(client, imapRead, NULL, NULL, NULL);
-	*write = funopen(client, NULL, imapWrite, NULL, imapClose);
-	if (!*read || !*write) err(EX_SOFTWARE, "funopen");
+	struct IMAP imap = {
+		.r = funopen(client, imapRead, NULL, NULL, NULL),
+		.w = funopen(client, NULL, imapWrite, NULL, imapClose),
+	};
+	if (!imap.r || !imap.w) err(EX_OSERR, "funopen");
 
-	setlinebuf(*write);
+	setlinebuf(imap.w);
+	return imap;
 }
 
-static size_t cap;
-static char *buf;
-static char *ptr;
-
-static void imapLine(FILE *imap) {
-	ssize_t len = getline(&buf, &cap, imap);
+static void imapLine(struct IMAP *imap) {
+	ssize_t len = getline(&imap->buf, &imap->cap, imap->r);
 	if (len < 0) errx(EX_PROTOCOL, "unexpected eof");
-	if (len < 1 || buf[len - 1] != '\n') errx(EX_PROTOCOL, "missing LF");
-	if (len < 2 || buf[len - 2] != '\r') errx(EX_PROTOCOL, "missing CR");
-	buf[len - 2] = '\0';
-	ptr = buf;
+	if (len < 1 || imap->buf[len - 1] != '\n') errx(EX_PROTOCOL, "missing LF");
+	if (len < 2 || imap->buf[len - 2] != '\r') errx(EX_PROTOCOL, "missing CR");
+	imap->buf[len - 2] = '\0';
+	imap->ptr = imap->buf;
 }
 
-static struct Data parseAtom(void) {
-	size_t len = (*ptr == '.' ? 1 : strcspn(ptr, " .()[]{\""));
+static struct Data parseAtom(struct IMAP *imap) {
+	size_t len = (*imap->ptr == '.' ? 1 : strcspn(imap->ptr, " .()[]{\""));
 	struct Data data = {
 		.type = Atom,
-		.atom = atomn(ptr, len),
+		.atom = atomn(imap->ptr, len),
 	};
-	ptr += len;
+	imap->ptr += len;
 	return data;
 }
 
-static struct Data parseNumber(void) {
+static struct Data parseNumber(struct IMAP *imap) {
 	return (struct Data) {
 		.type = Number,
-		.number = strtoull(ptr, &ptr, 10),
+		.number = strtoull(imap->ptr, &imap->ptr, 10),
 	};
 }
 
-static struct Data parseQuoted(void) {
-	ptr++;
-	size_t len = strcspn(ptr, "\"");
-	if (ptr[len] != '"') errx(EX_PROTOCOL, "missing quoted string delimiter");
+static struct Data parseQuoted(struct IMAP *imap) {
+	imap->ptr++;
+	size_t len = strcspn(imap->ptr, "\"");
+	if (imap->ptr[len] != '"') {
+		errx(EX_PROTOCOL, "missing quoted string delimiter");
+	}
 	struct Data data = {
 		.type = String,
-		.string = strndup(ptr, len),
+		.string = strndup(imap->ptr, len),
 	};
 	if (!data.string) err(EX_OSERR, "strndup");
-	ptr += len + 1;
+	imap->ptr += len + 1;
 	return data;
 }
 
-static struct Data parseLiteral(FILE *imap) {
-	ptr++;
-	size_t len = strtoull(ptr, &ptr, 10);
-	if (*ptr != '}') errx(EX_PROTOCOL, "missing literal prefix delimiter");
+static struct Data parseLiteral(struct IMAP *imap) {
+	imap->ptr++;
+	size_t len = strtoull(imap->ptr, &imap->ptr, 10);
+	if (*imap->ptr != '}') {
+		errx(EX_PROTOCOL, "missing literal prefix delimiter");
+	}
 	struct Data data = {
 		.type = String,
 		.string = malloc(len + 1),
 	};
 	if (!data.string) err(EX_OSERR, "malloc");
-	size_t n = fread(data.string, len, 1, imap);
+	size_t n = fread(data.string, len, 1, imap->r);
 	if (!n) errx(EX_PROTOCOL, "truncated literal");
 	imapLine(imap);
 	data.string[len] = '\0';
 	return data;
 }
 
-static struct Data parseData(FILE *imap);
+static struct Data parseData(struct IMAP *imap);
 
-static struct Data parseList(FILE *imap, char close) {
-	if (*ptr) ptr++;
+static struct Data parseList(struct IMAP *imap, char close) {
+	if (*imap->ptr) imap->ptr++;
 	struct Data data = { .type = List };
-	while (*ptr != close) {
+	while (*imap->ptr != close) {
 		listPush(&data.list, parseData(imap));
 	}
-	if (*ptr) ptr++;
+	if (*imap->ptr) imap->ptr++;
 	return data;
 }
 
-static struct Data parseData(FILE *imap) {
-	if (*ptr == ' ') ptr++;
-	if (*ptr == '"') return parseQuoted();
-	if (*ptr == '{') return parseLiteral(imap);
-	if (*ptr == '(') return parseList(imap, ')');
-	if (*ptr == '[') return parseList(imap, ']');
-	if (*ptr >= '0' && *ptr <= '9') return parseNumber();
-	if (*ptr) return parseAtom();
+static struct Data parseData(struct IMAP *imap) {
+	if (*imap->ptr == ' ') imap->ptr++;
+	if (*imap->ptr == '"') return parseQuoted(imap);
+	if (*imap->ptr == '{') return parseLiteral(imap);
+	if (*imap->ptr == '(') return parseList(imap, ')');
+	if (*imap->ptr == '[') return parseList(imap, ']');
+	if (*imap->ptr >= '0' && *imap->ptr <= '9') return parseNumber(imap);
+	if (*imap->ptr) return parseAtom(imap);
 	errx(EX_PROTOCOL, "unexpected eof");
 }
 
-struct Resp imapResp(FILE *imap) {
+struct Resp imapResp(struct IMAP *imap) {
 	struct Data data;
 	struct Resp resp = {0};
 	imapLine(imap);
@@ -193,8 +196,8 @@ struct Resp imapResp(FILE *imap) {
 	if (data.type != Atom) errx(EX_PROTOCOL, "expected tag atom");
 	resp.tag = data.atom;
 	if (resp.tag == AtomContinue) {
-		if (*ptr == ' ') ptr++;
-		resp.text = ptr;
+		if (*imap->ptr == ' ') imap->ptr++;
+		resp.text = imap->ptr;
 		return resp;
 	}
 
@@ -213,13 +216,13 @@ struct Resp imapResp(FILE *imap) {
 		resp.resp == AtomPreauth ||
 		resp.resp == AtomBye
 	) {
-		if (*ptr == ' ') ptr++;
-		if (*ptr == '[') {
+		if (*imap->ptr == ' ') imap->ptr++;
+		if (*imap->ptr == '[') {
 			data = parseList(imap, ']');
 			resp.code = data.list;
 		}
-		if (*ptr == ' ') ptr++;
-		resp.text = ptr;
+		if (*imap->ptr == ' ') imap->ptr++;
+		resp.text = imap->ptr;
 	} else {
 		data = parseList(imap, '\0');
 		resp.data = data.list;
diff --git a/imap.h b/imap.h
index 186cc55..7cd52e6 100644
--- a/imap.h
+++ b/imap.h
@@ -160,7 +160,16 @@ static inline void respFree(struct Resp resp) {
 }
 
 extern bool imapVerbose;
-void imapOpen(FILE **read, FILE **write, const char *host, const char *port);
-struct Resp imapResp(FILE *imapRead);
+
+struct IMAP {
+	FILE *r;
+	FILE *w;
+	size_t cap;
+	char *buf;
+	char *ptr;
+};
+
+struct IMAP imapOpen(const char *host, const char *port);
+struct Resp imapResp(struct IMAP *imap);
 
 #endif /* IMAP_H */
diff --git a/notemap.c b/notemap.c
index 8cdde70..8612493 100644
--- a/notemap.c
+++ b/notemap.c
@@ -295,11 +295,10 @@ int main(int argc, char *argv[]) {
 	enum Atom create = atom("create");
 	enum Atom replace = atom("replace");
 
-	FILE *imapRead, *imap;
-	imapOpen(&imapRead, &imap, host, port);
+	struct IMAP imap = imapOpen(host, port);
 	for (
 		struct Resp resp;
-		resp = imapResp(imapRead), resp.resp != AtomBye;
+		resp = imapResp(&imap), resp.resp != AtomBye;
 		respFree(resp)
 	) {
 		if (resp.resp == AtomNo || resp.resp == AtomBad) {
@@ -309,13 +308,13 @@ int main(int argc, char *argv[]) {
 		if (!login) {
 			login = atom("login");
 			fprintf(
-				imap, "%s LOGIN \"%s\" \"%s\"\r\n",
+				imap.w, "%s LOGIN \"%s\" \"%s\"\r\n",
 				Atoms[login], user, pass
 			);
 		}
 
 		if (resp.tag == login) {
-			fprintf(imap, "%s SELECT \"%s\"\r\n", Atoms[next], mailbox);
+			fprintf(imap.w, "%s SELECT \"%s\"\r\n", Atoms[next], mailbox);
 		}
 
 		ssize_t len;
@@ -324,7 +323,7 @@ next:
 			len = getline(&entry, &cap, map);
 			if (ferror(map)) err(EX_IOERR, "%s", path);
 			if (len < 1) {
-				fprintf(imap, "ayy LOGOUT\r\n");
+				fprintf(imap.w, "ayy LOGOUT\r\n");
 				continue;
 			}
 			if (entry[len - 1] == '\n') entry[len - 1] = '\0';
@@ -347,7 +346,7 @@ next:
 			}
 
 			fprintf(
-				imap,
+				imap.w,
 				"%s SEARCH HEADER X-Universally-Unique-Identifier \"%s\"\r\n",
 				Atoms[AtomSearch], uuid
 			);
@@ -361,13 +360,13 @@ next:
 			if (resp.data.len) {
 				seq = dataCheck(resp.data.ptr[0], Number).number;
 				fprintf(
-					imap, "%s FETCH %" PRIu32 " ENVELOPE\r\n",
+					imap.w, "%s FETCH %" PRIu32 " ENVELOPE\r\n",
 					Atoms[AtomFetch], seq
 				);
 			} else {
 				message = format(user, uuid, note);
 				fprintf(
-					imap, "%s APPEND %s (\\Seen) {%zu}\r\n",
+					imap.w, "%s APPEND %s (\\Seen) {%zu}\r\n",
 					Atoms[create], mailbox, strlen(message)
 				);
 			}
@@ -405,13 +404,13 @@ next:
 
 			message = format(user, uuid, note);
 			fprintf(
-				imap, "%s APPEND %s (\\Seen) {%zu}\r\n",
+				imap.w, "%s APPEND %s (\\Seen) {%zu}\r\n",
 				Atoms[replace], mailbox, strlen(message)
 			);
 		}
 
 		if (resp.tag == AtomContinue) {
-			fprintf(imap, "%s\r\n", message);
+			fprintf(imap.w, "%s\r\n", message);
 			free(message);
 		}
 
@@ -423,13 +422,13 @@ next:
 		if (resp.tag == replace) {
 			printf("~ %s\n", note);
 			fprintf(
-				imap, "%s STORE %" PRIu32 " +FLAGS (\\Deleted)\r\n",
+				imap.w, "%s STORE %" PRIu32 " +FLAGS (\\Deleted)\r\n",
 				Atoms[next], seq
 			);
 		}
 	}
-	fclose(imapRead);
-	fclose(imap);
+	fclose(imap.r);
+	fclose(imap.w);
 
 	int ret = EX_OK;
 	for (int i = 0; i < argc; ++i) {