]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Initial support for automatically reconnecting to remote server.
authorTimo Sirainen <tss@iki.fi>
Sun, 9 Oct 2011 13:41:17 +0000 (16:41 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 9 Oct 2011 13:41:17 +0000 (16:41 +0300)
src/lib-imap-client/imapc-client-private.h
src/lib-imap-client/imapc-client.c
src/lib-imap-client/imapc-client.h
src/lib-imap-client/imapc-connection.c
src/lib-imap-client/imapc-connection.h
src/lib-imap-client/imapc-msgmap.c
src/lib-imap-client/imapc-msgmap.h
src/lib-storage/index/imapc/imapc-mail.c
src/lib-storage/index/imapc/imapc-mailbox.c
src/lib-storage/index/imapc/imapc-storage.c
src/lib-storage/index/imapc/imapc-storage.h

index 6d053138c20364ec8534446ae3d9e6ed09d877fb..b427872a55376a8cbec54dc8209a8359c171b3a8 100644 (file)
@@ -28,8 +28,13 @@ struct imapc_client_mailbox {
        struct imapc_connection *conn;
        struct imapc_msgmap *msgmap;
 
+       void (*reopen_callback)(void *context);
+       void *reopen_context;
+
        void *untagged_box_context;
        unsigned int pending_box_command_count;
+
+       bool reconnect_ok;
 };
 
 void imapc_client_ref(struct imapc_client *client);
index bf0a5f1960d5b06c34719a82b260330af28bae63..83da9c7f4e472dbb8754c5640c1526244877d233 100644 (file)
@@ -118,7 +118,7 @@ void imapc_client_register_untagged(struct imapc_client *client,
        client->untagged_context = context;
 }
 
-void imapc_client_run_pre(struct imapc_client *client)
+static void imapc_client_run_pre(struct imapc_client *client)
 {
        struct imapc_client_connection *const *connp;
        struct ioloop *prev_ioloop = current_ioloop;
@@ -138,7 +138,7 @@ void imapc_client_run_pre(struct imapc_client *client)
        current_ioloop = prev_ioloop;
 }
 
-void imapc_client_run_post(struct imapc_client *client)
+static void imapc_client_run_post(struct imapc_client *client)
 {
        struct imapc_client_connection *const *connp;
        struct ioloop *ioloop = client->ioloop;
@@ -151,6 +151,12 @@ void imapc_client_run_post(struct imapc_client *client)
        io_loop_destroy(&ioloop);
 }
 
+void imapc_client_run(struct imapc_client *client)
+{
+       imapc_client_run_pre(client);
+       imapc_client_run_post(client);
+}
+
 void imapc_client_stop(struct imapc_client *client)
 {
        if (client->ioloop != NULL)
@@ -238,10 +244,34 @@ imapc_client_mailbox_open(struct imapc_client *client,
        return box;
 }
 
-void imapc_client_mailbox_disconnect(struct imapc_client_mailbox *box)
+void imapc_client_mailbox_set_reopen_cb(struct imapc_client_mailbox *box,
+                                       void (*callback)(void *context),
+                                       void *context)
+{
+       box->reopen_callback = callback;
+       box->reopen_context = context;
+}
+
+static void
+imapc_client_reconnect_cb(const struct imapc_command_reply *reply,
+                         void *context)
+{
+       struct imapc_client_mailbox *box = context;
+
+       if (reply->state == IMAPC_COMMAND_STATE_OK) {
+               /* reopen the mailbox */
+               box->reopen_callback(box->reopen_context);
+       }
+}
+
+void imapc_client_mailbox_reconnect(struct imapc_client_mailbox *box)
 {
-       if (box->conn != NULL)
-               imapc_connection_disconnect(box->conn);
+       imapc_connection_disconnect(box->conn);
+       if (box->reopen_callback != NULL && box->reconnect_ok) {
+               imapc_connection_connect(box->conn,
+                                        imapc_client_reconnect_cb, box);
+       }
+       box->reconnect_ok = FALSE;
 }
 
 void imapc_client_mailbox_close(struct imapc_client_mailbox **_box)
@@ -249,6 +279,13 @@ void imapc_client_mailbox_close(struct imapc_client_mailbox **_box)
        struct imapc_client_mailbox *box = *_box;
        struct imapc_client_connection *const *connp;
 
+       /* cancel any pending commands */
+       imapc_connection_unselect(box);
+
+       /* set this only after unselect, which may cancel some commands that
+          reference this box */
+       *_box = NULL;
+
        array_foreach(&box->client->conns, connp) {
                if ((*connp)->box == box) {
                        (*connp)->box = NULL;
@@ -256,14 +293,8 @@ void imapc_client_mailbox_close(struct imapc_client_mailbox **_box)
                }
        }
 
-       if (box->conn != NULL)
-               imapc_connection_unselect(box);
        imapc_msgmap_deinit(&box->msgmap);
        i_free(box);
-
-       /* set this only after unselect, which may cancel some commands that
-          reference this box */
-       *_box = NULL;
 }
 
 struct imapc_command *
@@ -285,24 +316,25 @@ imapc_client_mailbox_get_msgmap(struct imapc_client_mailbox *box)
 
 void imapc_client_mailbox_idle(struct imapc_client_mailbox *box)
 {
-       if (imapc_client_mailbox_is_connected(box))
+       if (imapc_client_mailbox_is_opened(box))
                imapc_connection_idle(box->conn);
+       box->reconnect_ok = TRUE;
 }
 
-bool imapc_client_mailbox_is_connected(struct imapc_client_mailbox *box)
+bool imapc_client_mailbox_is_opened(struct imapc_client_mailbox *box)
 {
        struct imapc_client_mailbox *selected_box;
 
-       selected_box = box->conn == NULL ? NULL :
-               imapc_connection_get_mailbox(box->conn);
-       if (selected_box == box)
-               return TRUE;
-
-       if (selected_box != NULL)
-               i_error("imapc: Selected mailbox changed unexpectedly");
+       if (imapc_connection_get_state(box->conn) != IMAPC_CONNECTION_STATE_DONE)
+               return FALSE;
 
-       box->conn = NULL;
-       return FALSE;
+       selected_box = imapc_connection_get_mailbox(box->conn);
+       if (selected_box != box) {
+               if (selected_box != NULL)
+                       i_error("imapc: Selected mailbox changed unexpectedly");
+               return FALSE;
+       }
+       return TRUE;
 }
 
 enum imapc_capability
index 1b916081ecf1d4f505483c61cd4681f91fb442e8..5fe6026786687dc8e0df5da59de9c441e79fdaed 100644 (file)
@@ -27,7 +27,14 @@ extern const struct imapc_capability_name imapc_capability_names[];
 
 enum imapc_command_flags {
        /* The command changes the selected mailbox (SELECT, EXAMINE) */
-       IMAPC_COMMAND_FLAG_SELECT       = 0x01
+       IMAPC_COMMAND_FLAG_SELECT       = 0x01,
+       /* The command is sent to server before login (or is the login
+          command itself). Non-prelogin commands will be queued until login
+          is successful. */
+       IMAPC_COMMAND_FLAG_PRELOGIN     = 0x02,
+       /* Allow command to be automatically retried if disconnected before it
+          finishes. */
+       IMAPC_COMMAND_FLAG_RETRIABLE    = 0x04
 };
 
 enum imapc_client_ssl_mode {
@@ -129,16 +136,18 @@ void imapc_client_register_untagged(struct imapc_client *client,
                                    imapc_untagged_callback_t *callback,
                                    void *context);
 
-void imapc_client_run_pre(struct imapc_client *client);
-void imapc_client_run_post(struct imapc_client *client);
+void imapc_client_run(struct imapc_client *client);
 void imapc_client_stop(struct imapc_client *client);
 bool imapc_client_is_running(struct imapc_client *client);
 
 struct imapc_client_mailbox *
 imapc_client_mailbox_open(struct imapc_client *client,
                          void *untagged_box_context);
+void imapc_client_mailbox_set_reopen_cb(struct imapc_client_mailbox *box,
+                                       void (*callback)(void *context),
+                                       void *context);
 void imapc_client_mailbox_close(struct imapc_client_mailbox **box);
-void imapc_client_mailbox_disconnect(struct imapc_client_mailbox *box);
+void imapc_client_mailbox_reconnect(struct imapc_client_mailbox *box);
 struct imapc_command *
 imapc_client_mailbox_cmd(struct imapc_client_mailbox *box,
                         imapc_command_callback_t *callback, void *context);
@@ -146,7 +155,7 @@ struct imapc_msgmap *
 imapc_client_mailbox_get_msgmap(struct imapc_client_mailbox *box);
 
 void imapc_client_mailbox_idle(struct imapc_client_mailbox *box);
-bool imapc_client_mailbox_is_connected(struct imapc_client_mailbox *box);
+bool imapc_client_mailbox_is_opened(struct imapc_client_mailbox *box);
 
 enum imapc_capability
 imapc_client_get_capabilities(struct imapc_client *client);
index 56edc0b45fddfde9552fa92e52f9ba8dc138cb4f..2267b3ae3ed5fbc8cb484922dfaaa61e13c42fcb 100644 (file)
@@ -122,8 +122,7 @@ struct imapc_connection {
 static int imapc_connection_output(struct imapc_connection *conn);
 static int imapc_connection_ssl_init(struct imapc_connection *conn);
 static void imapc_command_free(struct imapc_command *cmd);
-static void imapc_command_send_more(struct imapc_connection *conn,
-                                   struct imapc_command *cmd);
+static void imapc_command_send_more(struct imapc_connection *conn);
 
 struct imapc_connection *
 imapc_connection_init(struct imapc_client *client)
@@ -253,9 +252,12 @@ imapc_login_callback(struct imapc_connection *conn,
 static void imapc_connection_set_state(struct imapc_connection *conn,
                                       enum imapc_connection_state state)
 {
-       if (state == IMAPC_CONNECTION_STATE_DISCONNECTED) {
-               struct imapc_command_reply reply;
+       struct imapc_command_reply reply;
+
+       conn->state = state;
 
+       switch (state) {
+       case IMAPC_CONNECTION_STATE_DISCONNECTED:
                memset(&reply, 0, sizeof(reply));
                reply.state = IMAPC_COMMAND_STATE_DISCONNECTED;
                reply.text_without_resp = reply.text_full =
@@ -269,15 +271,13 @@ static void imapc_connection_set_state(struct imapc_connection *conn,
 
                conn->selecting_box = NULL;
                conn->selected_box = NULL;
+               break;
+       case IMAPC_CONNECTION_STATE_DONE:
+               imapc_command_send_more(conn);
+               break;
+       default:
+               break;
        }
-       if (state == IMAPC_CONNECTION_STATE_DONE) {
-               if (array_count(&conn->cmd_send_queue) > 0) {
-                       struct imapc_command *const *cmd_p =
-                               array_idx(&conn->cmd_send_queue, 0);
-                       imapc_command_send_more(conn, *cmd_p);
-               }
-       }
-       conn->state = state;
 }
 
 static void imapc_connection_lfiles_free(struct imapc_connection *conn)
@@ -330,6 +330,14 @@ void imapc_connection_disconnect(struct imapc_connection *conn)
        imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DISCONNECTED);
 }
 
+static void imapc_connection_reconnect(struct imapc_connection *conn)
+{
+       if (conn->selected_box != NULL)
+               imapc_client_mailbox_reconnect(conn->selected_box);
+       else
+               imapc_connection_disconnect(conn);
+}
+
 static void ATTR_FORMAT(2, 3)
 imapc_connection_input_error(struct imapc_connection *conn,
                             const char *fmt, ...)
@@ -339,7 +347,6 @@ imapc_connection_input_error(struct imapc_connection *conn,
        va_start(va, fmt);
        i_error("imapc(%s): Server sent invalid input: %s",
                conn->name, t_strdup_vprintf(fmt, va));
-       sleep(3600);
        imapc_connection_disconnect(conn);
        va_end(va);
 }
@@ -636,6 +643,8 @@ static void imapc_connection_login_cb(const struct imapc_command_reply *reply,
        timeout_remove(&conn->to);
        imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DONE);
        imapc_login_callback(conn, reply);
+
+       imapc_command_send_more(conn);
 }
 
 static const char *
@@ -678,6 +687,7 @@ static void imapc_connection_authenticate(struct imapc_connection *conn)
 
        cmd = imapc_connection_cmd(conn, imapc_connection_login_cb,
                                   conn);
+       imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
 
        if ((set->master_user == NULL &&
             need_literal(set->username) && need_literal(set->password)) ||
@@ -727,6 +737,7 @@ static void imapc_connection_starttls(struct imapc_connection *conn)
                }
                cmd = imapc_connection_cmd(conn, imapc_connection_starttls_cb,
                                           conn);
+               imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
                imapc_command_send(cmd, "STARTTLS");
                return;
        }
@@ -769,6 +780,7 @@ static int imapc_connection_input_banner(struct imapc_connection *conn)
                /* capabilities weren't sent in the banner. ask for them. */
                cmd = imapc_connection_cmd(conn, imapc_connection_capability_cb,
                                           conn);
+               imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
                imapc_command_send(cmd, "CAPABILITY");
        } else {
                imapc_connection_starttls(conn);
@@ -864,7 +876,7 @@ static int imapc_connection_input_plus(struct imapc_connection *conn)
        } else if (cmds_count > 0 && cmds[0]->wait_for_literal) {
                /* reply for literal */
                cmds[0]->wait_for_literal = FALSE;
-               imapc_command_send_more(conn, cmds[0]);
+               imapc_command_send_more(conn);
        } else {
                imapc_connection_input_error(conn, "Unexpected '+': %s", line);
                return -1;
@@ -1042,7 +1054,7 @@ static void imapc_connection_input(struct imapc_connection *conn)
                        i_error("imapc(%s): Server disconnected: %s",
                                conn->name, errstr != NULL ? errstr : "");
                }
-               imapc_connection_disconnect(conn);
+               imapc_connection_reconnect(conn);
        }
        imapc_connection_unref(&conn);
 }
