imap-client.h revision 809329fe7be1281bec99dd5d06fd7b8b52752daf
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch#ifndef IMAP_CLIENT_H
02b32cf39a098edf60981fc228e4b034f11f3b90Timo Sirainen#define IMAP_CLIENT_H
02b32cf39a098edf60981fc228e4b034f11f3b90Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen#include "imap-commands.h"
02b32cf39a098edf60981fc228e4b034f11f3b90Timo Sirainen
4a7e04d325db0c03f575f98f045246fceb0de279Timo Sirainen#define CLIENT_COMMAND_QUEUE_MAX_SIZE 4
02b32cf39a098edf60981fc228e4b034f11f3b90Timo Sirainen/* Maximum number of CONTEXT=SEARCH UPDATEs. Clients probably won't need more
4eb418849d5c6bf77b2721e4e6aef2e97deaa197Timo Sirainen than a few, so this is mainly to avoid more or less accidental pointless
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen resource usage. */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#define CLIENT_MAX_SEARCH_UPDATES 10
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenstruct client;
9e86ad9eb313004cd4c8b5427daeb4c241b57af6Timo Sirainenstruct mail_storage;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenstruct imap_parser;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenstruct imap_arg;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenstruct mailbox_keywords {
1ea0aa8e14e843f2776746776a429b0a1aae299dTimo Sirainen /* All keyword names. The array itself exists in mail_index.
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen Keywords are currently only appended, they're never removed. */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen const ARRAY_TYPE(keywords) *names;
68332e3a49dea15013aa8f4daa16b5e07eb3d543Timo Sirainen /* Number of keywords announced to client via FLAGS/PERMANENTFLAGS.
65f9a90ef5ed4c86fb9e44f22e472509126ae9f5Timo Sirainen This relies on keywords not being removed while mailbox is
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen selected. */
48f78a48f2e1cf299026544444666471ae16ad97Timo Sirainen unsigned int announce_count;
4a7e04d325db0c03f575f98f045246fceb0de279Timo Sirainen};
4a7e04d325db0c03f575f98f045246fceb0de279Timo Sirainen
f83fd83f9c6708d198748e714aa947cad9362c02Timo Sirainenstruct imap_search_update {
4a7e04d325db0c03f575f98f045246fceb0de279Timo Sirainen char *tag;
1ea0aa8e14e843f2776746776a429b0a1aae299dTimo Sirainen struct mail_search_result *result;
1ea0aa8e14e843f2776746776a429b0a1aae299dTimo Sirainen bool return_uids;
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen};
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainenenum client_command_state {
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen /* Waiting for more input */
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen CLIENT_COMMAND_STATE_WAIT_INPUT,
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen /* Waiting to be able to send more output */
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen CLIENT_COMMAND_STATE_WAIT_OUTPUT,
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen /* Wait for other commands to finish execution */
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY,
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen /* Waiting for other commands to finish so we can sync */
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen CLIENT_COMMAND_STATE_WAIT_SYNC,
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen /* Command is finished */
6e77746e501c2b45850b1c530836058ed75e09eeTimo Sirainen CLIENT_COMMAND_STATE_DONE
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainen};
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainen
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainenstruct imap_module_register {
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainen unsigned int id;
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainen};
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainen
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainenunion imap_module_context {
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainen struct imap_module_register *reg;
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainen};
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainenextern struct imap_module_register imap_module_register;
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainen
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainenstruct client_command_context {
8c8f7ac580b661aee3d8b8dd37df4a9b41c77000Timo Sirainen struct client_command_context *prev, *next;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen struct client *client;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen pool_t pool;
48f78a48f2e1cf299026544444666471ae16ad97Timo Sirainen /* IMAP command tag */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen const char *tag;
48f78a48f2e1cf299026544444666471ae16ad97Timo Sirainen /* Name of this command */
48f78a48f2e1cf299026544444666471ae16ad97Timo Sirainen const char *name;
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen /* Parameters for this command. These are generated from parsed IMAP
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen arguments, so they may not be exactly the same as how client sent
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen them. */
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen const char *args;
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen enum command_flags cmd_flags;
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen command_func_t *func;
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen void *context;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen /* Module-specific contexts. */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen ARRAY_DEFINE(module_contexts, union imap_module_context *);
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct imap_parser *parser;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch enum client_command_state state;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct client_sync_context *sync;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int uid:1; /* used UID command */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int cancel:1; /* command is wanted to be cancelled */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int param_error:1;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int search_save_result:1; /* search result is being updated */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int temp_executed:1; /* temporary execution state tracking */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen};
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainenstruct client {
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct client *prev, *next;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen int fd_in, fd_out;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct io *io;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct istream *input;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct ostream *output;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct timeout *to_idle, *to_idle_output;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen pool_t pool;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct mail_storage_service_user *service_user;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen const struct imap_settings *set;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen string_t *capability_string;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct mail_user *user;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct mailbox *mailbox;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct mailbox_keywords keywords;
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen unsigned int select_counter; /* increased when mailbox is changed */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int sync_counter;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen uint32_t messages_count, recent_count, uidvalidity;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen enum mailbox_feature enabled_features;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen time_t last_input, last_output;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int bad_counter;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen /* one parser is kept here to be used for new commands */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct imap_parser *free_parser;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen /* command_pool is cleared when the command queue gets empty */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen pool_t command_pool;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen /* New commands are always prepended to the queue */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct client_command_context *command_queue;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int command_queue_size;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen uint64_t sync_last_full_modseq;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen uint64_t highest_fetch_modseq;
14cac26dcb71108abfdc95ea524e74be1f95774cPhil Carmody
14cac26dcb71108abfdc95ea524e74be1f95774cPhil Carmody /* SEARCHRES extension: Last saved SEARCH result */
14cac26dcb71108abfdc95ea524e74be1f95774cPhil Carmody ARRAY_TYPE(seq_range) search_saved_uidset;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen /* SEARCH=CONTEXT extension: Searches that get updated */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen ARRAY_DEFINE(search_updates, struct imap_search_update);
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen /* client input/output is locked by this command */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct client_command_context *input_lock;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct client_command_context *output_lock;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen /* command changing the mailbox */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen struct client_command_context *mailbox_change_lock;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen /* Module-specific contexts. */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen ARRAY_DEFINE(module_contexts, union imap_module_context *);
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen /* syncing marks this TRUE when it sees \Deleted flags. this is by
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen EXPUNGE for Outlook-workaround. */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int sync_seen_deletes:1;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int sync_seen_expunges:1;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int disconnected:1;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int destroyed:1;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int handling_input:1;
1107c86ff3fa4f29796c2e76134b78d0b4a0db50Timo Sirainen unsigned int syncing:1;
1107c86ff3fa4f29796c2e76134b78d0b4a0db50Timo Sirainen unsigned int id_logged:1;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int mailbox_examined:1;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int anvil_sent:1;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int tls_compression:1;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int input_skip_line:1; /* skip all the data until we've
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen found a new line */
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen unsigned int modseqs_sent_since_sync:1;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen};
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainenextern struct client *imap_clients;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainenextern unsigned int imap_client_count;
b5ff746939712c6a9bef71405fa786d5471cf177Timo Sirainen
4eb418849d5c6bf77b2721e4e6aef2e97deaa197Timo Sirainen/* Create new client with specified input/output handles. socket specifies
4eb418849d5c6bf77b2721e4e6aef2e97deaa197Timo Sirainen if the handle is a socket. */
4eb418849d5c6bf77b2721e4e6aef2e97deaa197Timo Sirainenstruct client *client_create(int fd_in, int fd_out, struct mail_user *user,
4eb418849d5c6bf77b2721e4e6aef2e97deaa197Timo Sirainen struct mail_storage_service_user *service_user,
4eb418849d5c6bf77b2721e4e6aef2e97deaa197Timo Sirainen const struct imap_settings *set);
4eb418849d5c6bf77b2721e4e6aef2e97deaa197Timo Sirainenvoid client_destroy(struct client *client, const char *reason);
a8b37b688ceaa3ed3d40b3ccbdba5bb75cfb64b0Timo Sirainen
a8b37b688ceaa3ed3d40b3ccbdba5bb75cfb64b0Timo Sirainen/* Disconnect client connection */
4eb418849d5c6bf77b2721e4e6aef2e97deaa197Timo Sirainenvoid client_disconnect(struct client *client, const char *reason);
4eb418849d5c6bf77b2721e4e6aef2e97deaa197Timo Sirainenvoid client_disconnect_with_error(struct client *client, const char *msg);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen/* Send a line of data to client. Returns 1 if ok, 0 if buffer is getting full,
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen -1 if error */
02b32cf39a098edf60981fc228e4b034f11f3b90Timo Sirainenint client_send_line(struct client *client, const char *data);
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen/* Send line of data to client, prefixed with client->tag. You need to prefix
4eb418849d5c6bf77b2721e4e6aef2e97deaa197Timo Sirainen the data with "OK ", "NO " or "BAD ". */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenvoid client_send_tagline(struct client_command_context *cmd, const char *data);
02b32cf39a098edf60981fc228e4b034f11f3b90Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen/* Send a BAD command reply to client via client_send_tagline(). If there have
02b32cf39a098edf60981fc228e4b034f11f3b90Timo Sirainen been too many command errors, the client is disconnected. msg may be NULL,
4a7e04d325db0c03f575f98f045246fceb0de279Timo Sirainen in which case the error is looked up from imap_parser. */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenvoid client_send_command_error(struct client_command_context *cmd,
4a7e04d325db0c03f575f98f045246fceb0de279Timo Sirainen const char *msg);
4a7e04d325db0c03f575f98f045246fceb0de279Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen/* Read a number of arguments. Returns TRUE if everything was read or
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen FALSE if either needs more data or error occurred. */
0dc7891233a973829f00371b27810f849b987c66Timo Sirainenbool client_read_args(struct client_command_context *cmd, unsigned int count,
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen unsigned int flags, const struct imap_arg **args_r);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen/* Reads a number of string arguments. ... is a list of pointers where to
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen store the arguments. */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenbool client_read_string_args(struct client_command_context *cmd,
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen unsigned int count, ...);
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen/* SEARCHRES extension: Call if $ is being used/updated, returns TRUE if we
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen have to wait for an existing SEARCH SAVE to finish. */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenbool client_handle_search_save_ambiguity(struct client_command_context *cmd);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenvoid client_enable(struct client *client, enum mailbox_feature features);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenstruct imap_search_update *
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenclient_search_update_lookup(struct client *client, const char *tag,
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen unsigned int *idx_r);
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainenvoid client_search_updates_free(struct client *client);
4a7e04d325db0c03f575f98f045246fceb0de279Timo Sirainen
4a7e04d325db0c03f575f98f045246fceb0de279Timo Sirainenvoid client_command_cancel(struct client_command_context **cmd);
f83fd83f9c6708d198748e714aa947cad9362c02Timo Sirainenvoid client_command_free(struct client_command_context **cmd);
4a7e04d325db0c03f575f98f045246fceb0de279Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenbool client_handle_unfinished_cmd(struct client_command_context *cmd);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenvoid client_continue_pending_input(struct client *client);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
02b32cf39a098edf60981fc228e4b034f11f3b90Timo Sirainenvoid client_input(struct client *client);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenbool client_handle_input(struct client *client);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenint client_output(struct client *client);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
0dc7891233a973829f00371b27810f849b987c66Timo Sirainenvoid clients_destroy_all(void);
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen
0dc7891233a973829f00371b27810f849b987c66Timo Sirainen#endif
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen