From: Markus Valentin Date: Tue, 13 May 2025 11:36:28 +0000 (+0200) Subject: imapc: Automatically enable IMAP4rev2 if server has the capability X-Git-Tag: 2.4.2~722 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7ed88b8e0318aa9153a38bddd038388ac5a36022;p=thirdparty%2Fdovecot%2Fcore.git imapc: Automatically enable IMAP4rev2 if server has the capability --- diff --git a/src/lib-imap-client/imapc-connection.c b/src/lib-imap-client/imapc-connection.c index a9a49a52a0..7b43a65d80 100644 --- a/src/lib-imap-client/imapc-connection.c +++ b/src/lib-imap-client/imapc-connection.c @@ -156,6 +156,7 @@ struct imapc_connection { bool idling:1; bool idle_stopping:1; bool idle_plus_waiting:1; + bool imap4rev2_enabled:1; bool select_waiting_reply:1; /* TRUE if IMAP server is in SELECTED state. select_box may be NULL though, if we already closed the mailbox from client point of @@ -753,6 +754,30 @@ imapc_connection_read_line(struct imapc_connection *conn, return ret; } +static void +imapc_connection_imap4rev2_enable_callback(const struct imapc_command_reply *reply ATTR_UNUSED, + void *context) +{ + struct imapc_connection *conn = context; + + if (reply->state == IMAPC_COMMAND_STATE_OK) + conn->imap4rev2_enabled = TRUE; +} + +static void imapc_connection_send_enable_imap4rev2(struct imapc_connection *conn) +{ + struct imapc_command *cmd; + + if ((conn->capabilities & IMAPC_CAPABILITY_IMAP4REV2) == 0 || + conn->imap4rev2_enabled) + return; + + cmd = imapc_connection_cmd(conn, + imapc_connection_imap4rev2_enable_callback, + conn); + imapc_command_send(cmd, "ENABLE IMAP4REV2"); +} + static int imapc_connection_parse_capability(struct imapc_connection *conn, const char *value) @@ -907,6 +932,9 @@ imapc_connection_auth_finish(struct imapc_connection *conn, imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DONE); imapc_login_callback(conn, reply); + /* Enable IMAP4REV2 post login, if available */ + imapc_connection_send_enable_imap4rev2(conn); + imapc_command_send_more(conn); } diff --git a/src/lib-imap-client/test-imapc-client.c b/src/lib-imap-client/test-imapc-client.c index 2ddb88b87b..e8ca2be8bd 100644 --- a/src/lib-imap-client/test-imapc-client.c +++ b/src/lib-imap-client/test-imapc-client.c @@ -162,7 +162,7 @@ static bool test_imapc_server_expect(const char *expected_line) } static void -test_server_wait_connection(struct test_server *server, bool send_banner) +test_server_wait_connection_common(struct test_server *server) { if (debug) i_debug("Waiting for connection"); @@ -177,13 +177,31 @@ test_server_wait_connection(struct test_server *server, bool send_banner) server->input = i_stream_create_fd(server->fd, SIZE_MAX); server->output = o_stream_create_fd(server->fd, SIZE_MAX); o_stream_set_no_error_handling(server->output, TRUE); +} +static void +test_server_wait_connection(struct test_server *server, bool send_banner) +{ + test_server_wait_connection_common(server); if (send_banner) { o_stream_nsend_str(server->output, "* OK [CAPABILITY IMAP4rev1 UNSELECT QUOTA] ready\r\n"); } } +#ifdef EXPERIMENTAL_IMAP4REV2 +static void +test_server_wait_connection_imap4rev2(struct test_server *server, bool send_banner) +{ + test_server_wait_connection_common(server); + + if (send_banner) { + o_stream_nsend_str(server->output, + "* OK [CAPABILITY IMAP4rev1 IMAP4rev2 UNSELECT QUOTA QRESYNC CONDSTORE] ready\r\n"); + } +} +#endif + static void test_server_disconnect(struct test_server *server) { if (debug) @@ -847,6 +865,51 @@ static void test_imapc_client_get_capabilities_disconnected(void) test_end(); } +#ifdef EXPERIMENTAL_IMAP4REV2 +/* + * imapc_client_get_capabilities_imap4rev2() + */ + +static void test_imapc_client_get_capabilities_imap4rev2_client(void) +{ + enum imapc_capability capabilities; + + test_assert(imapc_client_get_capabilities(imapc_client, &capabilities) == 0); + test_assert(capabilities == (IMAPC_CAPABILITY_IMAP4REV1 | + IMAPC_CAPABILITY_IMAP4REV2 | + IMAPC_CAPABILITY_QRESYNC | + IMAPC_CAPABILITY_CONDSTORE | + IMAPC_CAPABILITY_UNSELECT | + IMAPC_CAPABILITY_QUOTA)); +} + +static void test_imapc_client_get_capabilities_imap4rev2_server(void) +{ + test_server_wait_connection_imap4rev2(&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 ENABLE IMAP4REV2")); + o_stream_nsend_str(server.output, "2 OK ENABLED\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_imap4rev2(void) +{ + test_begin("imapc_client_get_capabilities_imap4rev2()"); + test_run_client_server(test_imapc_client_get_capabilities_imap4rev2_client, + test_imapc_client_get_capabilities_imap4rev2_server, + FALSE); + test_end(); +} +#endif + /* * Main */ @@ -878,6 +941,9 @@ int main(int argc ATTR_UNUSED, char *argv[]) test_imapc_client_get_capabilities, test_imapc_client_get_capabilities_reconnected, test_imapc_client_get_capabilities_disconnected, +#ifdef EXPERIMENTAL_IMAP4REV2 + test_imapc_client_get_capabilities_imap4rev2, +#endif NULL };