]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-imap-client: Allow reconnecting to IMAP server even if there had been no idle...
authorTimo Sirainen <tss@iki.fi>
Tue, 25 Aug 2015 13:57:57 +0000 (16:57 +0300)
committerTimo Sirainen <tss@iki.fi>
Tue, 25 Aug 2015 13:57:57 +0000 (16:57 +0300)
src/lib-imap-client/imapc-client.c
src/lib-imap-client/imapc-connection.c
src/lib-imap-client/imapc-connection.h

index 5647e7919125d58aff12b10926d9e9a5d74d1c12..2f9aa21c92b99b084a3e0542aa6012278fd5515c 100644 (file)
@@ -299,6 +299,7 @@ imapc_client_reconnect_cb(const struct imapc_command_reply *reply,
        if (reply->state == IMAPC_COMMAND_STATE_OK) {
                /* reopen the mailbox */
                box->reopen_callback(box->reopen_context);
+               imapc_connection_set_reconnected(box->conn);
        } else {
                imapc_connection_abort_commands(box->conn, NULL, FALSE);
        }
@@ -306,6 +307,9 @@ imapc_client_reconnect_cb(const struct imapc_command_reply *reply,
 
 bool imapc_client_mailbox_can_reconnect(struct imapc_client_mailbox *box)
 {
+       /* the reconnect_ok flag attempts to avoid infinite reconnection loops
+          to a server that keeps disconnecting us (e.g. some of the commands
+          we send keeps crashing it always) */
        return box->reopen_callback != NULL && box->reconnect_ok;
 }
 
@@ -322,6 +326,9 @@ void imapc_client_mailbox_reconnect(struct imapc_client_mailbox *box)
                imapc_connection_connect(box->conn,
                                         imapc_client_reconnect_cb, box);
        }
+       /* if we fail again, avoid reconnecting immediately. if the server is
+          broken we could just get into an infinitely failing reconnection
+          loop. */
        box->reconnect_ok = FALSE;
 }
 
@@ -393,6 +400,7 @@ void imapc_client_mailbox_idle(struct imapc_client_mailbox *box)
                        timeout_add_short(IMAPC_CLIENT_IDLE_SEND_DELAY_MSECS,
                                          imapc_client_mailbox_idle_send, box);
        }
+       /* we're done with all work at this point. */
        box->reconnect_ok = TRUE;
 }
 
index e0da955bf182bd51eba9a12dcb2a1395ba9ac4ff..ecba20361806798e57788b8c45f939d5ac221e6e 100644 (file)
@@ -110,6 +110,7 @@ struct imapc_connection {
        ARRAY_TYPE(imapc_command) cmd_send_queue;
        /* commands that have been sent, waiting for their tagged reply */
        ARRAY_TYPE(imapc_command) cmd_wait_list;
+       unsigned int reconnect_command_count;
 
        unsigned int ips_count, prev_connect_idx;
        struct ip_addr *ips;
@@ -1303,6 +1304,16 @@ static int imapc_connection_input_tagged(struct imapc_connection *conn)
                imapc_connection_unselect(conn->selected_box);
        }
 
+       if (conn->reconnect_command_count > 0) {
+               if (--conn->reconnect_command_count == 0) {
+                       /* we've received replies for all the commands started
+                          before reconnection. if we get disconnected now, we
+                          can safely reconnect without worrying about infinite
+                          reconnect loops. */
+                       if (conn->selected_box != NULL)
+                               conn->selected_box->reconnect_ok = TRUE;
+               }
+       }
        imapc_connection_input_reset(conn);
        imapc_command_reply_free(cmd, &reply);
        imapc_command_send_more(conn);
@@ -2216,3 +2227,9 @@ void imapc_connection_idle(struct imapc_connection *conn)
        cmd->idle = TRUE;
        imapc_command_send(cmd, "IDLE");
 }
+
+void imapc_connection_set_reconnected(struct imapc_connection *conn)
+{
+       conn->reconnect_command_count = array_count(&conn->cmd_wait_list) +
+               array_count(&conn->cmd_send_queue);
+}
index d77411b9548e3d53d8697c65680e9e393b4a59cb..08b4dc50bcd4bf783e3431ff04319805de4053c9 100644 (file)
@@ -52,5 +52,6 @@ struct imapc_client_mailbox *
 imapc_connection_get_mailbox(struct imapc_connection *conn);
 
 void imapc_connection_idle(struct imapc_connection *conn);
+void imapc_connection_set_reconnected(struct imapc_connection *conn);
 
 #endif