@@ -1252,17 +1264,18 @@ imapc_connection_dns_callback(const struct dns_lookup_result *result,
 }
 
 void imapc_connection_connect(struct imapc_connection *conn,
-                             imapc_command_callback_t *callback, void *context)
+                             imapc_command_callback_t *login_callback,
+                             void *login_context)
 {
        struct dns_lookup_settings dns_set;
 
-       i_assert(conn->login_callback == NULL);
        if (conn->fd != -1) {
-               i_assert(callback == NULL);
+               i_assert(login_callback == NULL);
                return;
        }
-       conn->login_callback = callback;
-       conn->login_context = context;
+       i_assert(conn->login_callback == NULL);
+       conn->login_callback = login_callback;
+       conn->login_context = login_context;
 
        imapc_connection_input_reset(conn);
 
@@ -1370,13 +1383,8 @@ static void imapc_command_send_done(struct imapc_connection *conn,
        array_delete(&conn->cmd_send_queue, 0, 1);
        array_append(&conn->cmd_wait_list, &cmd, 1);
 
-       if (array_count(&conn->cmd_send_queue) > 0 &&
-           conn->state == IMAPC_CONNECTION_STATE_DONE) {
-               /* send the next command in queue */
-               struct imapc_command *const *cmd2_p =
-                       array_idx(&conn->cmd_send_queue, 0);
-               imapc_command_send_more(conn, *cmd2_p);
-       }
+       /* send the next command in queue */
+       imapc_command_send_more(conn);
 }
 
 static struct imapc_command_stream *
@@ -1440,15 +1448,29 @@ static void imapc_connection_set_selecting(struct imapc_client_mailbox *box)
        }
 }
 
