changeset 7583:a99b9735f875 HEAD

Don't try to call a cancelled command if it hasn't started running. Cancel the input-waiting command last. These should fix "Trying to close mailbox with open transactions" assert when client disconnects.
author Timo Sirainen <tss@iki.fi>
date Sat, 31 May 2008 13:59:46 +0300
parents 8e7a15987428
children e528d9e3cdc8
files src/imap/client.c
diffstat 1 files changed, 26 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/client.c	Sat May 31 13:47:11 2008 +0300
+++ b/src/imap/client.c	Sat May 31 13:59:46 2008 +0300
@@ -71,8 +71,26 @@
 	struct client_command_context *cmd = *_cmd;
 	bool cmd_ret;
 
-	cmd->cancel = TRUE;
-	cmd_ret = cmd->func == NULL ? TRUE : cmd->func(cmd);
+	switch (cmd->state) {
+	case CLIENT_COMMAND_STATE_WAIT_INPUT:
+		/* a bit kludgy check: cancel command only if it has context
+		   set. currently only append command matches this check. all
+		   other commands haven't even started the processing yet. */
+		if (cmd->context == NULL)
+			break;
+		/* fall through */
+	case CLIENT_COMMAND_STATE_WAIT_OUTPUT:
+		cmd->cancel = TRUE;
+		break;
+	case CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY:
+	case CLIENT_COMMAND_STATE_WAIT_SYNC:
+		/* commands haven't started yet */
+		break;
+	case CLIENT_COMMAND_STATE_DONE:
+		i_unreached();
+	}
+
+	cmd_ret = !cmd->cancel || cmd->func == NULL ? TRUE : cmd->func(cmd);
 	if (!cmd_ret && cmd->state != CLIENT_COMMAND_STATE_DONE) {
 		if (cmd->client->output->closed)
 			i_panic("command didn't cancel itself: %s", cmd->name);
@@ -130,12 +148,16 @@
 	/* finish off all the queued commands. */
 	if (client->output_lock != NULL)
 		client_command_cancel(&client->output_lock);
-	if (client->input_lock != NULL)
-		client_command_cancel(&client->input_lock);
 	while (client->command_queue != NULL) {
 		cmd = client->command_queue;
 		client_command_cancel(&cmd);
 	}
+	/* handle the input_lock command last. it might have been waiting on
+	   other queued commands (although we probably should just drop the
+	   command at that point since it hasn't started running. but this may
+	   change in future). */
+	if (client->input_lock != NULL)
+		client_command_cancel(&client->input_lock);
 
 	if (client->mailbox != NULL)
 		mailbox_close(&client->mailbox);