changeset 13621:8fdd22504aab

imapc: Initial support for automatically reconnecting to remote server.
author Timo Sirainen <tss@iki.fi>
date Sun, 09 Oct 2011 16:41:17 +0300
parents 7e0bdfa76f12
children 305ca9c93dd7
files 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
diffstat 11 files changed, 200 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-imap-client/imapc-client-private.h	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-imap-client/imapc-client-private.h	Sun Oct 09 16:41:17 2011 +0300
@@ -28,8 +28,13 @@
 	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);
--- a/src/lib-imap-client/imapc-client.c	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-imap-client/imapc-client.c	Sun Oct 09 16:41:17 2011 +0300
@@ -118,7 +118,7 @@
 	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 @@
 	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 @@
 	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 @@
 	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)
 {
-	if (box->conn != NULL)
-		imapc_connection_disconnect(box->conn);
+	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)
+{
+	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 @@
 	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 @@
 		}
 	}
 
-	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 @@
 
 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 (imapc_connection_get_state(box->conn) != IMAPC_CONNECTION_STATE_DONE)
+		return FALSE;
 
-	if (selected_box != NULL)
-		i_error("imapc: Selected mailbox changed unexpectedly");
-
-	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
--- a/src/lib-imap-client/imapc-client.h	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-imap-client/imapc-client.h	Sun Oct 09 16:41:17 2011 +0300
@@ -27,7 +27,14 @@
 
 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 @@
 				    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 @@
 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);
--- a/src/lib-imap-client/imapc-connection.c	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-imap-client/imapc-connection.c	Sun Oct 09 16:41:17 2011 +0300
@@ -122,8 +122,7 @@
 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 @@
 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 @@
 
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 
 	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 @@
 		}
 		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 @@
 		/* 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 @@
 	} 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 @@
 			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 @@
 }
 
 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 @@
 	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_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 @@
 		   (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 @@
 	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 @@
 		}
 
 		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 @@
 		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 @@
 		}
 	}
 
-	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);
 
--- a/src/lib-imap-client/imapc-connection.h	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-imap-client/imapc-connection.h	Sun Oct 09 16:41:17 2011 +0300
@@ -22,8 +22,8 @@
 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);
--- a/src/lib-imap-client/imapc-msgmap.c	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-imap-client/imapc-msgmap.c	Sun Oct 09 16:41:17 2011 +0300
@@ -86,3 +86,9 @@
 
 	array_delete(&msgmap->uids, rseq-1, 1);
 }
+
+void imapc_msgmap_reset(struct imapc_msgmap *msgmap)
+{
+	array_clear(&msgmap->uids);
+	msgmap->uid_next = 1;
+}
--- a/src/lib-imap-client/imapc-msgmap.h	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-imap-client/imapc-msgmap.h	Sun Oct 09 16:41:17 2011 +0300
@@ -13,5 +13,6 @@
 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
--- a/src/lib-storage/index/imapc/imapc-mail.c	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-storage/index/imapc/imapc-mail.c	Sun Oct 09 16:41:17 2011 +0300
@@ -62,7 +62,7 @@
 
 	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 {
--- a/src/lib-storage/index/imapc/imapc-mailbox.c	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-storage/index/imapc/imapc-mailbox.c	Sun Oct 09 16:41:17 2011 +0300
@@ -30,7 +30,7 @@
 		/* 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 *
--- a/src/lib-storage/index/imapc/imapc-storage.c	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-storage/index/imapc/imapc-storage.c	Sun Oct 09 16:41:17 2011 +0300
@@ -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_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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 	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 = {
--- a/src/lib-storage/index/imapc/imapc-storage.h	Sat Oct 08 20:31:22 2011 +0300
+++ b/src/lib-storage/index/imapc/imapc-storage.h	Sun Oct 09 16:41:17 2011 +0300
@@ -37,6 +37,7 @@
 
 	struct imapc_mailbox *cur_status_box;
 	struct mailbox_status *cur_status;
+	unsigned int reopen_count;
 
 	ARRAY_DEFINE(untagged_callbacks, struct imapc_storage_event_callback);
 };