-static void imapc_command_send_more(struct imapc_connection *conn,
-                                   struct imapc_command *cmd)
+static void imapc_command_send_more(struct imapc_connection *conn)
 {
+       struct imapc_command *const *cmds, *cmd;
        struct imapc_command_reply reply;
        const unsigned char *p, *data;
-       unsigned int seek_pos, start_pos, end_pos, size;
+       unsigned int count, seek_pos, start_pos, end_pos, size;
        int ret;
 
-       i_assert(!cmd->wait_for_literal);
+       cmds = array_get(&conn->cmd_send_queue, &count);
+       if (count == 0)
+               return;
+       cmd = cmds[0];
+
+       if ((cmd->flags & IMAPC_COMMAND_FLAG_PRELOGIN) == 0 &&
+           conn->state != IMAPC_CONNECTION_STATE_DONE) {
+               /* wait until we're fully connected */
+               return;
+       }
+       if (cmd->wait_for_literal) {
+               /* wait until we received '+' */
+               return;
+       }
+
        i_assert(cmd->send_pos < cmd->data->used);
 
        if (cmd->box == NULL) {
@@ -1457,11 +1479,13 @@ static void imapc_command_send_more(struct imapc_connection *conn,
                   (cmd->flags & IMAPC_COMMAND_FLAG_SELECT) != 0) {
                /* SELECT/EXAMINE command */
                imapc_connection_set_selecting(cmd->box);
-       } else if (!imapc_client_mailbox_is_connected(cmd->box)) {
+       } else if (!imapc_client_mailbox_is_opened(cmd->box)) {
                /* shouldn't normally happen */
                memset(&reply, 0, sizeof(reply));
                reply.text_without_resp = reply.text_full = "Mailbox not open";
                reply.state = IMAPC_COMMAND_STATE_BAD;
+
+               array_delete(&conn->cmd_send_queue, 0, 1);
                imapc_command_reply_free(cmd, &reply);
                return;
        }
@@ -1535,7 +1559,7 @@ static void imapc_connection_cmd_send(struct imapc_command *cmd)
        switch (conn->state) {
        case IMAPC_CONNECTION_STATE_AUTHENTICATING:
                array_insert(&conn->cmd_send_queue, 0, &cmd, 1);
-               imapc_command_send_more(conn, cmd);
+               imapc_command_send_more(conn);
                break;
        case IMAPC_CONNECTION_STATE_DONE:
                if (cmd->idle) {
@@ -1547,8 +1571,7 @@ static void imapc_connection_cmd_send(struct imapc_command *cmd)
                }
 
                array_append(&conn->cmd_send_queue, &cmd, 1);
-               if (array_count(&conn->cmd_send_queue) == 1)
-                       imapc_command_send_more(conn, cmd);
+               imapc_command_send_more(conn);
                break;
        default:
                array_append(&conn->cmd_send_queue, &cmd, 1);
@@ -1575,7 +1598,7 @@ static int imapc_connection_output(struct imapc_connection *conn)
                if (imapc_command_get_sending_stream(cmds[0]) != NULL &&
                    !cmds[0]->wait_for_literal) {
                        /* we're sending a stream. send more. */
-                       imapc_command_send_more(conn, cmds[0]);
+                       imapc_command_send_more(conn);
                }
        }
        o_stream_uncork(conn->output);
@@ -1742,9 +1765,7 @@ void imapc_connection_unselect(struct imapc_client_mailbox *box)
                }
        }
 
