summary refs log tree commit diff
path: root/imap.h
blob: 0c9f6b9f2e50949687dfda1a0b151c7647db7b5c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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);