Mercurial > dovecot > original-hg > dovecot-2.1
changeset 4941:f612d2086448 HEAD
If running commands in parallel would cause ambiguity, run them
sequentially.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 20 Dec 2006 22:47:02 +0200 |
parents | 76aa8a360c2f |
children | b382b21409b5 |
files | src/imap/client.c src/imap/client.h src/imap/cmd-uid.c src/imap/commands.c src/imap/commands.h |
diffstat | 5 files changed, 117 insertions(+), 45 deletions(-) [+] |
line wrap: on
line diff
--- a/src/imap/client.c Wed Dec 20 22:13:07 2006 +0200 +++ b/src/imap/client.c Wed Dec 20 22:47:02 2006 +0200 @@ -280,6 +280,47 @@ } static struct client_command_context * +client_command_find_with_flags(struct client_command_context *new_cmd, + enum command_flags flags) +{ + struct client_command_context *cmd; + + cmd = new_cmd->client->command_queue; + for (; cmd != NULL; cmd = cmd->next) { + if (cmd != new_cmd && (cmd->cmd_flags & flags) != 0) + return cmd; + } + return NULL; +} + +static bool client_command_check_ambiguity(struct client_command_context *cmd) +{ + enum command_flags flags; + bool broken_client = FALSE; + + if ((cmd->cmd_flags & COMMAND_FLAG_USES_SEQS) != 0) { + /* no existing command must be breaking sequences */ + flags = COMMAND_FLAG_BREAKS_SEQS; + broken_client = TRUE; + } else if ((cmd->cmd_flags & COMMAND_FLAG_BREAKS_SEQS) != 0) { + /* if existing command uses sequences, we'll have to block */ + flags = COMMAND_FLAG_USES_SEQS; + } else { + return FALSE; + } + + if (client_command_find_with_flags(cmd, flags) == NULL) + return FALSE; + + if (broken_client) { + client_send_line(cmd->client, + "* BAD Command pipelining results in ambiguity."); + } + + return TRUE; +} + +static struct client_command_context * client_command_new(struct client *client) { struct client_command_context *cmd; @@ -356,7 +397,10 @@ p_clear(client->command_pool); } - if (client->input_lock == NULL && !client->disconnected) { + if (!client->disconnected && + (client->input_lock == NULL || + (client->input_lock->waiting_unambiguity && + !client_command_check_ambiguity(client->input_lock)))) { if (client->io == NULL) { i_assert(i_stream_get_fd(client->input) >= 0); client->io = io_add(i_stream_get_fd(client->input), @@ -425,14 +469,27 @@ cmd->name = p_strdup(cmd->pool, cmd->name); } + client->input_skip_line = TRUE; + if (cmd->name == '\0') { /* command not given - cmd_func is already NULL. */ } else { /* find the command function */ - cmd->func = command_find(cmd->name); + struct command *command = command_find(cmd->name); + + if (command != NULL) { + cmd->func = command->func; + cmd->cmd_flags = command->flags; + if (client_command_check_ambiguity(cmd)) { + /* do nothing until existing commands are + finished */ + cmd->waiting_unambiguity = TRUE; + io_remove(&client->io); + return FALSE; + } + } } - client->input_skip_line = TRUE; if (cmd->func == NULL) { /* unknown command */ client_send_command_error(cmd, "Unknown command.");
--- a/src/imap/client.h Wed Dec 20 22:13:07 2006 +0200 +++ b/src/imap/client.h Wed Dec 20 22:47:02 2006 +0200 @@ -23,6 +23,7 @@ pool_t pool; const char *tag; const char *name; + enum command_flags cmd_flags; command_func_t *func; void *context; @@ -33,6 +34,7 @@ unsigned int cancel:1; /* command is wanted to be cancelled */ unsigned int param_error:1; unsigned int output_pending:1; + unsigned int waiting_unambiguity:1; }; struct client {
--- a/src/imap/cmd-uid.c Wed Dec 20 22:13:07 2006 +0200 +++ b/src/imap/cmd-uid.c Wed Dec 20 22:47:02 2006 +0200 @@ -5,6 +5,7 @@ bool cmd_uid(struct client_command_context *cmd) { + struct command *command; const char *cmd_name; /* UID <command> <args> */ @@ -12,7 +13,9 @@ if (cmd_name == NULL) return FALSE; - cmd->func = command_find(t_strconcat("UID ", cmd_name, NULL)); + command = command_find(t_strconcat("UID ", cmd_name, NULL)); + cmd->cmd_flags = command->flags; + cmd->func = command->func; if (cmd->func != NULL) { cmd->uid = TRUE;
--- a/src/imap/commands.c Wed Dec 20 22:13:07 2006 +0200 +++ b/src/imap/commands.c Wed Dec 20 22:47:02 2006 +0200 @@ -8,48 +8,49 @@ #include <stdlib.h> const struct command imap4rev1_commands[] = { - { "CAPABILITY", cmd_capability }, - { "LOGOUT", cmd_logout }, - { "NOOP", cmd_noop }, + { "CAPABILITY", cmd_capability, 0 }, + { "LOGOUT", cmd_logout, 0 }, + { "NOOP", cmd_noop, COMMAND_FLAG_BREAKS_SEQS }, - { "APPEND", cmd_append }, - { "EXAMINE", cmd_examine }, - { "CREATE", cmd_create }, - { "DELETE", cmd_delete }, - { "RENAME", cmd_rename }, - { "LIST", cmd_list }, - { "LSUB", cmd_lsub }, - { "SELECT", cmd_select }, - { "STATUS", cmd_status }, - { "SUBSCRIBE", cmd_subscribe }, - { "UNSUBSCRIBE", cmd_unsubscribe }, + { "APPEND", cmd_append, COMMAND_FLAG_BREAKS_SEQS }, + { "EXAMINE", cmd_examine, COMMAND_FLAG_BREAKS_MAILBOX }, + { "CREATE", cmd_create, 0 }, + { "DELETE", cmd_delete, 0 }, + { "RENAME", cmd_rename, 0 }, + { "LIST", cmd_list, 0 }, + { "LSUB", cmd_lsub, 0 }, + { "SELECT", cmd_select, COMMAND_FLAG_BREAKS_MAILBOX }, + { "STATUS", cmd_status, 0 }, + { "SUBSCRIBE", cmd_subscribe, 0 }, + { "UNSUBSCRIBE", cmd_unsubscribe, 0 }, - { "CHECK", cmd_check }, - { "CLOSE", cmd_close }, - { "COPY", cmd_copy }, - { "EXPUNGE", cmd_expunge }, - { "FETCH", cmd_fetch }, - { "SEARCH", cmd_search }, - { "STORE", cmd_store }, - { "UID", cmd_uid }, - { "UID COPY", cmd_copy }, - { "UID FETCH", cmd_fetch }, - { "UID SEARCH", cmd_search }, - { "UID STORE", cmd_store } + { "CHECK", cmd_check, COMMAND_FLAG_BREAKS_SEQS }, + { "CLOSE", cmd_close, COMMAND_FLAG_BREAKS_MAILBOX }, + { "COPY", cmd_copy, COMMAND_FLAG_USES_SEQS | + COMMAND_FLAG_BREAKS_SEQS }, + { "EXPUNGE", cmd_expunge, COMMAND_FLAG_BREAKS_SEQS }, + { "FETCH", cmd_fetch, COMMAND_FLAG_USES_SEQS }, + { "SEARCH", cmd_search, COMMAND_FLAG_USES_SEQS }, + { "STORE", cmd_store, COMMAND_FLAG_USES_SEQS }, + { "UID", cmd_uid, 0 }, + { "UID COPY", cmd_copy, COMMAND_FLAG_BREAKS_SEQS }, + { "UID FETCH", cmd_fetch, COMMAND_FLAG_BREAKS_SEQS }, + { "UID SEARCH", cmd_search, COMMAND_FLAG_BREAKS_SEQS }, + { "UID STORE", cmd_store, COMMAND_FLAG_BREAKS_SEQS } }; #define IMAP4REV1_COMMANDS_COUNT \ (sizeof(imap4rev1_commands) / sizeof(imap4rev1_commands[0])) const struct command imap_ext_commands[] = { - { "IDLE", cmd_idle }, - { "NAMESPACE", cmd_namespace }, - { "SORT", cmd_sort }, - { "THREAD", cmd_thread }, - { "UID EXPUNGE", cmd_uid_expunge }, - { "UID SORT", cmd_sort }, - { "UID THREAD", cmd_thread }, - { "UNSELECT", cmd_unselect }, - { "X-CANCEL", cmd_x_cancel } + { "IDLE", cmd_idle, COMMAND_FLAG_BREAKS_SEQS }, + { "NAMESPACE", cmd_namespace, 0 }, + { "SORT", cmd_sort, COMMAND_FLAG_USES_SEQS }, + { "THREAD", cmd_thread, COMMAND_FLAG_USES_SEQS }, + { "UID EXPUNGE", cmd_uid_expunge, COMMAND_FLAG_BREAKS_SEQS }, + { "UID SORT", cmd_sort, COMMAND_FLAG_BREAKS_SEQS }, + { "UID THREAD", cmd_thread, COMMAND_FLAG_BREAKS_SEQS }, + { "UNSELECT", cmd_unselect, COMMAND_FLAG_BREAKS_MAILBOX }, + { "X-CANCEL", cmd_x_cancel, 0 } }; #define IMAP_EXT_COMMANDS_COUNT \ (sizeof(imap_ext_commands) / sizeof(imap_ext_commands[0])) @@ -112,9 +113,8 @@ return strcasecmp(name, cmd->name); } -command_func_t *command_find(const char *name) +struct command *command_find(const char *name) { - const struct command *cmd; void *base; unsigned int count; @@ -124,9 +124,8 @@ commands_unsorted = FALSE; } - cmd = bsearch(name, base, count, sizeof(struct command), - command_bsearch); - return cmd == NULL ? NULL : cmd->func; + return bsearch(name, base, count, sizeof(struct command), + command_bsearch); } void commands_init(void)
--- a/src/imap/commands.h Wed Dec 20 22:13:07 2006 +0200 +++ b/src/imap/commands.h Wed Dec 20 22:47:02 2006 +0200 @@ -10,9 +10,20 @@ typedef bool command_func_t(struct client_command_context *cmd); +enum command_flags { + /* Command uses sequences as its input parameters */ + COMMAND_FLAG_USES_SEQS = 0x01, + /* Command may reply with EXPUNGE, causing sequences to break */ + COMMAND_FLAG_BREAKS_SEQS = 0x02, + /* Command changes the mailbox */ + COMMAND_FLAG_BREAKS_MAILBOX = 0x04 | COMMAND_FLAG_BREAKS_SEQS +}; + struct command { const char *name; command_func_t *func; + + enum command_flags flags; }; /* Register command. Given name parameter must be permanently stored until @@ -24,7 +35,7 @@ void command_register_array(const struct command *cmdarr, unsigned int count); void command_unregister_array(const struct command *cmdarr, unsigned int count); -command_func_t *command_find(const char *name); +struct command *command_find(const char *name); void commands_init(void); void commands_deinit(void);