1 #ifndef IMAPC_CLIENT_H
2 #define IMAPC_CLIENT_H
3 
4 #include "net.h"
5 #include "iostream-ssl.h"
6 
7 /* IMAP RFC defines this to be at least 30 minutes. */
8 #define IMAPC_DEFAULT_MAX_IDLE_TIME (60*29)
9 
10 enum imapc_command_state {
11 	IMAPC_COMMAND_STATE_OK = 0,
12 	IMAPC_COMMAND_STATE_NO,
13 	IMAPC_COMMAND_STATE_BAD,
14 	/* Authentication to IMAP server failed (NO or BAD) */
15 	IMAPC_COMMAND_STATE_AUTH_FAILED,
16 	/* Client was unexpectedly disconnected. */
17 	IMAPC_COMMAND_STATE_DISCONNECTED
18 };
19 extern const char *imapc_command_state_names[];
20 
21 enum imapc_capability {
22 	IMAPC_CAPABILITY_SASL_IR	= 0x01,
23 	IMAPC_CAPABILITY_LITERALPLUS	= 0x02,
24 	IMAPC_CAPABILITY_QRESYNC	= 0x04,
25 	IMAPC_CAPABILITY_IDLE		= 0x08,
26 	IMAPC_CAPABILITY_UIDPLUS	= 0x10,
27 	IMAPC_CAPABILITY_AUTH_PLAIN	= 0x20,
28 	IMAPC_CAPABILITY_STARTTLS	= 0x40,
29 	IMAPC_CAPABILITY_X_GM_EXT_1	= 0x80,
30 	IMAPC_CAPABILITY_CONDSTORE	= 0x100,
31 	IMAPC_CAPABILITY_NAMESPACE	= 0x200,
32 	IMAPC_CAPABILITY_UNSELECT	= 0x400,
33 	IMAPC_CAPABILITY_ESEARCH	= 0x800,
34 	IMAPC_CAPABILITY_WITHIN		= 0x1000,
35 	IMAPC_CAPABILITY_QUOTA		= 0x2000,
36 	IMAPC_CAPABILITY_ID		= 0x4000,
37 	IMAPC_CAPABILITY_SAVEDATE	= 0x8000,
38 
39 	IMAPC_CAPABILITY_IMAP4REV1	= 0x40000000
40 };
41 struct imapc_capability_name {
42 	const char *name;
43 	enum imapc_capability capability;
44 };
45 extern const struct imapc_capability_name imapc_capability_names[];
46 
47 enum imapc_command_flags {
48 	/* The command changes the selected mailbox (SELECT, EXAMINE) */
49 	IMAPC_COMMAND_FLAG_SELECT	= 0x01,
50 	/* The command is sent to server before login (or is the login
51 	   command itself). Non-prelogin commands will be queued until login
52 	   is successful. */
53 	IMAPC_COMMAND_FLAG_PRELOGIN	= 0x02,
54 	/* Allow command to be automatically retried if disconnected before it
55 	   finishes. */
56 	IMAPC_COMMAND_FLAG_RETRIABLE	= 0x04,
57 	/* This is the LOGOUT command. Use a small timeout for it. */
58 	IMAPC_COMMAND_FLAG_LOGOUT	= 0x08,
59 	/* Command is being resent after a reconnection. */
60 	IMAPC_COMMAND_FLAG_RECONNECTED	= 0x10
61 };
62 
63 enum imapc_client_ssl_mode {
64 	IMAPC_CLIENT_SSL_MODE_NONE,
65 	IMAPC_CLIENT_SSL_MODE_IMMEDIATE,
66 	IMAPC_CLIENT_SSL_MODE_STARTTLS
67 };
68 
69 #define IMAPC_DEFAULT_CONNECT_TIMEOUT_MSECS (1000*30)
70 #define IMAPC_DEFAULT_COMMAND_TIMEOUT_MSECS (1000*60*5)
71 #define IMAPC_DEFAULT_MAX_LINE_LENGTH (SIZE_MAX)
72 
73 struct imapc_throttling_settings {
74 	unsigned int init_msecs;
75 	unsigned int max_msecs;
76 	unsigned int shrink_min_msecs;
77 };
78 
79 struct imapc_client_settings {
80 	const char *host;
81 	in_port_t port;
82 
83 	const char *master_user;
84 	const char *username;
85 	const char *password;
86 	/* Space-separated list of SASL mechanisms to try (in the specified
87 	   order). The default is to use only LOGIN command or SASL PLAIN. */
88 	const char *sasl_mechanisms;
89 	bool use_proxyauth; /* Use Sun/Oracle PROXYAUTH command */
90 	unsigned int max_idle_time;
91 	/* If ID capability is advertised, send a unique "x-session-ext-id",
92 	   which begins with this prefix. */
93 	const char *session_id_prefix;
94 
95 	const char *dns_client_socket_path;
96 	const char *temp_path_prefix;
97 	struct ssl_iostream_settings ssl_set;
98 
99 	enum imapc_client_ssl_mode ssl_mode;
100 
101 	const char *rawlog_dir;
102 	bool debug;
103 
104 	/* Timeout for logging in. 0 = default. */
105 	unsigned int connect_timeout_msecs;
106 	/* Number of retries, -1 = infinity */
107 	unsigned int connect_retry_count;
108 	/* Interval between retries, must be > 0 if retries > 0 */
109 	unsigned int connect_retry_interval_msecs;
110 
111 	/* Timeout for IMAP commands. Reset every time more data is being
112 	   sent or received. 0 = default. */
113 	unsigned int cmd_timeout_msecs;
114 
115 	/* Maximum allowed line length (not including literals read as
116 	   streams). 0 = unlimited. */
117 	size_t max_line_length;
118 
119 	struct imapc_throttling_settings throttle_set;
120 };
121 
122 struct imapc_command_reply {
123 	enum imapc_command_state state;
124 	/* "[RESP TEXT]" produces key=RESP, value=TEXT.
125 	   "[RESP]" produces key=RESP, value=NULL
126 	   otherwise both are NULL */
127 	const char *resp_text_key, *resp_text_value;
128 	/* The full tagged reply, including [RESP TEXT]. */
129 	const char *text_full;
130 	/* Tagged reply text without [RESP TEXT] */
131 	const char *text_without_resp;
132 };
133 
134 struct imapc_arg_file {
135 	/* file descriptor containing the value */
136 	int fd;
137 
138 	/* parent_arg.list[list_idx] points to the IMAP_ARG_LITERAL_SIZE
139 	   argument */
140 	const struct imap_arg *parent_arg;
141 	unsigned int list_idx;
142 };
143 
144 struct imapc_untagged_reply {
145 	/* name of the untagged reply, e.g. EXISTS */
146 	const char *name;
147 	/* number at the beginning of the reply, or 0 if there wasn't any.
148 	   Set for EXISTS, EXPUNGE, etc. */
149 	uint32_t num;
150 	/* the rest of the reply can be read from these args. */
151 	const struct imap_arg *args;
152 	/* arguments whose contents are stored into files. only
153 	   "FETCH (BODY[" arguments can be here. */
154 	const struct imapc_arg_file *file_args;
155 	unsigned int file_args_count;
156 
157 	/* "* OK [RESP TEXT]" produces key=RESP, value=TEXT.
158 	   "* OK [RESP]" produces key=RESP, value=NULL
159 	   otherwise both are NULL */
160 	const char *resp_text_key, *resp_text_value;
161 
162 	/* If this reply occurred while a mailbox was selected, this contains
163 	   the mailbox's untagged_context. */
164 	void *untagged_box_context;
165 };
166 
167 enum imapc_state_change_event {
168 	IMAPC_STATE_CHANGE_AUTH_OK,
169 	IMAPC_STATE_CHANGE_AUTH_FAILED,
170 };
171 
172 /* Called when tagged reply is received for command. */
173 typedef void imapc_command_callback_t(const struct imapc_command_reply *reply,
174 				      void *context);
175 /* Called each time untagged input is received. */
176 typedef void imapc_untagged_callback_t(const struct imapc_untagged_reply *reply,
177 				       void *context);
178 typedef void imapc_state_change_callback_t(void *context,
179 					   enum imapc_state_change_event event,
180 					   const char *error);
181 
182 struct imapc_client *
183 imapc_client_init(const struct imapc_client_settings *set,
184 		  struct event *event_parent);
185 void imapc_client_disconnect(struct imapc_client *client);
186 void imapc_client_deinit(struct imapc_client **client);
187 
188 /* Set login callback, must be set before calling other commands.
189    This is called only for the first login, not for any reconnects or if there
190    are multiple connections created. */
191 void
192 imapc_client_set_login_callback(struct imapc_client *client,
193 				imapc_command_callback_t *callback, void *context);
194 /* Explicitly login to server (also done automatically). */
195 void imapc_client_login(struct imapc_client *client);
196 /* Send a LOGOUT and wait for disconnection. */
197 void imapc_client_logout(struct imapc_client *client);
198 
199 struct imapc_command *
200 imapc_client_cmd(struct imapc_client *client,
201 		 imapc_command_callback_t *callback, void *context);
202 void imapc_command_set_flags(struct imapc_command *cmd,
203 			     enum imapc_command_flags flags);
204 bool imapc_command_connection_is_selected(struct imapc_command *cmd);
205 void imapc_command_send(struct imapc_command *cmd, const char *cmd_str);
206 void imapc_command_sendf(struct imapc_command *cmd, const char *cmd_fmt, ...)
207 	ATTR_FORMAT(2, 3);
208 void imapc_command_sendvf(struct imapc_command *cmd,
209 			  const char *cmd_fmt, va_list args) ATTR_FORMAT(2, 0);
210 const char *imapc_command_get_tag(struct imapc_command *cmd);
211 void imapc_command_abort(struct imapc_command **cmd);
212 
213 void imapc_client_register_untagged(struct imapc_client *client,
214 				    imapc_untagged_callback_t *callback,
215 				    void *context);
216 
217 void imapc_client_run(struct imapc_client *client);
218 void imapc_client_stop(struct imapc_client *client);
219 bool imapc_client_is_running(struct imapc_client *client);
220 
221 struct imapc_client_mailbox *
222 imapc_client_mailbox_open(struct imapc_client *client,
223 			  void *untagged_box_context);
224 void imapc_client_mailbox_set_reopen_cb(struct imapc_client_mailbox *box,
225 					void (*callback)(void *context),
226 					void *context);
227 void imapc_client_mailbox_close(struct imapc_client_mailbox **box);
228 bool imapc_client_mailbox_can_reconnect(struct imapc_client_mailbox *box);
229 void imapc_client_mailbox_reconnect(struct imapc_client_mailbox *box,
230 				    const char *errmsg);
231 struct imapc_command *
232 imapc_client_mailbox_cmd(struct imapc_client_mailbox *box,
233 			 imapc_command_callback_t *callback, void *context);
234 struct imapc_msgmap *
235 imapc_client_mailbox_get_msgmap(struct imapc_client_mailbox *box);
236 
237 void imapc_client_mailbox_idle(struct imapc_client_mailbox *box);
238 bool imapc_client_mailbox_is_opened(struct imapc_client_mailbox *box);
239 
240 int imapc_client_get_capabilities(struct imapc_client *client,
241 				  enum imapc_capability *capabilities_r);
242 
243 int imapc_client_create_temp_fd(struct imapc_client *client,
244 				const char **path_r);
245 
246 void imapc_client_register_state_change_callback(struct imapc_client *client,
247 						 imapc_state_change_callback_t *cb,
248 						 void *context);
249 
250 #endif
251