[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