From 4d541ff929d0c320c382d6ebd6569c0c7faf8304 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Fri, 10 Apr 2020 14:20:35 -0400 Subject: Refactor main loop state machine --- archive.c | 166 ++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 92 insertions(+), 74 deletions(-) (limited to 'archive.c') diff --git a/archive.c b/archive.c index e741b4e..3b7d003 100644 --- a/archive.c +++ b/archive.c @@ -103,101 +103,119 @@ int main(int argc, char *argv[]) { if (!pass) errx(EX_CONFIG, ENV_PASSWORD " unset"); } - enum Atom login = 0; - enum Atom examine = atom("EXAMINE"); - enum Atom thread = atom("THREAD"); - enum Atom export = 0; - enum Atom concat = 0; + enum Atom AtomThread = atom("THREAD"); + + enum { + Ready, + Login, + Examine, + Thread, + Export, + Concat, + Logout, + } state = Ready; + + enum Atom login = atom("login"); + enum Atom examine = atom("examine"); + enum Atom thread = atom("thread"); + enum Atom export = atom("export"); + enum Atom concat = atom("concat"); uint32_t uidNext = 0; struct List threads = {0}; - FILE *imap = imapOpen(host, port); for (struct Resp resp; resp = imapResp(imap), resp.resp != AtomBye;) { if (resp.resp == AtomNo || resp.resp == AtomBad) { errx(EX_CONFIG, "%s %s", Atoms[resp.resp], resp.text); } - if (!login) { - login = atom("login"); - fprintf( - imap, "%s LOGIN \"%s\" \"%s\"\r\n", - Atoms[login], user, pass - ); - } + switch (state) { + break; case Ready: { + fprintf( + imap, "%s LOGIN \"%s\" \"%s\"\r\n", + Atoms[login], user, pass + ); + state = Login; + } - if (resp.tag == login) { - fprintf(imap, "%s EXAMINE \"%s\"\r\n", Atoms[examine], mailbox); - } + break; case Login: { + if (resp.tag != login) break; + fprintf(imap, "%s EXAMINE \"%s\"\r\n", Atoms[examine], mailbox); + state = Examine; + } - if ( - resp.resp == AtomOk && - resp.code.len > 1 && - resp.code.ptr[0].type == Atom - ) { - enum Atom code = resp.code.ptr[0].atom; - if (code == AtomUIDValidity || code == AtomUIDNext) { - if (resp.code.ptr[1].type != Number) { - errx(EX_PROTOCOL, "invalid %s", Atoms[code]); + break; case Examine: { + if (resp.resp == AtomOk && resp.code.len > 1) { + enum Atom code = dataCheck(resp.code.ptr[0], Atom).atom; + struct Data value = resp.code.ptr[1]; + if (code == AtomUIDValidity) { + uint32_t validity = dataCheck(value, Number).number; + uint32_t previous = uidRead("UIDVALIDITY"); + if (previous && validity != previous) { + errx( + EX_TEMPFAIL, + "UIDVALIDITY changed; fresh export required" + ); + } + if (!previous) uidWrite("UIDVALIDITY", validity); + } else if (code == AtomUIDNext) { + uidNext = dataCheck(value, Number).number; + uint32_t prev = uidRead("UIDNEXT"); + if (uidNext == prev) { + fprintf(imap, "ayy LOGOUT\r\n"); + state = Logout; + } + } } + + if (resp.tag != examine) break; + fprintf( + imap, "%s UID THREAD %s UTF-8 %s\r\n", + Atoms[thread], algo, search + ); + state = Thread; } - if (code == AtomUIDValidity) { - uint32_t validity = resp.code.ptr[1].number; - uint32_t previous = uidRead("UIDVALIDITY"); - if (previous && validity != previous) { - errx( - EX_TEMPFAIL, - "UIDVALIDITY changed; fresh export required" - ); + + break; case Thread: { + if (resp.resp != AtomThread) break; + if (!resp.data.len) { + errx(EX_TEMPFAIL, "no messages matching %s", search); } - if (!previous) uidWrite("UIDVALIDITY", validity); - } - if (code == AtomUIDNext) { - uidNext = resp.code.ptr[1].number; - uint32_t prev = uidRead("UIDNEXT"); - if (uidNext == prev) { - examine = 0; - fprintf(imap, "ayy LOGOUT\r\n"); + createDir("UID"); + createDir("message"); + threads = resp.data; + resp.data = (struct List) {0}; + if (exportFetch(imap, export, threads)) { + state = Export; + } else { + concatFetch(imap, concat, threads); + state = Concat; } } - } - if (resp.tag == examine) { - fprintf( - imap, "%s UID THREAD %s UTF-8 %s\r\n", - Atoms[thread], algo, search - ); - } - - if (resp.resp == thread) { - if (!resp.data.len) { - errx(EX_TEMPFAIL, "no messages matching %s", search); + break; case Export: { + if (resp.resp == AtomFetch) { + if (!resp.data.len) errx(EX_PROTOCOL, "missing FETCH data"); + exportData(dataCheck(resp.data.ptr[0], List).list); + } + if (resp.tag != export) break; + concatFetch(imap, concat, threads); + state = Concat; } - createDir("UID"); - createDir("message"); - threads = resp.data; - resp.data = (struct List) {0}; - export = exportFetch(imap, threads); - if (!export) concat = concatFetch(imap, threads); - } - if (export && resp.resp == AtomFetch) { - if (!resp.data.len || resp.data.ptr[0].type != List) { - errx(EX_PROTOCOL, "invalid FETCH data"); + break; case Concat: { + if (resp.resp == AtomFetch) { + if (!resp.data.len) errx(EX_PROTOCOL, "missing FETCH data"); + concatData(threads, dataCheck(resp.data.ptr[0], List).list); + } + if (resp.tag != concat) break; + uidWrite("UIDNEXT", uidNext); + fprintf(imap, "ayy LOGOUT\r\n"); + state = Logout; } - exportData(resp.data.ptr[0].list); + + break; case Logout:; } - - if (export && resp.tag == export) { - export = 0; - concat = concatFetch(imap, threads); - } - - if (concat && resp.tag == concat) { - uidWrite("UIDNEXT", uidNext); - fprintf(imap, "ayy LOGOUT\r\n"); - } - respFree(resp); } fclose(imap); -- cgit 1.4.1