[dovecot-cvs] dovecot/src/imap client.c, 1.73, 1.74 client.h, 1.39, 1.40 cmd-uid.c, 1.8, 1.9 commands.c, 1.19, 1.20 commands.h, 1.21, 1.22
tss at dovecot.org
tss at dovecot.org
Wed Dec 20 20:47:04 UTC 2006
Update of /var/lib/cvs/dovecot/src/imap
In directory talvi:/tmp/cvs-serv709
Modified Files:
client.c client.h cmd-uid.c commands.c commands.h
Log Message:
If running commands in parallel would cause ambiguity, run them
sequentially.
Index: client.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap/client.c,v
retrieving revision 1.73
retrieving revision 1.74
diff -u -d -r1.73 -r1.74
--- client.c 20 Dec 2006 19:23:46 -0000 1.73
+++ client.c 20 Dec 2006 20:47:02 -0000 1.74
@@ -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.");
Index: client.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap/client.h,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -d -r1.39 -r1.40
--- client.h 20 Dec 2006 19:23:46 -0000 1.39
+++ client.h 20 Dec 2006 20:47:02 -0000 1.40
@@ -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 {
Index: cmd-uid.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap/cmd-uid.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- cmd-uid.c 20 Dec 2006 19:23:46 -0000 1.8
+++ cmd-uid.c 20 Dec 2006 20:47:02 -0000 1.9
@@ -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;
Index: commands.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap/commands.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- commands.c 20 Dec 2006 19:23:46 -0000 1.19
+++ commands.c 20 Dec 2006 20:47:02 -0000 1.20
@@ -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)
Index: commands.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap/commands.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- commands.h 20 Dec 2006 19:23:46 -0000 1.21
+++ commands.h 20 Dec 2006 20:47:02 -0000 1.22
@@ -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);
More information about the dovecot-cvs
mailing list