-       if (conn->selected_box == NULL && conn->selecting_box == NULL) {
-               i_assert(conn->state == IMAPC_CONNECTION_STATE_DISCONNECTED);
-       } else {
+       if (conn->selected_box != NULL || conn->selecting_box != NULL) {
                i_assert(conn->selected_box == box ||
                         conn->selecting_box == box);
 
index 1fcce2385d7a2b75759837843b4cba87cfd1e91d..0b50a6cf2d9abcb02a34e0ddd73865de2665a5c0 100644 (file)
@@ -22,8 +22,8 @@ imapc_connection_init(struct imapc_client *client);
 void imapc_connection_deinit(struct imapc_connection **conn);
 
 void imapc_connection_connect(struct imapc_connection *conn,
-                             imapc_command_callback_t *callback,
-                             void *context);
+                             imapc_command_callback_t *login_callback,
+                             void *login_context);
 void imapc_connection_disconnect(struct imapc_connection *conn);
 void imapc_connection_ioloop_changed(struct imapc_connection *conn);
 void imapc_connection_input_pending(struct imapc_connection *conn);
index d8c7f9e9839d15d068ff02ecd5cdb76190f22bd6..758bb11b85ea20d822c73564c720d4987da37e02 100644 (file)
@@ -86,3 +86,9 @@ void imapc_msgmap_expunge(struct imapc_msgmap *msgmap, uint32_t rseq)
 
        array_delete(&msgmap->uids, rseq-1, 1);
 }
