summary refs log tree commit diff
path: root/imap.c
diff options
context:
space:
mode:
Diffstat (limited to 'imap.c')
-rw-r--r--imap.c107
1 files changed, 55 insertions, 52 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;