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