]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap(-login): Change imap_capability to boollist.
authorsergey.kitov <sergey.kitov@open-xchange.com>
Thu, 29 Aug 2024 09:51:10 +0000 (12:51 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Jan 2025 08:40:00 +0000 (10:40 +0200)
configure.ac
src/imap-login/Makefile.am
src/imap-login/imap-login-client.c
src/imap-login/imap-login-settings.c
src/imap-login/imap-login-settings.h
src/imap/imap-client.c
src/imap/imap-settings.c
src/imap/imap-settings.h
src/lib-settings/settings-parser.c

index 9408e1e931e8e5877f1636ae294381af09924f2a..ced65542bc846716e42bbc7e43f0f327be48fd71 100644 (file)
@@ -754,17 +754,6 @@ SETTING_LINKED_FILES=`echo $libdovecot_c_files | $SED -e s,$srcdir/src,./src,g -
 AC_SUBST(SETTING_FILES)
 AC_SUBST(SETTING_LINKED_FILES)
 
-dnl **
-dnl ** capabilities
-dnl **
-
-dnl IDLE doesn't really belong to banner. It's there just to make Blackberries
-dnl happy, because otherwise BIS server disables push email.
-capability_banner="IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE"
-capability="$capability_banner SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY PREVIEW STATUS=SIZE SAVEDATE COMPRESS=DEFLATE INPROGRESS${experimental_capabilities}"
-AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", [IMAP capabilities])
-AC_DEFINE_UNQUOTED(CAPABILITY_BANNER_STRING, "$capability_banner", [IMAP capabilities advertised in banner])
-
 CFLAGS="$CFLAGS $EXTRA_CFLAGS"
 CXXFLAGS="$CXXFLAGS $EXTRA_CFLAGS"
 BINARY_LDFLAGS="$PIE_LDFLAGS $RELRO_LDFLAGS"
index e69b8d47916d9e2669d4644e3fa2f65e559041b8..d58e3d062bfe9527368ec9dd8a0c63f26182e091 100644 (file)
@@ -12,6 +12,7 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib-imap \
        -I$(top_srcdir)/src/lib-master \
        -I$(top_srcdir)/src/lib-login \
+       -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/login-common \
        $(BINARY_CFLAGS)
 
index a3be3c0e71e11965dfb450456f466846d7447ec2..15ddd559b7abb3cfb8ad47f7425b1f6d0a6d8f1f 100644 (file)
@@ -21,6 +21,7 @@
 #include "imap-quote.h"
 #include "imap-login-commands.h"
 #include "imap-login-settings.h"
+#include "imap-util.h"
 
 #if LOGIN_MAX_INBUF_SIZE < 1024+2
 #  error LOGIN_MAX_INBUF_SIZE too short to fit all ID command parameters
@@ -89,24 +90,16 @@ static bool is_login_cmd_disabled(struct client *client)
        return FALSE;
 }
 
+static int imap_client_reload_config(struct client *client,
+                                    const char **error_r);
+
 static const char *get_capability(struct client *client)
 {
        struct imap_client *imap_client =
                container_of(client, struct imap_client, common);
        string_t *cap_str = t_str_new(256);
 
-       if (*imap_client->set->imap_capability == '\0')
-               str_append(cap_str, CAPABILITY_BANNER_STRING);
-       else {
-               str_append(cap_str, CAPABILITY_BANNER_STRING);
-               str_append_c(cap_str, ' ');
-               str_append(cap_str, imap_client->set->imap_capability + 1);
-       }
-
-       if (imap_client->set->imap_literal_minus)
-               str_append(cap_str, " LITERAL-");
-       else
-               str_append(cap_str, " LITERAL+");
+       imap_write_capability(cap_str, &imap_client->set->imap_capability);
 
        if (client_is_tls_enabled(client) && !client->connection_tls_secured &&
            !client->haproxy_terminated_tls)
@@ -390,9 +383,27 @@ static int imap_client_create(struct client *client)
                imap_parser_create(imap_client->common.input,
                                   imap_client->common.output,
                                   IMAP_LOGIN_MAX_LINE_LENGTH);
-       if (imap_client->set->imap_literal_minus)
+       struct settings_instance *set_instance = settings_instance_find(client->event);
+       if (set_instance == NULL) {
+               set_instance = settings_instance_new(
+                       master_service_get_settings_root(master_service));
+               event_set_ptr(client->event, SETTINGS_EVENT_INSTANCE, set_instance);
+       }
+
+       if (imap_client->set->imap_literal_minus) {
+               settings_override(set_instance,
+                                 "imap_capability/LITERAL+",
+                                 "no", SETTINGS_OVERRIDE_TYPE_CODE);
                imap_parser_enable_literal_minus(imap_client->parser);
+       } else
+               settings_override(set_instance,
+                                 "imap_capability/LITERAL-",
+                                 "no", SETTINGS_OVERRIDE_TYPE_CODE);
        client->io = io_add_istream(client->input, client_input, client);
+       if (imap_client_reload_config(client, &error) < 0) {
+               e_error(client->event, "%s", error);
+               return -1;
+       }
        return 0;
 }
 
index c26dc26198c963abc5eb2fb0c3ea20e921dbfc13..ba4e2dc3fdbaef84bd989306e724c498babb57e5 100644 (file)
@@ -51,7 +51,7 @@ const struct setting_keyvalue imap_login_service_settings_defaults[] = {
        SETTING_DEFINE_STRUCT_##type(#name, name, struct imap_login_settings)
 
 static const struct setting_define imap_login_setting_defines[] = {
-       DEF(STR, imap_capability),
+       DEF(BOOLLIST, imap_capability),
        DEF(BOOL, imap_literal_minus),
        DEF(BOOL, imap_id_retain),
 
@@ -62,13 +62,23 @@ static const struct setting_define imap_login_setting_defines[] = {
 };
 
 static const struct imap_login_settings imap_login_default_settings = {
-       .imap_capability = "",
+       .imap_capability = ARRAY_INIT,
        .imap_id_send = ARRAY_INIT,
        .imap_literal_minus = FALSE,
        .imap_id_retain = FALSE,
 };
 
 static const struct setting_keyvalue imap_login_default_settings_keyvalue[] = {
+       {"service/imap-login/imap_capability/IMAP4rev1", "yes"},
+       {"service/imap-login/imap_capability/LOGIN-REFERRALS", "yes"},
+       {"service/imap-login/imap_capability/ID", "yes"},
+       {"service/imap-login/imap_capability/ENABLE", "yes"},
+       /* IDLE doesn't really belong to banner. It's there just to make
+          Blackberries happy, because otherwise BIS server disables push email. */
+       { "service/imap-login/imap_capability/IDLE", "yes" },
+       { "service/imap-login/imap_capability/SASL-IR", "yes" },
+       { "service/imap-login/imap_capability/LITERAL+", "yes" },
+       { "service/imap-login/imap_capability/LITERAL-", "yes" },
        { "imap_id_send/name", DOVECOT_NAME },
        { NULL, NULL },
 };
index cfdf5b843e9573676b704b94065fd15ada44e6cf..3dd90ff237a0c307450d00d5d084dac3c5a6a7ad 100644 (file)
@@ -3,7 +3,7 @@
 
 struct imap_login_settings {
        pool_t pool;
-       const char *imap_capability;
+       ARRAY_TYPE(const_string) imap_capability;
        ARRAY_TYPE(const_string) imap_id_send;
        bool imap_literal_minus;
        bool imap_id_retain;
index 7e78e16ef9d34756ec2bf8f00e04ea52a32c29ba..186a86325322ce625ca28f64af007bc502f665cd 100644 (file)
@@ -85,6 +85,14 @@ static void client_init_urlauth(struct client *client)
        client->urlauth_ctx = imap_urlauth_init(client->user, &config);
 }
 
+static void
+imap_unset_capability(struct settings_instance *set_instance, const char *capability)
+{
+       settings_override(set_instance,
+                         t_strdup_printf("imap_capability/%s", capability),
+                         "no", SETTINGS_OVERRIDE_TYPE_CODE);
+}
+
 struct client *client_create(int fd_in, int fd_out,
                             enum client_create_flags flags,
                             struct event *event, struct mail_user *user,
@@ -138,30 +146,24 @@ struct client *client_create(int fd_in, int fd_out,
        client->notify_flag_changes = TRUE;
        p_array_init(&client->enabled_features, client->pool, 8);
 
-       client->capability_string =
-               str_new(client->pool, sizeof(CAPABILITY_STRING)+64);
-
-       if (*set->imap_capability == '\0')
-               str_append(client->capability_string, CAPABILITY_STRING);
-       else
-               str_append(client->capability_string, set->imap_capability);
+       struct settings_instance *set_instance =
+               mail_storage_service_user_get_settings_instance(
+                       client->user->service_user);
+       /* All capabilities are enabled by defaults.
+          Remove the capabilities here that can't work due current settings. */
        if (client->set->imap_literal_minus)
-               client_add_capability(client, "LITERAL-");
-       else
-               client_add_capability(client, "LITERAL+");
-       if (user->fuzzy_search) {
-               /* Enable FUZZY capability only when it actually has
-                  a chance of working */
-               client_add_capability(client, "SEARCH=FUZZY");
-       }
+               imap_unset_capability(set_instance, "LITERAL+");
+        else
+               imap_unset_capability(set_instance, "LITERAL-");
+       /* Enable FUZZY capability only when it actually has a chance of working */
+       if (!user->fuzzy_search)
+               imap_unset_capability(set_instance, "SEARCH=FUZZY");
 
        mail_set = mail_user_set_get_storage_set(user);
-       if (mail_set->mailbox_list_index) {
-               /* NOTIFY is enabled only when mailbox list indexes are
-                  enabled, although even that doesn't necessarily guarantee
-                  it always */
-               client_add_capability(client, "NOTIFY");
-       }
+       /* NOTIFY is enabled only when mailbox list indexes are enabled,
+          althoaugh even that doesn't necessarily guarantee it always */
+       if (!mail_set->mailbox_list_index)
+               imap_unset_capability(set_instance, "NOTIFY");
 
        const char *error;
        int ret = mailbox_attribute_dict_is_enabled(user, &error);
@@ -169,19 +171,30 @@ struct client *client_create(int fd_in, int fd_out,
                client->init_error = p_strdup(user->pool, error);
        bool have_mailbox_attribute_dict = ret > 0;
 
-       if (*set->imap_urlauth_host != '\0' && have_mailbox_attribute_dict) {
-               /* Enable URLAUTH capability only when dict is
-                  configured correctly */
+       /* Enable URLAUTH capability only when dict is configured correctly */
+       if (*set->imap_urlauth_host != '\0' && have_mailbox_attribute_dict)
                client_init_urlauth(client);
-               client_add_capability(client, "URLAUTH");
-               client_add_capability(client, "URLAUTH=BINARY");
-       }
-       if (set->imap_metadata && have_mailbox_attribute_dict)
-               client_add_capability(client, "METADATA");
-       if (user->have_special_use_mailboxes) {
-               /* Advertise SPECIAL-USE only if there are actually some
-                  SPECIAL-USE flags in mailbox configuration. */
-               client_add_capability(client, "SPECIAL-USE");
+       else {
+               imap_unset_capability(set_instance, "URLAUTH");
+               imap_unset_capability(set_instance, "URLAUTH=BINARY");
+       }
+       if (!set->imap_metadata || !have_mailbox_attribute_dict)
+               imap_unset_capability(set_instance, "METADATA");
+       /* Advertise SPECIAL-USE only if there are actually some
+          SPECIAL-USE flags in mailbox configuration. */
+       if (!user->have_special_use_mailboxes)
+               imap_unset_capability(set_instance, "SPECIAL-USE");
+
+       const struct imap_settings *modified_set;
+       if (settings_get(client->user->event, &imap_setting_parser_info,
+                        0, &modified_set, &error) < 0) {
+               if (client->init_error == NULL)
+                       client->init_error = p_strdup(user->pool, error);
+       } else {
+               client->capability_string = str_new(client->pool, 256);
+               imap_write_capability(client->capability_string,
+                                     &modified_set->imap_capability);
+               settings_free(modified_set);
        }
 
        struct master_service_anvil_session anvil_session;
@@ -590,8 +603,7 @@ void client_add_capability(struct client *client, const char *capability)
 {
        /* require a single capability at a time (feels cleaner) */
        i_assert(strchr(capability, ' ') == NULL);
-
-       if (client->set->imap_capability[0] != '\0') {
+       if (settings_boollist_is_stopped(&client->set->imap_capability)) {
                /* explicit capability - don't change it */
                return;
        }
index eb8610ccd8139cb39aa4a998b266586c2d35ba33..04191d8dafefa539e488752e08e9f12bf30dc9ff 100644 (file)
@@ -61,7 +61,7 @@ static const struct setting_define imap_setting_defines[] = {
 
        DEF(SIZE_HIDDEN, imap_max_line_length),
        DEF(TIME_HIDDEN, imap_idle_notify_interval),
-       DEF(STR, imap_capability),
+       DEF(BOOLLIST, imap_capability),
        DEF(BOOLLIST, imap_client_workarounds),
        DEF(STR_NOVARS, imap_logout_format),
        DEF(ENUM, imap_fetch_failure),
@@ -89,7 +89,7 @@ static const struct imap_settings imap_default_settings = {
           liberal by default. */
        .imap_max_line_length = 64*1024,
        .imap_idle_notify_interval = 2*60,
-       .imap_capability = "",
+       .imap_capability = ARRAY_INIT,
        .imap_client_workarounds = ARRAY_INIT,
        .imap_logout_format = "in=%i out=%o deleted=%{deleted} "
                "expunged=%{expunged} trashed=%{trashed} "
@@ -110,6 +110,48 @@ static const struct imap_settings imap_default_settings = {
 };
 
 static const struct setting_keyvalue imap_default_settings_keyvalue[] = {
+       { "service/imap/imap_capability/IMAP4rev1", "yes" },
+       { "service/imap/imap_capability/SASL-IR", "yes" },
+       { "service/imap/imap_capability/LOGIN-REFERRALS", "yes" },
+       { "service/imap/imap_capability/ID", "yes" },
+       { "service/imap/imap_capability/ENABLE", "yes" },
+       { "service/imap/imap_capability/IDLE", "yes" },
+       { "service/imap/imap_capability/SORT", "yes" },
+       { "service/imap/imap_capability/SORT=DISPLAY", "yes" },
+       { "service/imap/imap_capability/THREAD=REFERENCES", "yes" },
+       { "service/imap/imap_capability/THREAD=REFS", "yes" },
+       { "service/imap/imap_capability/THREAD=ORDEREDSUBJECT", "yes" },
+       { "service/imap/imap_capability/MULTIAPPEND", "yes" },
+       { "service/imap/imap_capability/URL-PARTIAL", "yes" },
+       { "service/imap/imap_capability/CATENATE", "yes" },
+       { "service/imap/imap_capability/UNSELECT", "yes" },
+       { "service/imap/imap_capability/CHILDREN", "yes" },
+       { "service/imap/imap_capability/NAMESPACE", "yes" },
+       { "service/imap/imap_capability/UIDPLUS", "yes" },
+       { "service/imap/imap_capability/LIST-EXTENDED", "yes" },
+       { "service/imap/imap_capability/I18NLEVEL=1", "yes" },
+       { "service/imap/imap_capability/CONDSTORE", "yes" },
+       { "service/imap/imap_capability/QRESYNC", "yes" },
+       { "service/imap/imap_capability/ESEARCH", "yes" },
+       { "service/imap/imap_capability/ESORT", "yes" },
+       { "service/imap/imap_capability/SEARCHRES", "yes" },
+       { "service/imap/imap_capability/WITHIN", "yes" },
+       { "service/imap/imap_capability/CONTEXT=SEARCH", "yes" },
+       { "service/imap/imap_capability/LIST-STATUS", "yes" },
+       { "service/imap/imap_capability/BINARY", "yes" },
+       { "service/imap/imap_capability/MOVE", "yes" },
+       { "service/imap/imap_capability/SNIPPET=FUZZY", "yes" },
+       { "service/imap/imap_capability/PREVIEW=FUZZY", "yes" },
+       { "service/imap/imap_capability/PREVIEW", "yes" },
+       { "service/imap/imap_capability/STATUS=SIZE", "yes" },
+       { "service/imap/imap_capability/SAVEDATE", "yes" },
+       { "service/imap/imap_capability/COMPRESS=DEFLATE", "yes" },
+       { "service/imap/imap_capability/INPROGRESS", "yes" },
+       { "service/imap/imap_capability/NOTIFY", "yes" },
+       { "service/imap/imap_capability/METADATA", "yes" },
+       { "service/imap/imap_capability/SPECIAL-USE", "yes" },
+       { "service/imap/imap_capability/LITERAL+", "yes" },
+       { "service/imap/imap_capability/LITERAL-", "yes" },
        { "imap_id_send/name", DOVECOT_NAME },
        { NULL, NULL },
 };
index e78a49bf95753d26f1c4ebe098633758a685ae77..90203bc482cd0c0add32e3e100fe6755385c79bd 100644 (file)
@@ -27,7 +27,7 @@ struct imap_settings {
        /* imap: */
        uoff_t imap_max_line_length;
        unsigned int imap_idle_notify_interval;
-       const char *imap_capability;
+       ARRAY_TYPE(const_string) imap_capability;
        ARRAY_TYPE(const_string) imap_client_workarounds;
        const char *imap_logout_format;
        const char *imap_fetch_failure;
index 244730d4e4b0218e2ec6f04c21fb3f467192f236..fe4623693b0e29ac12300c8281036a3075bee6ad 100644 (file)
@@ -519,12 +519,9 @@ bool settings_boollist_is_stopped(const ARRAY_TYPE(const_string) *array)
        /* The first element after the visible array is NULL. If the next element
           after the NULL is set_array_stop, then the boollist is stopped. */
        unsigned int count;
-       const char *const *values =
-               array_get(array, &count);
+       const char *const *values = array_get(array, &count);
        i_assert(values[count] == NULL);
-       if (values[count + 1] == set_array_stop)
-               return TRUE;
-       return FALSE;
+       return values[count + 1] == set_array_stop;
 }
 
 static int