From 525648f0200230ca4fface61dac5b99c37a27e61 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Tue, 27 Oct 2020 19:47:07 -0400 Subject: Refactor IMAP struct --- imap.c | 107 +++++++++++++++++++++++++++++++++------------------------------- imap.h | 13 ++++++-- imbox.c | 33 ++++++++++---------- 3 files changed, 82 insertions(+), 71 deletions(-) diff --git a/imap.c b/imap.c index b4aa6be..77381f7 100644 --- a/imap.c +++ b/imap.c @@ -75,7 +75,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"); @@ -89,96 +89,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); @@ -187,8 +190,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; } @@ -207,13 +210,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 c2b7af1..0af96ff 100644 --- a/imap.h +++ b/imap.h @@ -163,7 +163,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/imbox.c b/imbox.c index 08b7181..e58663e 100644 --- a/imbox.c +++ b/imbox.c @@ -185,11 +185,10 @@ int main(int argc, char *argv[]) { enum Atom login = 0; enum Atom examine = atom("examine"); - 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) { @@ -199,33 +198,33 @@ 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 EXAMINE \"%s\"\r\n", Atoms[examine], mailbox); + fprintf(imap.w, "%s EXAMINE \"%s\"\r\n", Atoms[examine], mailbox); } if (resp.tag == examine) { - fprintf(imap, "%s SEARCH CHARSET UTF-8", Atoms[AtomSearch]); - if (subject) fprintf(imap, " SUBJECT \"%s\"", subject); - if (from) fprintf(imap, " FROM \"%s\"", from); - if (to) fprintf(imap, " TO \"%s\"", to); - if (cc) fprintf(imap, " CC \"%s\"", cc); - fprintf(imap, "\r\n"); + 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, "%s FETCH ", Atoms[AtomFetch]); + 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, "%s%" PRIu32, (i ? "," : ""), num); + fprintf(imap.w, "%s%" PRIu32, (i ? "," : ""), num); } fprintf( - imap, + imap.w, " (BODY[HEADER.FIELDS (" FETCH_HEADERS ")] BODY[TEXT])\r\n" ); } @@ -254,9 +253,9 @@ int main(int argc, char *argv[]) { } if (resp.tag == AtomFetch) { - fprintf(imap, "ayy LOGOUT\r\n"); + fprintf(imap.w, "ayy LOGOUT\r\n"); } } - fclose(imapRead); - fclose(imap); + fclose(imap.r); + fclose(imap.w); } -- cgit 1.4.1