diff options
author | June McEnroe <june@causal.agency> | 2020-05-04 17:46:58 -0400 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2020-05-04 17:48:18 -0400 |
commit | 75f6594d4e9287c83de171b7a41ed9f1eb045ae6 (patch) | |
tree | c4e3e3d2ae1e66fc5e80106c0419997393b7d8a2 | |
parent | Use a real IMAP parser (diff) | |
download | notemap-75f6594d4e9287c83de171b7a41ed9f1eb045ae6.tar.gz notemap-75f6594d4e9287c83de171b7a41ed9f1eb045ae6.zip |
Update IMAP parser
-rw-r--r-- | imap.c | 26 | ||||
-rw-r--r-- | imap.h | 93 | ||||
-rw-r--r-- | notemap.c | 18 |
3 files changed, 77 insertions, 60 deletions
diff --git a/imap.c b/imap.c index 6894319..7984e0e 100644 --- a/imap.c +++ b/imap.c @@ -60,10 +60,11 @@ static int imapClose(void *_tls) { struct tls *tls = _tls; int error = tls_close(tls); if (error) errx(EX_IOERR, "tls_close: %s", tls_error(tls)); + tls_free(tls); return error; } -FILE *imapOpen(const char *host, const char *port) { +void imapOpen(FILE **read, FILE **write, const char *host, const char *port) { struct tls *client = tls_client(); if (!client) errx(EX_SOFTWARE, "tls_client"); @@ -77,11 +78,11 @@ FILE *imapOpen(const char *host, const char *port) { error = tls_connect(client, host, port); if (error) errx(EX_NOHOST, "tls_connect: %s", tls_error(client)); - FILE *imap = funopen(client, imapRead, imapWrite, NULL, imapClose); - if (!imap) err(EX_SOFTWARE, "funopen"); + *read = funopen(client, imapRead, NULL, NULL, NULL); + *write = funopen(client, NULL, imapWrite, NULL, imapClose); + if (!*read || !*write) err(EX_SOFTWARE, "funopen"); - setlinebuf(imap); - return imap; + setlinebuf(*write); } static size_t cap; @@ -98,7 +99,7 @@ static void imapLine(FILE *imap) { } static struct Data parseAtom(void) { - size_t len = strcspn(ptr, " ()[]{\""); + size_t len = (*ptr == '.' ? 1 : strcspn(ptr, " .()[]{\"")); struct Data data = { .type = Atom, .atom = atomn(ptr, len), @@ -149,18 +150,7 @@ static struct Data parseList(FILE *imap, char close) { if (*ptr) ptr++; struct Data data = { .type = List }; while (*ptr != close) { - if (data.list.len == data.list.cap) { - if (data.list.cap) { - data.list.cap *= 2; - } else { - data.list.cap = 4; - } - data.list.ptr = realloc( - data.list.ptr, sizeof(*data.list.ptr) * data.list.cap - ); - if (!data.list.ptr) err(EX_OSERR, "realloc"); - } - data.list.ptr[data.list.len++] = parseData(imap); + listPush(&data.list, parseData(imap)); } if (*ptr) ptr++; return data; diff --git a/imap.h b/imap.h index 04cf5a0..8b6b717 100644 --- a/imap.h +++ b/imap.h @@ -14,6 +14,9 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#ifndef IMAP_H +#define IMAP_H + #include <err.h> #include <stdbool.h> #include <stdint.h> @@ -24,33 +27,16 @@ #define ENUM_ATOM \ X(AtomNil, "NIL") \ + X(AtomUntagged, "*") \ + X(AtomContinue, "+") \ X(AtomOk, "OK") \ X(AtomNo, "NO") \ X(AtomBad, "BAD") \ X(AtomPreauth, "PREAUTH") \ X(AtomBye, "BYE") \ - X(AtomAlert, "ALERT") \ - X(AtomBadCharset, "BADCHARSET") \ - X(AtomCapability, "CAPABILITY") \ - X(AtomParse, "PARSE") \ - X(AtomPermanentFlags, "PERMANENTFLAGS") \ - X(AtomReadOnly, "READ-ONLY") \ - X(AtomReadWrite, "READ-WRITE") \ - X(AtomTryCreate, "TRYCREATE") \ - X(AtomUIDNext, "UIDNEXT") \ - X(AtomUIDValidity, "UIDVALIDITY") \ - X(AtomUnseen, "UNSEEN") \ - X(AtomList, "LIST") \ - X(AtomLSub, "LSUB") \ - X(AtomStatus, "STATUS") \ X(AtomSearch, "SEARCH") \ - X(AtomFlags, "FLAGS") \ - X(AtomExists, "EXISTS") \ - X(AtomRecent, "RECENT") \ - X(AtomExpunge, "EXPUNGE") \ X(AtomFetch, "FETCH") \ - X(AtomUntagged, "*") \ - X(AtomContinue, "+") + X(AtomEnvelope, "ENVELOPE") enum Atom { #define X(id, str) id, @@ -97,16 +83,57 @@ struct Data { }; }; -static inline void dataFree(struct Data data) { - if (data.type == String) free(data.string); - if (data.type == List) { - for (size_t i = 0; i < data.list.len; ++i) { - dataFree(data.list.ptr[i]); +static inline struct Data dataCheck(struct Data data, enum Type type) { + const char *Types[] = { "atom", "number", "string", "list" }; + if (data.type != type) { + errx( + EX_PROTOCOL, "expected %s, found %s", + Types[type], Types[data.type] + ); + } + return data; +} + +static inline struct Data dataTake(struct Data *from) { + struct Data take = *from; + from->type = Atom; + from->atom = AtomNil; + return take; +} + +static inline void listPush(struct List *list, struct Data data) { + if (list->len == list->cap) { + list->cap = (list->cap ? list->cap * 2 : 4); + list->ptr = realloc(list->ptr, sizeof(*list->ptr) * list->cap); + if (!list->ptr) err(EX_OSERR, "realloc"); + } + list->ptr[list->len++] = data; +} + +static inline void listFlatten(struct List *flat, struct List nested) { + for (size_t i = 0; i < nested.len; ++i) { + if (nested.ptr[i].type == List) { + listFlatten(flat, nested.ptr[i].list); + } else { + listPush(flat, nested.ptr[i]); } - free(data.list.ptr); } } +static inline void dataFree(struct Data data); + +static inline void listFree(struct List list) { + for (size_t i = 0; i < list.len; ++i) { + dataFree(list.ptr[i]); + } + free(list.ptr); +} + +static inline void dataFree(struct Data data) { + if (data.type == String) free(data.string); + if (data.type == List) listFree(data.list); +} + struct Resp { enum Atom tag; uint32_t number; @@ -117,14 +144,12 @@ struct Resp { }; static inline void respFree(struct Resp resp) { - for (size_t i = 0; i < resp.code.len; ++i) { - dataFree(resp.code.ptr[i]); - } - for (size_t i = 0; i < resp.data.len; ++i) { - dataFree(resp.data.ptr[i]); - } + listFree(resp.code); + listFree(resp.data); } extern bool imapVerbose; -FILE *imapOpen(const char *host, const char *port); -struct Resp imapResp(FILE *imap); +void imapOpen(FILE **read, FILE **write, const char *host, const char *port); +struct Resp imapResp(FILE *imapRead); + +#endif /* IMAP_H */ diff --git a/notemap.c b/notemap.c index dfe9872..99a1418 100644 --- a/notemap.c +++ b/notemap.c @@ -283,9 +283,14 @@ int main(int argc, char *argv[]) { enum Atom next = atom("next"); enum Atom create = atom("create"); enum Atom replace = atom("replace"); - enum Atom envelope = atom("ENVELOPE"); - FILE *imap = imapOpen(host, port); - for (struct Resp resp; resp = imapResp(imap), resp.resp != AtomBye;) { + + FILE *imapRead, *imap; + imapOpen(&imapRead, &imap, host, port); + for ( + struct Resp resp; + resp = imapResp(imapRead), resp.resp != AtomBye; + respFree(resp) + ) { if (resp.resp == AtomNo || resp.resp == AtomBad) { errx(EX_CONFIG, "%s: %s", Atoms[resp.resp], resp.text); } @@ -335,8 +340,6 @@ next: "%s SEARCH HEADER X-Universally-Unique-Identifier \"%s\"\r\n", Atoms[AtomSearch], uuid ); - - respFree(resp); continue; } @@ -368,7 +371,7 @@ next: resp.data.ptr[0].type == List && resp.data.ptr[0].list.len > 1 && resp.data.ptr[0].list.ptr[0].type == Atom && - resp.data.ptr[0].list.ptr[0].atom == envelope && + resp.data.ptr[0].list.ptr[0].atom == AtomEnvelope && resp.data.ptr[0].list.ptr[1].type == List ) { struct List envelope = resp.data.ptr[0].list.ptr[1].list; @@ -414,9 +417,8 @@ next: Atoms[next], seq ); } - - respFree(resp); } + fclose(imapRead); fclose(imap); int ret = EX_OK; |