summary refs log tree commit diff
path: root/imap.h
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-04-08 16:49:50 -0400
committerJune McEnroe <june@causal.agency>2020-04-08 16:49:50 -0400
commitdca3eb7a6a0c7e8a71d26c4390d908f5f6c2f32f (patch)
treedd82c828c185820ac7c39fc6db8681e1b5bbe649 /imap.h
parentSimplify mboxrd output (diff)
downloadimbox-dca3eb7a6a0c7e8a71d26c4390d908f5f6c2f32f.tar.gz
imbox-dca3eb7a6a0c7e8a71d26c4390d908f5f6c2f32f.zip
Use a real IMAP parser
Diffstat (limited to 'imap.h')
-rw-r--r--imap.h129
1 files changed, 129 insertions, 0 deletions
diff --git a/imap.h b/imap.h
new file mode 100644
index 0000000..0c9f6b9
--- /dev/null
+++ b/imap.h
@@ -0,0 +1,129 @@
+/* Copyright (C) 2020  C. McEnroe <june@causal.agency>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <err.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#define ENUM_ATOM \
+	X(AtomNil, "NIL") \
+	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, "*")
+
+enum Atom {
+#define X(id, str) id,
+	ENUM_ATOM
+#undef X
+	AtomCap = 1024,
+};
+
+extern const char *Atoms[AtomCap];
+
+static inline enum Atom atomn(const char *str, size_t len) {
+	enum Atom i;
+	for (i = 0; i < AtomCap; ++i) {
+		if (!Atoms[i]) break;
+		if (strlen(Atoms[i]) != len) continue;
+		if (!strncasecmp(Atoms[i], str, len)) return i;
+	}
+	if (i == AtomCap) errx(EX_SOFTWARE, "atom capacity exceeded");
+	Atoms[i] = strndup(str, len);
+	if (!Atoms[i]) err(EX_OSERR, "strndup");
+	return i;
+}
+
+static inline enum Atom atom(const char *str) {
+	return atomn(str, strlen(str));
+}
+
+struct Data {
+	enum Type {
+		Atom,
+		Number,
+		String,
+		List,
+	} type;
+	union {
+		enum Atom atom;
+		uint32_t number;
+		char *string;
+		struct List {
+			size_t cap;
+			size_t len;
+			struct Data *ptr;
+		} list;
+	};
+};
+
+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]);
+		}
+		free(data.list.ptr);
+	}
+}
+
+struct Resp {
+	enum Atom tag;
+	uint32_t number;
+	enum Atom resp;
+	struct List code;
+	struct List data;
+	const char *text;
+};
+
+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]);
+	}
+}
+
+extern bool imapVerbose;
+FILE *imapOpen(const char *host, const char *port);
+struct Resp imapResp(FILE *imap);