summary refs log tree commit diff
path: root/imap.h
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-05-01 17:15:22 -0400
committerJune McEnroe <june@causal.agency>2020-05-01 17:20:45 -0400
commiteeed8059e2eca4e078f2b95ae6650963b3edfd2e (patch)
tree3cc786d51b298e181bea4220fa3ab5e47db74d4b /imap.h
parentRemove unused includes (diff)
downloadimbox-eeed8059e2eca4e078f2b95ae6650963b3edfd2e.tar.gz
imbox-eeed8059e2eca4e078f2b95ae6650963b3edfd2e.zip
Update IMAP parser
Diffstat (limited to 'imap.h')
-rw-r--r--imap.h95
1 files changed, 62 insertions, 33 deletions
diff --git a/imap.h b/imap.h
index 0c9f6b9..7896b97 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,32 +27,19 @@
 
 #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(AtomBody, "BODY") \
+	X(AtomDot, ".") \
+	X(AtomHeader, "HEADER") \
+	X(AtomText, "TEXT")
 
 enum Atom {
 #define X(id, str) id,
@@ -96,16 +86,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;
@@ -116,14 +147,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 */