changeset 21933:a892db12fd6a

lib-imap-client: Call the public login callback exactly once. Previously it was also called only once, as long as there were only a single imap connection. (The current imapc code wouldn't create more than one connection.) It was a bit confusing what the expectation was, so now the callback is never called more than once.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 10 Apr 2017 15:49:24 +0300
parents 742783900e50
children 76fdf3886569
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
diffstat 5 files changed, 54 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-imap-client/imapc-client-private.h	Mon Apr 10 14:14:40 2017 +0300
+++ b/src/lib-imap-client/imapc-client-private.h	Mon Apr 10 15:49:24 2017 +0300
@@ -7,6 +7,7 @@
 
 struct imapc_client_connection {
 	struct imapc_connection *conn;
+	struct imapc_client *client;
 	struct imapc_client_mailbox *box;
 };
 
--- a/src/lib-imap-client/imapc-client.c	Mon Apr 10 14:14:40 2017 +0300
+++ b/src/lib-imap-client/imapc-client.c	Mon Apr 10 15:49:24 2017 +0300
@@ -176,8 +176,7 @@
 	array_foreach(&client->conns, connp) {
 		imapc_connection_ioloop_changed((*connp)->conn);
 		if (imapc_connection_get_state((*connp)->conn) == IMAPC_CONNECTION_STATE_DISCONNECTED)
-			imapc_connection_connect((*connp)->conn, client->login_callback,
-					 client->login_context);
+			imapc_connection_connect((*connp)->conn);
 	}
 
 	if (io_loop_is_running(client->ioloop))
@@ -200,7 +199,6 @@
 
 void imapc_client_run(struct imapc_client *client)
 {
-	i_assert(client->login_callback != NULL);
 	imapc_client_run_pre(client);
 	imapc_client_run_post(client);
 }
@@ -225,13 +223,44 @@
 	return client->ioloop != NULL;
 }
 
+static void imapc_client_login_callback(const struct imapc_command_reply *reply,
+					void *context)
+{
+	struct imapc_client_connection *conn = context;
+	struct imapc_client *client = conn->client;
+	struct imapc_client_mailbox *box = conn->box;
+
+	if (box != NULL && box->reconnecting) {
+		box->reconnecting = FALSE;
+
+		if (reply->state == IMAPC_COMMAND_STATE_OK) {
+			/* reopen the mailbox */
+			box->reopen_callback(box->reopen_context);
+		} else {
+			imapc_connection_abort_commands(box->conn, NULL, FALSE);
+		}
+	}
+
+	/* call the login callback only once */
+	if (client->login_callback != NULL) {
+		imapc_command_callback_t *callback = client->login_callback;
+		void *context = client->login_context;
+
+		client->login_callback = NULL;
+		client->login_context = NULL;
+		callback(reply, context);
+	}
+}
+
 static struct imapc_client_connection *
 imapc_client_add_connection(struct imapc_client *client)
 {
 	struct imapc_client_connection *conn;
 
 	conn = i_new(struct imapc_client_connection, 1);
-	conn->conn = imapc_connection_init(client);
+	conn->client = client;
+	conn->conn = imapc_connection_init(client, imapc_client_login_callback,
+					   conn);
 	array_append(&client->conns, &conn, 1);
 	return conn;
 }
@@ -281,8 +310,7 @@
 	i_assert(array_count(&client->conns) == 0);
 
 	conn = imapc_client_add_connection(client);
-	imapc_connection_connect(conn->conn,
-				 client->login_callback, client->login_context);
+	imapc_connection_connect(conn->conn);
 }
 
 struct imapc_logout_ctx {
@@ -360,23 +388,6 @@
 	box->reopen_context = context;
 }
 
-static void
-imapc_client_reconnect_cb(const struct imapc_command_reply *reply,
-			  void *context)
-{
-	struct imapc_client_mailbox *box = context;
-
-	i_assert(box->reconnecting);
-	box->reconnecting = FALSE;
-
-	if (reply->state == IMAPC_COMMAND_STATE_OK) {
-		/* reopen the mailbox */
-		box->reopen_callback(box->reopen_context);
-	} else {
-		imapc_connection_abort_commands(box->conn, NULL, FALSE);
-	}
-}
-
 bool imapc_client_mailbox_can_reconnect(struct imapc_client_mailbox *box)
 {
 	/* the reconnect_ok flag attempts to avoid infinite reconnection loops
@@ -396,7 +407,7 @@
 	box->reconnect_ok = FALSE;
 
 	imapc_connection_disconnect_full(box->conn, TRUE);
-	imapc_connection_connect(box->conn, imapc_client_reconnect_cb, box);
+	imapc_connection_connect(box->conn);
 }
 
 void imapc_client_mailbox_close(struct imapc_client_mailbox **_box)
--- a/src/lib-imap-client/imapc-client.h	Mon Apr 10 14:14:40 2017 +0300
+++ b/src/lib-imap-client/imapc-client.h	Mon Apr 10 15:49:24 2017 +0300
@@ -174,7 +174,9 @@
 void imapc_client_disconnect(struct imapc_client *client);
 void imapc_client_deinit(struct imapc_client **client);
 
-/* Set login callback, must be set before calling other commands */
+/* Set login callback, must be set before calling other commands.
+   This is called only for the first login, not for any reconnects or if there
+   are multiple connections created. */
 void
 imapc_client_set_login_callback(struct imapc_client *client,
 				imapc_command_callback_t *callback, void *context);
--- a/src/lib-imap-client/imapc-connection.c	Mon Apr 10 14:14:40 2017 +0300
+++ b/src/lib-imap-client/imapc-connection.c	Mon Apr 10 15:49:24 2017 +0300
@@ -179,13 +179,17 @@
 }
 
 struct imapc_connection *
