dovecot-2.1: imapc: Initial support for automatically reconnecti...

dovecot at dovecot.org dovecot at dovecot.org
Sun Oct 9 16:32:57 EEST 2011


details:   http://hg.dovecot.org/dovecot-2.1/rev/8fdd22504aab
changeset: 13621:8fdd22504aab
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Oct 09 16:41:17 2011 +0300
description:
imapc: Initial support for automatically reconnecting to remote server.

diffstat:

 src/lib-imap-client/imapc-client-private.h  |   5 +
 src/lib-imap-client/imapc-client.c          |  76 +++++++++++++++------
 src/lib-imap-client/imapc-client.h          |  19 ++++-
 src/lib-imap-client/imapc-connection.c      |  99 +++++++++++++++++-----------
 src/lib-imap-client/imapc-connection.h      |   4 +-
 src/lib-imap-client/imapc-msgmap.c          |   6 +
 src/lib-imap-client/imapc-msgmap.h          |   1 +
 src/lib-storage/index/imapc/imapc-mail.c    |   2 +-
 src/lib-storage/index/imapc/imapc-mailbox.c |   2 +-
 src/lib-storage/index/imapc/imapc-storage.c |  66 ++++++++++++++++---
 src/lib-storage/index/imapc/imapc-storage.h |   1 +
 11 files changed, 200 insertions(+), 81 deletions(-)

diffs (truncated from 659 to 300 lines):

diff -r 7e0bdfa76f12 -r 8fdd22504aab src/lib-imap-client/imapc-client-private.h
--- 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);
diff -r 7e0bdfa76f12 -r 8fdd22504aab src/lib-imap-client/imapc-client.c
--- 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)
 {
-	if (box->conn != NULL)
-		imapc_connection_disconnect(box->conn);
+	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)
+{
+	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
diff -r 7e0bdfa76f12 -r 8fdd22504aab src/lib-imap-client/imapc-client.h
--- 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);
diff -r 7e0bdfa76f12 -r 8fdd22504aab src/lib-imap-client/imapc-connection.c
--- 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);


More information about the dovecot-cvs mailing list