+
+void imapc_msgmap_reset(struct imapc_msgmap *msgmap)
+{
+       array_clear(&msgmap->uids);
+       msgmap->uid_next = 1;
+}
index 51424fda4b0eb057eec5cc5b2c3b0f686e00b336..934bf9717458c291e1480c22fd0ad7ed8875c173 100644 (file)
@@ -13,5 +13,6 @@ bool imapc_msgmap_uid_to_rseq(struct imapc_msgmap *msgmap,
 void imapc_msgmap_append(struct imapc_msgmap *msgmap,
                         uint32_t rseq, uint32_t uid);
 void imapc_msgmap_expunge(struct imapc_msgmap *msgmap, uint32_t rseq);
+void imapc_msgmap_reset(struct imapc_msgmap *msgmap);
 
 #endif
index c974ca12694298469695b4b70e375949622a3d54..bb6ba7cf39e0aacfac89b7b0f078dbdf90c4bed2 100644 (file)
@@ -62,7 +62,7 @@ static void imapc_mail_failed(struct mail *mail, const char *field)
 
        if (mail->expunged || imapc_mail_is_expunged(mail))
                mail_set_expunged(mail);
-       else if (!imapc_client_mailbox_is_connected(mbox->client_box)) {
+       else if (!imapc_client_mailbox_is_opened(mbox->client_box)) {
                /* we've already logged a disconnection error */
                mail_storage_set_internal_error(mail->box->storage);
        } else {
index 622b8db4294f8076298b7decb5d064fb3f4356a6..2a87a4b52928f601bcf9bea2ee986b5179a1ff57 100644 (file)
@@ -30,7 +30,7 @@ static void imapc_mailbox_set_corrupted(struct imapc_mailbox *mbox,
                /* maybe the remote server is buggy and has become confused.
                   try reconnecting. */
        }
-       imapc_client_mailbox_disconnect(mbox->client_box);
+       imapc_client_mailbox_reconnect(mbox->client_box);
 }
 
 static struct mail_index_view *
index 2bfd43dfb0013e43023ca5d26eb9ad727741213e..923a4bf3e662be2fa5f1a6420d7e4c26351d7df7 100644 (file)
@@ -6,9 +6,10 @@
 #include "imap-arg.h"
 #include "imap-resp-code.h"
 #include "mailbox-tree.h"
-#include "imapc-mail.h"
 #include "imapc-client.h"
 #include "imapc-connection.h"
+#include "imapc-msgmap.h"
+#include "imapc-mail.h"
 #include "imapc-list.h"
 #include "imapc-sync.h"
 #include "imapc-settings.h"
@@ -113,8 +114,9 @@ void imapc_simple_run(struct imapc_simple_context *sctx)
 
 void imapc_storage_run(struct imapc_storage *storage)
 {
-       imapc_client_run_pre(storage->client);
-       imapc_client_run_post(storage->client);
+       do {
+               imapc_client_run(storage->client);
+       } while (storage->reopen_count > 0);
 }
 
 void imapc_simple_callback(const struct imapc_command_reply *reply,
@@ -348,12 +350,58 @@ imapc_mailbox_exists(struct mailbox *box, bool auto_boxes ATTR_UNUSED,
        return 0;
 }
 
+static bool imapc_mailbox_want_examine(struct imapc_mailbox *mbox)
+{
+       return (mbox->box.flags & MAILBOX_FLAG_DROP_RECENT) == 0 &&
+               ((mbox->box.flags & MAILBOX_FLAG_READONLY) != 0 ||
+                (mbox->box.flags & MAILBOX_FLAG_SAVEONLY) != 0);
+}
+
+static void
+imapc_mailbox_reopen_callback(const struct imapc_command_reply *reply,
+                             void *context)
+{
+       struct imapc_mailbox *mbox = context;
+
+       i_assert(mbox->storage->reopen_count > 0);
+       mbox->storage->reopen_count--;
+       mbox->selecting = FALSE;
+       if (reply->state != IMAPC_COMMAND_STATE_OK) {
+               mail_storage_set_critical(mbox->box.storage,
+                       "imapc: Reopening mailbox '%s' failed: %s",
+                       mbox->box.name, reply->text_full);
+               imapc_client_mailbox_reconnect(mbox->client_box);
+       }
+       imapc_client_stop(mbox->storage->client);
+}
+
+static void imapc_mailbox_reopen(void *context)
+{
+       struct imapc_mailbox *mbox = context;
+       struct imapc_command *cmd;
+
+       /* we're reconnecting and need to reopen the mailbox */
+       mbox->initial_sync_done = FALSE;
+       mbox->selecting = TRUE;
+       imapc_msgmap_reset(imapc_client_mailbox_get_msgmap(mbox->client_box));
+
+       cmd = imapc_client_mailbox_cmd(mbox->client_box,
+                                      imapc_mailbox_reopen_callback, mbox);
+       imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_SELECT);
+       if (imapc_mailbox_want_examine(mbox))
+               imapc_command_sendf(cmd, "EXAMINE %s", mbox->box.name);
+       else
+               imapc_command_sendf(cmd, "SELECT %s", mbox->box.name);
+       mbox->storage->reopen_count++;
+}
+
 static void
 imapc_mailbox_open_callback(const struct imapc_command_reply *reply,
                            void *context)
 {
        struct imapc_open_context *ctx = context;
 
+       ctx->mbox->selecting = FALSE;
        if (reply->state == IMAPC_COMMAND_STATE_OK)
                ctx->ret = 0;
        else if (reply->state == IMAPC_COMMAND_STATE_NO) {
@@ -373,16 +421,13 @@ int imapc_mailbox_select(struct imapc_mailbox *mbox)
 {
        struct imapc_command *cmd;
        struct imapc_open_context ctx;
-       bool examine = TRUE;
 
        i_assert(mbox->client_box == NULL);
 
-       examine = (mbox->box.flags & MAILBOX_FLAG_DROP_RECENT) == 0 &&
-               ((mbox->box.flags & MAILBOX_FLAG_READONLY) != 0 ||
-                (mbox->box.flags & MAILBOX_FLAG_SAVEONLY) != 0);
-
        mbox->client_box =
                imapc_client_mailbox_open(mbox->storage->client, mbox);
+       imapc_client_mailbox_set_reopen_cb(mbox->client_box,
+                                          imapc_mailbox_reopen, mbox);
 
        mbox->selecting = TRUE;
        ctx.mbox = mbox;
@@ -390,14 +435,13 @@ int imapc_mailbox_select(struct imapc_mailbox *mbox)
        cmd = imapc_client_mailbox_cmd(mbox->client_box,
                                       imapc_mailbox_open_callback, &ctx);
        imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_SELECT);
-       if (examine)
+       if (imapc_mailbox_want_examine(mbox))
                imapc_command_sendf(cmd, "EXAMINE %s", mbox->box.name);
        else
                imapc_command_sendf(cmd, "SELECT %s", mbox->box.name);
 
        while (ctx.ret == -2)
                imapc_storage_run(mbox->storage);
-       mbox->selecting = FALSE;
        return ctx.ret;
 }
 
@@ -670,7 +714,7 @@ static bool imapc_is_inconsistent(struct mailbox *box)
        if (mail_index_view_is_inconsistent(box->view))
                return TRUE;
 
-       return !imapc_client_mailbox_is_connected(mbox->client_box);
+       return !imapc_client_mailbox_is_opened(mbox->client_box);
 }
 
 struct mail_storage imapc_storage = {
index 98922e29ebfe52dbfcacb075b612c7bf2d69efdc..ac45ae0fadbe6a2ae0a4106269bbc857677cf72d 100644 (file)
@@ -37,6 +37,7 @@ struct imapc_storage {
 
        struct imapc_mailbox *cur_status_box;
        struct mailbox_status *cur_status;
+       unsigned int reopen_count;
 
        ARRAY_DEFINE(untagged_callbacks, struct imapc_storage_event_callback);
 };