From b07b342d93ea5720cbbc0c347bf610aeaa1c1e92 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Sat, 28 Nov 2020 20:43:28 -0500 Subject: Refactor IMAP struct --- archive.c | 27 +++++++-------- imap.c | 115 ++++++++++++++++++++++++++++++++++---------------------------- imap.h | 13 +++++-- 3 files changed, 87 insertions(+), 68 deletions(-) diff --git a/archive.c b/archive.c index 376e2fc..469c24c 100644 --- a/archive.c +++ b/archive.c @@ -151,11 +151,10 @@ int main(int argc, char *argv[]) { struct List threads = {0}; struct Envelope *envelopes = NULL; - 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) { @@ -165,7 +164,7 @@ int main(int argc, char *argv[]) { switch (state) { break; case Ready: { fprintf( - imap, "%s LOGIN \"%s\" \"%s\"\r\n", + imap.w, "%s LOGIN \"%s\" \"%s\"\r\n", Atoms[login], user, pass ); state = Login; @@ -173,14 +172,14 @@ int main(int argc, char *argv[]) { break; case Login: { if (resp.tag != login) break; - fprintf(imap, "%s EXAMINE \"%s\"\r\n", Atoms[examine], mailbox); + fprintf(imap.w, "%s EXAMINE \"%s\"\r\n", Atoms[examine], mailbox); state = Examine; } break; case Examine: { if (resp.tag == examine) { fprintf( - imap, "%s UID THREAD %s UTF-8 %s\r\n", + imap.w, "%s UID THREAD %s UTF-8 %s\r\n", Atoms[thread], algo, search ); state = Thread; @@ -206,7 +205,7 @@ int main(int argc, char *argv[]) { uidNext = dataCheck(value, Number).number; uint32_t prev = uidRead("UIDNEXT"); if (uidNext == prev) { - fprintf(imap, "ayy LOGOUT\r\n"); + fprintf(imap.w, "ayy LOGOUT\r\n"); state = Logout; } else { exitStatus = EXIT_SUCCESS; @@ -226,11 +225,11 @@ int main(int argc, char *argv[]) { envelopes = calloc(threads.len, sizeof(*envelopes)); if (!envelopes) err(EX_OSERR, "calloc"); - if (exportFetch(imap, export, threads)) { + if (exportFetch(imap.w, export, threads)) { exportTags = 1; state = Export; } else { - concatFetch(imap, concat, threads); + concatFetch(imap.w, concat, threads); state = Concat; } } @@ -239,10 +238,10 @@ int main(int argc, char *argv[]) { if (resp.resp == AtomFetch) { if (!resp.data.len) errx(EX_PROTOCOL, "missing FETCH data"); struct List items = dataCheck(resp.data.ptr[0], List).list; - if (exportData(imap, export, items)) exportTags++; + if (exportData(imap.w, export, items)) exportTags++; } if (resp.tag != export || --exportTags) break; - concatFetch(imap, concat, threads); + concatFetch(imap.w, concat, threads); state = Concat; } @@ -257,15 +256,15 @@ int main(int argc, char *argv[]) { concatThreads(threads, envelopes); concatIndex(threads, envelopes); uidWrite("UIDNEXT", uidNext); - fprintf(imap, "ayy LOGOUT\r\n"); + fprintf(imap.w, "ayy LOGOUT\r\n"); state = Logout; } break; case Logout:; } } - fclose(imapRead); - fclose(imap); + fclose(imap.r); + fclose(imap.w); return exitStatus; } diff --git a/imap.c b/imap.c index 748d51c..10864aa 100644 --- a/imap.c +++ b/imap.c @@ -33,6 +33,14 @@ #include #include +FILE *funopen( + const void *cookie, + int (*readfn)(void *, char *, int), + int (*writefn)(void *, const char *, int), + fpos_t (*seekfn)(void *, fpos_t, int), + int (*closefn)(void *) +); + #include "imap.h" const char *Atoms[AtomCap] = { @@ -73,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"); @@ -87,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); @@ -185,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; } @@ -205,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 0f034c0..b744bcc 100644 --- a/imap.h +++ b/imap.h @@ -168,7 +168,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 */ -- cgit 1.4.1