Mercurial > dovecot > core-2.2
changeset 22756:1f74202e9f70
lib-imap-client: Avoid "Unknown tag" errors for aborted commands
If mailbox is closed before all command replies were received, the commands
were aborted but they'll still receive the replies from server. Remember
the aborted commands' tag numbers so they can be ignored.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Wed, 17 Jan 2018 15:03:06 +0200 |
parents | 59ac434fef3f |
children | ffccd1d964b3 |
files | src/lib-imap-client/imapc-connection.c |
diffstat | 1 files changed, 21 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-imap-client/imapc-connection.c Wed Jan 17 15:02:09 2018 +0200 +++ b/src/lib-imap-client/imapc-connection.c Wed Jan 17 15:03:06 2018 +0200 @@ -64,6 +64,8 @@ unsigned int idle:1; /* Waiting for '+' literal reply before we can continue */ unsigned int wait_for_literal:1; + /* Command is fully sent to server */ + unsigned int sent:1; }; ARRAY_DEFINE_TYPE(imapc_command, struct imapc_command *); @@ -114,6 +116,9 @@ ARRAY_TYPE(imapc_command) cmd_send_queue; /* commands that have been sent, waiting for their tagged reply */ ARRAY_TYPE(imapc_command) cmd_wait_list; + /* commands that were already sent, but were aborted since (due to + unselecting mailbox). */ + ARRAY_TYPE(seq_range) aborted_cmd_tags; unsigned int reconnect_command_count; unsigned int ips_count, prev_connect_idx; @@ -202,6 +207,7 @@ i_array_init(&conn->cmd_send_queue, 8); i_array_init(&conn->cmd_wait_list, 32); i_array_init(&conn->literal_files, 4); + i_array_init(&conn->aborted_cmd_tags, 8); if (client->set.debug) i_debug("imapc(%s): Created new connection", conn->name); @@ -234,6 +240,7 @@ array_free(&conn->cmd_send_queue); array_free(&conn->cmd_wait_list); array_free(&conn->literal_files); + array_free(&conn->aborted_cmd_tags); imapc_client_unref(&conn->client); i_free(conn->ips); i_free(conn->name); @@ -348,6 +355,11 @@ array_foreach(&tmp_array, cmdp) { cmd = *cmdp; + if (cmd->sent && conn->state == IMAPC_CONNECTION_STATE_DONE) { + /* We're not disconnected, so the reply will still + come. Remember that it needs to be ignored. */ + seq_range_array_add(&conn->aborted_cmd_tags, cmd->tag); + } cmd->callback(&reply, cmd->context); imapc_command_free(cmd); } @@ -386,6 +398,7 @@ i_free(conn->ips); conn->ips_count = 0; } + array_clear(&conn->aborted_cmd_tags); conn->idling = FALSE; conn->idle_plus_waiting = FALSE; conn->idle_stopping = FALSE; @@ -1435,6 +1448,13 @@ timeout_remove(&conn->to); if (cmd == NULL) { + if (seq_range_exists(&conn->aborted_cmd_tags, conn->cur_tag)) { + /* sent command was already aborted - ignore it */ + seq_range_array_remove(&conn->aborted_cmd_tags, + conn->cur_tag); + imapc_connection_input_reset(conn); + return 1; + } imapc_connection_input_error(conn, "Unknown tag in a reply: %u %s %s", conn->cur_tag, line, reply.text_full); @@ -1988,6 +2008,7 @@ if (cmd->idle) conn->idle_plus_waiting = TRUE; + cmd->sent = TRUE; /* everything sent. move command to wait list. */ cmdp = array_idx(&conn->cmd_send_queue, 0);