]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-imap-client: Fix hang when imapc_client_get_capabilities() is called without...
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 8 Jun 2017 17:39:47 +0000 (20:39 +0300)
committerGitLab <gitlab@git.dovecot.net>
Mon, 12 Jun 2017 12:21:17 +0000 (15:21 +0300)
src/lib-imap-client/imapc-client-private.h
src/lib-imap-client/imapc-client.c
src/lib-imap-client/imapc-connection.c
src/lib-imap-client/test-imapc-client.c

index 96e780a5fecfb21792b87480cdaa31328b777c77..f03631bc270c22e314801461f0744faefe472164 100644 (file)
@@ -31,6 +31,7 @@ struct imapc_client {
        bool logging_out;
 
        struct ioloop *ioloop;
+       bool stop_on_state_finish;
 };
 
 struct imapc_client_mailbox {
index 3e4020e7247c1364c46a2863f1740d345c03bde3..e5487d89903dd69710b336433778329c922e4829 100644 (file)
@@ -530,7 +530,9 @@ int imapc_client_get_capabilities(struct imapc_client *client,
                (void)imapc_client_add_connection(client);
 
        /* wait for any of the connections to login */
+       client->stop_on_state_finish = TRUE;
        imapc_client_run(client);
+       client->stop_on_state_finish = FALSE;
        if (imapc_client_get_any_capabilities(client, capabilities_r))
                return 0;
 
index 835aac616c0c898456147973f27a8bb97aad0152..f1b34da6cf3837fe619cffaca72de05526306bf2 100644 (file)
@@ -386,6 +386,12 @@ static void imapc_connection_set_state(struct imapc_connection *conn,
 
                conn->selecting_box = NULL;
                conn->selected_box = NULL;
+               /* fall through */
+       case IMAPC_CONNECTION_STATE_DONE:
+               /* if we came from imapc_client_get_capabilities(), stop so
+                  it can finish up and not just hang indefinitely. */
+               if (conn->client->stop_on_state_finish && !conn->reconnecting)
+                       imapc_client_stop(conn->client);
                break;
        default:
                break;
index 69bd865c84c8348d20c1841ae5f0d7ab630811c5..b2f405b517e75e62a24e8398f3075cc450d2d172 100644 (file)
@@ -81,7 +81,7 @@ test_server_wait_connection(struct test_server *server, bool send_banner)
 
        if (send_banner) {
                o_stream_nsend_str(server->output,
-                       "* OK [CAPABILITY IMAP4rev1] ready\r\n");
+                       "* OK [CAPABILITY IMAP4rev1 UNSELECT QUOTA] ready\r\n");
        }
 }
 
@@ -584,6 +584,101 @@ static void test_imapc_reconnect_mailbox(void)
        test_end();
 }
 
+static void test_imapc_client_get_capabilities_client(void)
+{
+       enum imapc_capability capabilities;
+
+       test_assert(imapc_client_get_capabilities(imapc_client, &capabilities) == 0);
+       test_assert(capabilities == (IMAPC_CAPABILITY_IMAP4REV1 |
+                                    IMAPC_CAPABILITY_UNSELECT |
+                                    IMAPC_CAPABILITY_QUOTA));
+}
+
+static void test_imapc_client_get_capabilities_server(void)
+{
+       test_server_wait_connection(&server, TRUE);
+       test_assert(test_imapc_server_expect("1 LOGIN \"testuser\" \"testpass\""));
+       o_stream_nsend_str(server.output, "1 OK \r\n");
+
+       test_assert(test_imapc_server_expect("2 LOGOUT"));
+       o_stream_nsend_str(server.output, "2 OK \r\n");
+
+       test_assert(i_stream_read_next_line(server.input) == NULL);
+}
+
+static void test_imapc_client_get_capabilities(void)
+{
+       struct imapc_client_settings set = test_imapc_default_settings;
+
+       test_begin("imapc_client_get_capabilities()");
+       test_run_client_server(&set, test_imapc_client_get_capabilities_client,
+                              test_imapc_client_get_capabilities_server);
+       test_end();
+}
+
+static void test_imapc_client_get_capabilities_reconnected_client(void)
+{
+       enum imapc_capability capabilities;
+
+       test_expect_errors(2);
+       test_assert(imapc_client_get_capabilities(imapc_client, &capabilities) == 0);
+       test_assert(capabilities == (IMAPC_CAPABILITY_IMAP4REV1 |
+                                    IMAPC_CAPABILITY_UNSELECT |
+                                    IMAPC_CAPABILITY_QUOTA));
+       test_expect_no_more_errors();
+}
+
+static void test_imapc_client_get_capabilities_reconnected_server(void)
+{
+       test_server_wait_connection(&server, TRUE);
+       test_server_disconnect_and_wait(TRUE);
+
+       test_assert(test_imapc_server_expect("2 LOGIN \"testuser\" \"testpass\""));
+       o_stream_nsend_str(server.output, "2 OK \r\n");
+
+       test_assert(test_imapc_server_expect("3 LOGOUT"));
+       o_stream_nsend_str(server.output, "3 OK \r\n");
+
+       test_assert(i_stream_read_next_line(server.input) == NULL);
+}
+
+static void test_imapc_client_get_capabilities_reconnected(void)
+{
+       struct imapc_client_settings set = test_imapc_default_settings;
+
+       test_begin("imapc_client_get_capabilities() reconnected");
+
+       test_run_client_server(&set, test_imapc_client_get_capabilities_reconnected_client,
+                              test_imapc_client_get_capabilities_reconnected_server);
+       test_end();
+}
+
+static void test_imapc_client_get_capabilities_disconnected_client(void)
+{
+       enum imapc_capability capabilities;
+
+       test_expect_errors(4);
+       test_assert(imapc_client_get_capabilities(imapc_client, &capabilities) < 0);
+       test_expect_no_more_errors();
+}
+
+static void test_imapc_client_get_capabilities_disconnected_server(void)
+{
+       test_server_wait_connection(&server, TRUE);
+       test_server_disconnect_and_wait(TRUE);
+}
+
+static void test_imapc_client_get_capabilities_disconnected(void)
+{
+       struct imapc_client_settings set = test_imapc_default_settings;
+
+       test_begin("imapc_client_get_capabilities() disconnected");
+
+       test_run_client_server(&set, test_imapc_client_get_capabilities_disconnected_client,
+                              test_imapc_client_get_capabilities_disconnected_server);
+       test_end();
+}
+
 int main(int argc ATTR_UNUSED, char *argv[])
 {
        static void (*const test_functions[])(void) = {
@@ -594,6 +689,9 @@ int main(int argc ATTR_UNUSED, char *argv[])
                test_imapc_reconnect_resend_commands,
                test_imapc_reconnect_resend_commands_failed,
                test_imapc_reconnect_mailbox,
+               test_imapc_client_get_capabilities,
+               test_imapc_client_get_capabilities_reconnected,
+               test_imapc_client_get_capabilities_disconnected,
                NULL
        };