-imapc_connection_init(struct imapc_client *client)
+imapc_connection_init(struct imapc_client *client,
+		      imapc_command_callback_t *login_callback,
+		      void *login_context)
 {
 	struct imapc_connection *conn;
 
 	conn = i_new(struct imapc_connection, 1);
 	conn->refcount = 1;
 	conn->client = client;
+	conn->login_callback = login_callback;
+	conn->login_context = login_context;
 	conn->fd = -1;
 	conn->name = i_strdup_printf("%s:%u", client->set.host,
 				     client->set.port);
@@ -345,15 +349,8 @@
 imapc_login_callback(struct imapc_connection *conn,
 		     const struct imapc_command_reply *reply)
 {
-	imapc_command_callback_t *login_callback = conn->login_callback;
-	void *login_context = conn->login_context;
-
-	if (login_callback == NULL)
-		return;
-
-	conn->login_callback = NULL;
-	conn->login_context = NULL;
-	login_callback(reply, login_context);
+	if (conn->login_callback != NULL)
+		conn->login_callback(reply, conn->login_context);
 }
 
 static void imapc_connection_set_state(struct imapc_connection *conn,
@@ -510,7 +507,7 @@
 		imapc_client_mailbox_reconnect(conn->selected_box);
 	else {
 		imapc_connection_disconnect_full(conn, TRUE);
-		imapc_connection_connect(conn, NULL, NULL);
+		imapc_connection_connect(conn);
 	}
 }
 
@@ -521,7 +518,7 @@
 	if (conn->prev_connect_idx + 1 < conn->ips_count) {
 		conn->reconnect_ok = TRUE;
 		imapc_connection_disconnect_full(conn, TRUE);
-		imapc_connection_connect(conn, NULL, NULL);
+		imapc_connection_connect(conn);
 		return;
 	}
 
@@ -1777,24 +1774,15 @@
 	imapc_connection_connect_next_ip(conn);
 }
 
-void imapc_connection_connect(struct imapc_connection *conn,
-			      imapc_command_callback_t *login_callback,
-			      void *login_context)
+void imapc_connection_connect(struct imapc_connection *conn)
 {
 	struct dns_lookup_settings dns_set;
 	struct ip_addr ip, *ips;
 	unsigned int ips_count;
 	int ret;
 
-	if (conn->fd != -1 || conn->dns_lookup != NULL) {
-		i_assert(login_callback == NULL);
+	if (conn->fd != -1 || conn->dns_lookup != NULL)
 		return;
-	}
-	i_assert(conn->login_callback == NULL || conn->reconnecting);
-	if (!conn->reconnecting) {
-		conn->login_callback = login_callback;
-		conn->login_context = login_context;
-	}
 	conn->reconnecting = FALSE;
 	/* if we get disconnected before we've finished all the pending
 	   commands, don't reconnect */
--- a/src/lib-imap-client/imapc-connection.h	Mon Apr 10 14:14:40 2017 +0300
+++ b/src/lib-imap-client/imapc-connection.h	Mon Apr 10 15:49:24 2017 +0300
@@ -26,12 +26,12 @@
 };
 
 struct imapc_connection *
-imapc_connection_init(struct imapc_client *client);
+imapc_connection_init(struct imapc_client *client,
+		      imapc_command_callback_t *login_callback,
+		      void *login_context);
 void imapc_connection_deinit(struct imapc_connection **conn);
 
-void imapc_connection_connect(struct imapc_connection *conn,
-			      imapc_command_callback_t *login_callback,
-			      void *login_context) ATTR_NULL(2, 3);
+void imapc_connection_connect(struct imapc_connection *conn);
 void imapc_connection_set_no_reconnect(struct imapc_connection *conn);
 void imapc_connection_disconnect(struct imapc_connection *conn);
 void imapc_connection_disconnect_full(struct imapc_connection *conn,