1 #ifndef IMAP_CLIENT_H
2 #define IMAP_CLIENT_H
3 
4 #include "imap-commands.h"
5 #include "message-size.h"
6 
7 #define CLIENT_COMMAND_QUEUE_MAX_SIZE 4
8 /* Maximum number of CONTEXT=SEARCH UPDATEs. Clients probably won't need more
9    than a few, so this is mainly to avoid more or less accidental pointless
10    resource usage. */
11 #define CLIENT_MAX_SEARCH_UPDATES 10
12 
13 struct client;
14 struct mail_storage;
15 struct mail_storage_service_ctx;
16 struct lda_settings;
17 struct imap_parser;
18 struct imap_arg;
19 struct imap_urlauth_context;
20 
21 struct mailbox_keywords {
22 	/* All keyword names. The array itself exists in mail_index.
23 	   Keywords are currently only appended, they're never removed. */
24 	const ARRAY_TYPE(keywords) *names;
25 	/* Number of keywords announced to client via FLAGS/PERMANENTFLAGS.
26 	   This relies on keywords not being removed while mailbox is
27 	   selected. */
28 	unsigned int announce_count;
29 };
30 
31 struct imap_search_update {
32 	char *tag;
33 	struct mail_search_result *result;
34 	bool return_uids;
35 
36 	pool_t fetch_pool;
37 	struct imap_fetch_context *fetch_ctx;
38 };
39 
40 enum client_command_state {
41 	/* Waiting for more input */
42 	CLIENT_COMMAND_STATE_WAIT_INPUT,
43 	/* Waiting to be able to send more output */
44 	CLIENT_COMMAND_STATE_WAIT_OUTPUT,
45 	/* Waiting for external interaction */
46 	CLIENT_COMMAND_STATE_WAIT_EXTERNAL,
47 	/* Wait for other commands to finish execution */
48 	CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY,
49 	/* Waiting for other commands to finish so we can sync */
50 	CLIENT_COMMAND_STATE_WAIT_SYNC,
51 	/* Command is finished */
52 	CLIENT_COMMAND_STATE_DONE
53 };
54 
55 struct client_command_stats {
56 	/* time when command handling was started - typically this is after
57 	   reading all the parameters. */
58 	struct timeval start_time;
59 	/* time when command handling was last finished. this is before
60 	   mailbox syncing is done. */
61 	struct timeval last_run_timeval;
62 	/* io_loop_get_wait_usecs()'s value when the command was started */
63 	uint64_t start_ioloop_wait_usecs;
64 	/* how many usecs this command itself has spent running */
65 	uint64_t running_usecs;
66 	/* how many usecs this command itself has spent waiting for locks */
67 	uint64_t lock_wait_usecs;
68 	/* how many bytes of client input/output command has used */
69 	uint64_t bytes_in, bytes_out;
70 };
71 
72 struct client_command_stats_start {
73 	struct timeval timeval;
74 	uint64_t lock_wait_usecs;
75 	uint64_t bytes_in, bytes_out;
76 };
77 
78 struct client_command_context {
79 	struct client_command_context *prev, *next;
80 	struct client *client;
81 	struct event *event;
82 
83 	pool_t pool;
84 	/* IMAP command tag */
85 	const char *tag;
86 	/* Name of this command */
87 	const char *name;
88 	/* Parameters for this command. These are generated from parsed IMAP
89 	   arguments, so they may not be exactly the same as how client sent
90 	   them. */
91 	const char *args;
92 	/* Parameters for this command generated with
93 	   imap_write_args_for_human(), so it's suitable for logging. */
94 	const char *human_args;
95 	enum command_flags cmd_flags;
96 	const char *tagline_reply;
97 
98 	command_func_t *func;
99 	void *context;
100 
101 	/* Module-specific contexts. */
102 	ARRAY(union imap_module_context *) module_contexts;
103 
104 	struct imap_parser *parser;
105 	enum client_command_state state;
106 	struct client_command_stats stats;
107 	struct client_command_stats_start stats_start;
108 
109 	struct imap_client_sync_context *sync;
110 
111 	bool uid:1; /* used UID command */
112 	bool cancel:1; /* command is wanted to be cancelled */
113 	bool param_error:1;
114 	bool search_save_result:1; /* search result is being updated */
115 	bool search_save_result_used:1; /* command uses search save */
116 	bool temp_executed:1; /* temporary execution state tracking */
117 	bool tagline_sent:1;
118 	bool executing:1;
119 };
120 
121 struct imap_client_vfuncs {
122 	/* Perform client initialization. This is called when client creation is
123 	   finished completely. Particulary, at this point the namespaces are
124 	   fully initialized, which is not the case for the client create hook.
125 	 */
126 	void (*init)(struct client *client);
127 	/* Destroy the client.*/
128 	void (*destroy)(struct client *client, const char *reason);
129 
130 	/* Send a tagged response line. */
131 	void (*send_tagline)(struct client_command_context *cmd,
132 			     const char *data);
133 	/* Run "mailbox syncing". This can send any unsolicited untagged
134 	   replies. Returns 1 = done, 0 = wait for more space in output buffer,
135 	   -1 = failed. */
136 	int (*sync_notify_more)(struct imap_sync_context *ctx);
137 
138 	/* Export client state into buffer. Returns 1 if ok, 0 if some state
139 	   couldn't be preserved, -1 if temporary internal error occurred. */
140 	int (*state_export)(struct client *client, bool internal,
141 			    buffer_t *dest, const char **error_r);
142 	/* Import a single block of client state from the given data. Returns
143 	   number of bytes successfully imported from the block, or 0 if state
144 	   is corrupted or contains unknown data (e.g. some plugin is no longer
145 	   loaded), -1 if temporary internal error occurred. */
146 	ssize_t (*state_import)(struct client *client, bool internal,
147 				const unsigned char *data, size_t size,
148 				const char **error_r);
149 };
150 
151 struct client {
152 	struct client *prev, *next;
153 
154 	struct imap_client_vfuncs v;
155 	struct event *event;
156 	const char *const *userdb_fields; /* for internal session saving/restoring */
157 
158 	int fd_in, fd_out;
159 	struct io *io;
160 	struct istream *input;
161 	struct ostream *output;
162 	struct timeout *to_idle, *to_idle_output, *to_delayed_input;
163 
164 	pool_t pool;
165 	struct mail_storage_service_user *service_user;
166 	const struct imap_settings *set;
167 	const struct smtp_submit_settings *smtp_set;
168 	string_t *capability_string;
169 	const char *disconnect_reason;
170 
171         struct mail_user *user;
172 	struct mailbox *mailbox;
173         struct mailbox_keywords keywords;
174 	unsigned int sync_counter;
175 	uint32_t messages_count, recent_count, uidvalidity;
176 	ARRAY(bool) enabled_features;
177 
178 	time_t last_input, last_output;
179 	unsigned int bad_counter;
180 
181 	/* one parser is kept here to be used for new commands */
182 	struct imap_parser *free_parser;
183 	/* command_pool is cleared when the command queue gets empty */
184 	pool_t command_pool;
185 	/* New commands are always prepended to the queue */
186 	struct client_command_context *command_queue;
187 	unsigned int command_queue_size;
188 
189 	char *last_cmd_name;
190 	struct client_command_stats last_cmd_stats;
191 
192 	uint64_t sync_last_full_modseq;
193 	uint64_t highest_fetch_modseq;
194 	ARRAY_TYPE(seq_range) fetch_failed_uids;
195 
196 	/* For imap_logout_format statistics: */
197 	unsigned int fetch_hdr_count, fetch_body_count;
198 	uint64_t fetch_hdr_bytes, fetch_body_bytes;
199 	unsigned int deleted_count, expunged_count, trashed_count;
200 	unsigned int autoexpunged_count, append_count;
201 
202 	/* SEARCHRES extension: Last saved SEARCH result */
203 	ARRAY_TYPE(seq_range) search_saved_uidset;
204 	/* SEARCH=CONTEXT extension: Searches that get updated */
205 	ARRAY(struct imap_search_update) search_updates;
206 	/* NOTIFY extension */
207 	struct imap_notify_context *notify_ctx;
208 	uint32_t notify_uidnext;
209 
210 	/* client input/output is locked by this command */
211 	struct client_command_context *input_lock;
212 	struct client_command_context *output_cmd_lock;
213 	/* command changing the mailbox */
214 	struct client_command_context *mailbox_change_lock;
215 
216 	/* IMAP URLAUTH context (RFC4467) */
217 	struct imap_urlauth_context *urlauth_ctx;
218 
219 	/* Module-specific contexts. */
220 	ARRAY(union imap_module_context *) module_contexts;
221 
222 	/* syncing marks this TRUE when it sees \Deleted flags. this is by
223 	   EXPUNGE for Outlook-workaround. */
224 	bool sync_seen_deletes:1;
225 	bool logged_out:1;
226 	bool disconnected:1;
227 	bool hibernated:1;
228 	bool destroyed:1;
229 	bool handling_input:1;
230 	bool syncing:1;
231 	bool id_logged:1;
232 	bool mailbox_examined:1;
233 	bool anvil_sent:1;
234 	bool tls_compression:1;
235 	bool input_skip_line:1; /* skip all the data until we've
236 					   found a new line */
237 	bool modseqs_sent_since_sync:1;
238 	bool notify_immediate_expunges:1;
239 	bool notify_count_changes:1;
240 	bool notify_flag_changes:1;
241 	bool nonpermanent_modseqs:1;
242 	bool state_import_bad_idle_done:1;
243 	bool state_import_idle_continue:1;
244 };
245 
246 struct imap_module_register {
247 	unsigned int id;
248 };
249 
250 union imap_module_context {
251 	struct imap_client_vfuncs super;
252 	struct imap_module_register *reg;
253 };
254 extern struct imap_module_register imap_module_register;
255 
256 extern struct client *imap_clients;
257 extern unsigned int imap_client_count;
258 
259 extern unsigned int imap_feature_condstore;
260 extern unsigned int imap_feature_qresync;
261 
262 /* Create new client with specified input/output handles. socket specifies
263    if the handle is a socket. */
264 struct client *client_create(int fd_in, int fd_out,
265 			     struct event *event, struct mail_user *user,
266 			     struct mail_storage_service_user *service_user,
267 			     const struct imap_settings *set,
268 			     const struct smtp_submit_settings *smtp_set);
269 void client_create_finish_io(struct client *client);
270 /* Finish creating the client. Returns 0 if ok, -1 if there's an error. */
271 int client_create_finish(struct client *client, const char **error_r);
272 void client_add_istream_prefix(struct client *client,
273 			       const unsigned char *data, size_t size);
274 void client_destroy(struct client *client, const char *reason) ATTR_NULL(2);
275 
276 /* Disconnect client connection */
277 void client_disconnect(struct client *client, const char *reason);
278 void client_disconnect_with_error(struct client *client,
279 				  const char *client_error);
280 
281 /* Add the given capability to the CAPABILITY reply. If imap_capability setting
282    has an explicit capability, nothing is changed. */
283 void client_add_capability(struct client *client, const char *capability);
284 
285 /* Send a line of data to client. */
286 void client_send_line(struct client *client, const char *data);
287 /* Send a line of data to client. Returns 1 if ok, 0 if buffer is getting full,
288    -1 if error. This should be used when you're (potentially) sending a lot of
289    lines to client. */
290 int client_send_line_next(struct client *client, const char *data);
291 /* Send line of data to client, prefixed with client->tag. You need to prefix
292    the data with "OK ", "NO " or "BAD ". */
293 void client_send_tagline(struct client_command_context *cmd, const char *data);
294 
295 /* Send a BAD command reply to client via client_send_tagline(). If there have
296    been too many command errors, the client is disconnected. client_error may
297    be NULL, in which case the error is looked up from imap_parser. */
298 void client_send_command_error(struct client_command_context *cmd,
299 			       const char *client_error);
300 
301 /* Send a NO command reply with the default internal error message to client
302    via client_send_tagline(). */
303 void client_send_internal_error(struct client_command_context *cmd);
304 
305 /* Read a number of arguments. Returns TRUE if everything was read or
306    FALSE if either needs more data or error occurred. */
307 bool client_read_args(struct client_command_context *cmd, unsigned int count,
308 		      unsigned int flags, const struct imap_arg **args_r);
309 /* Reads a number of string arguments. ... is a list of pointers where to
310    store the arguments. */
311 bool client_read_string_args(struct client_command_context *cmd,
312 			     unsigned int count, ...);
313 void client_args_finished(struct client_command_context *cmd,
314 			  const struct imap_arg *args);
315 
316 /* SEARCHRES extension: Call if $ is being used/updated, returns TRUE if we
317    have to wait for an existing SEARCH SAVE to finish. */
318 bool client_handle_search_save_ambiguity(struct client_command_context *cmd);
319 
320 void client_enable(struct client *client, unsigned int feature_idx);
321 /* Returns TRUE if the given feature is enabled */
322 bool client_has_enabled(struct client *client, unsigned int feature_idx);
323 /* Returns mailbox features that are currently enabled. */
324 enum mailbox_feature client_enabled_mailbox_features(struct client *client);
325 /* Returns all enabled features as strings. */
326 const char *const *client_enabled_features(struct client *client);
327 
328 /* Send client processing to imap-idle process. If successful, returns TRUE
329    and destroys the client. If hibernation failed, the exact reason is
330    returned (mainly for unit tests). */
331 bool imap_client_hibernate(struct client **client, const char **reason_r);
332 
333 struct imap_search_update *
334 client_search_update_lookup(struct client *client, const char *tag,
335 			    unsigned int *idx_r);
336 void client_search_updates_free(struct client *client);
337 
338 struct client_command_context *client_command_alloc(struct client *client);
339 void client_command_init_finished(struct client_command_context *cmd);
340 void client_command_cancel(struct client_command_context **cmd);
341 void client_command_free(struct client_command_context **cmd);
342 
343 bool client_handle_unfinished_cmd(struct client_command_context *cmd);
344 /* Handle any pending command input. This must be run at the end of all
345    I/O callbacks after they've (potentially) finished some commands. */
346 void client_continue_pending_input(struct client *client);
347 void client_add_missing_io(struct client *client);
348 const char *client_stats(struct client *client);
349 
350 void client_input(struct client *client);
351 bool client_handle_input(struct client *client);
352 int client_output(struct client *client);
353 
354 void clients_init(void);
355 void clients_destroy_all(void);
356 
357 #endif
358