]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Replace BROKENCHAR with mailbox_list_visible_escape_char setting
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Fri, 27 Oct 2023 21:04:39 +0000 (00:04 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 12 Feb 2025 10:34:11 +0000 (12:34 +0200)
12 files changed:
src/doveadm/doveadm-dsync.c
src/doveadm/dsync/dsync-brain-mailbox-tree.c
src/doveadm/dsync/dsync-mailbox-tree-fill.c
src/lib-storage/index/imapc/imapc-list.c
src/lib-storage/index/imapc/imapc-settings.c
src/lib-storage/index/imapc/imapc-storage.c
src/lib-storage/index/imapc/imapc-storage.h
src/lib-storage/mail-storage-settings.c
src/lib-storage/mail-storage-settings.h
src/lib-storage/mailbox-list.c
src/lib-storage/mailbox-list.h
src/lib-storage/test-mailbox-list.c

index bc7091ee5a62782d18630102553740fb003c0755..7a7fc3795bc660a861bbfc015609d38342019336 100644 (file)
 #include <sys/wait.h>
 
 #define DSYNC_REMOTE_CMD_EXIT_WAIT_SECS 30
-/* The default vname_escape_char to use unless overridden by BROKENCHAR
-   setting. Note that it's only used for internal dsync names, so it won't end
-   up in permanent storage names. The only requirement for it is that it's not
-   the same as the hierarchy separator. */
+/* The default vname_escape_char to use unless overridden by
+   mailbox_list_visible_escape_char setting. Note that it's only used for
+   internal dsync names, so it won't end up in permanent storage names. The
+   only requirement for it is that it's not the same as the hierarchy
+   separator. */
 #define DSYNC_LIST_VNAME_ESCAPE_CHAR '%'
 /* In case DSYNC_LIST_VNAME_ESCAPE_CHAR is the hierarchy separator,
    use this instead. */
@@ -367,6 +368,17 @@ static bool mirror_get_remote_cmd(struct dsync_cmd_context *ctx,
        return TRUE;
 }
 
+static void
+doveadm_update_escape_char(struct mail_namespace *ns, char ns_sep)
+{
+       const struct mail_storage_settings *old_set = ns->list->mail_set;
+       struct mail_storage_settings *new_set =
+               p_memdup(old_set->pool, old_set, sizeof(*old_set));
+       new_set->mailbox_list_visible_escape_char =
+               p_strdup_printf(old_set->pool, "%c", ns_sep);
+       ns->list->mail_set = new_set;
+}
+
 static void doveadm_user_init_dsync(struct mail_user *user)
 {
        struct mail_namespace *ns;
@@ -378,11 +390,11 @@ static void doveadm_user_init_dsync(struct mail_user *user)
                        p_new(ns->list->pool, struct dsync_mailbox_list, 1);
                MODULE_CONTEXT_SET(ns->list, dsync_mailbox_list_module, dlist);
 
-               if (ns->list->set.vname_escape_char == '\0') {
-                       ns->list->set.vname_escape_char =
+               if (ns->list->mail_set->mailbox_list_visible_escape_char[0] == '\0') {
+                       doveadm_update_escape_char(ns,
                                ns_sep != DSYNC_LIST_VNAME_ESCAPE_CHAR ?
                                DSYNC_LIST_VNAME_ESCAPE_CHAR :
-                               DSYNC_LIST_VNAME_ALT_ESCAPE_CHAR;
+                               DSYNC_LIST_VNAME_ALT_ESCAPE_CHAR);
                } else {
                        dlist->have_orig_escape_char = TRUE;
                }
@@ -484,8 +496,10 @@ cmd_dsync_run_local(struct dsync_cmd_context *ctx, struct mail_user *user,
        if (mail_namespace_get_sep(ns) != mail_namespace_get_sep(ns2)) {
                e_error(ctx->ctx.cctx->event,
                        "Mail locations must use the same hierarchy separator "
-                       "(specify namespace %s { separator } explicitly)",
-                       ns->set->name);
+                       "(specify namespace %s { separator=%c } != "
+                       "namespace %s { separator=%c })",
+                       ns->set->name, mail_namespace_get_sep(ns),
+                       ns2->set->name, mail_namespace_get_sep(ns2));
                ctx->ctx.exit_code = EX_CONFIG;
                mail_user_deinit(&user2);
                return -1;
index 384e472b5d98a7e050c3e166709e62302aeb99c4..6b94429c62093c710c410a074581bc987a10bdaa 100644 (file)
@@ -23,7 +23,7 @@ static void dsync_brain_check_namespaces(struct dsync_brain *brain)
                        continue;
 
                sep = mail_namespace_get_sep(ns);
-               escape_char = mailbox_list_get_settings(ns->list)->vname_escape_char;
+               escape_char = ns->list->mail_set->mailbox_list_visible_escape_char[0];
                if (first_ns == NULL) {
                        brain->hierarchy_sep = sep;
                        brain->escape_char = escape_char;
index 8ef09913a62c8ef8de088c6492990acf3f767971..140f765365d6705cd6d5315b74ccc7bd6423e0db 100644 (file)
@@ -19,7 +19,7 @@ dsync_mailbox_tree_name_unescape(struct mail_namespace *ns,
 {
        const char ns_sep = mail_namespace_get_sep(ns);
        const char escape_char =
-               mailbox_list_get_settings(ns->list)->vname_escape_char;
+               ns->list->mail_set->mailbox_list_visible_escape_char[0];
        const char *const *old_vname_parts =
                dsync_mailbox_name_to_parts(old_vname, ns_sep, escape_char);
 
index 827e6151ddba570a47a92dca2210ef06833a879c..43c181be51709526a965e45f0ea781a7246c13cf 100644 (file)
@@ -9,7 +9,7 @@
     - namespace separator = ':'
     - fs_list separator = '.'
     - mailbox_list storage_name_escape_char = '+'
-    - mailbox_list vname_escape_char = '~'
+    - mailbox_list mailbox_list_visible_escape_char = '~'
     - fs_list storage_name_escape_char = '%'
 
    remote_name = "prefix/~foo/bar^baz+_%_."
@@ -19,7 +19,7 @@
     - storage_name_escape character + is escaped as +2b
    vname = "~7efoo:bar.baz+_%_."
     - imapc_list_prefix is dropped
-    - vname_escape_character ~ is escaped into ~7e
+    - mailbox_list_visible_escape_char ~ is escaped into ~7e
     - separator is changed from ^ to :
     - storage_name_escape_characters are unescaped
    fs_name = "prefix.~foo.bar^baz+_%25_%2e"
index b6288f48ec2b584933d45fd6e98614af17ced541..0d50b14e4bed0a8e5a492fa79b5198031bd81b0c 100644 (file)
@@ -13,6 +13,7 @@ static bool imapc_settings_check(void *_set, pool_t pool, const char **error_r);
 
 static const struct setting_define imapc_setting_defines[] = {
        { .type = SET_FILTER_NAME, .key = "imapc" },
+       { .type = SET_FILTER_NAME, .key = "layout_imapc" },
        DEF(STR, imapc_host),
        DEF(IN_PORT, imapc_port),
 
@@ -64,6 +65,9 @@ static const struct imapc_settings imapc_default_settings = {
 
 static const struct setting_keyvalue imapc_default_filter_settings_keyvalue[] = {
        { "imapc/mailbox_list_layout", "imapc" },
+       /* We want to have all imapc mailboxes accessible, so escape them if
+          necessary. */
+       { "layout_imapc/mailbox_list_visible_escape_char", "~" },
        { NULL, NULL }
 };
 
index eb498e525e65adef1959c9e5c0cda96a2e4d9973..0725efa3beff135fa5740f8b0814bfb06ed8ab4c 100644 (file)
@@ -519,10 +519,6 @@ imapc_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
                                const struct mail_storage_settings *mail_set ATTR_UNUSED)
 {
        set->storage_name_escape_char = IMAPC_LIST_STORAGE_NAME_ESCAPE_CHAR;
-       /* We want to have all imapc mailboxes accessible, so escape them if
-          necessary. */
-       if (set->vname_escape_char == '\0')
-               set->vname_escape_char = IMAPC_LIST_VNAME_ESCAPE_CHAR;
 }
 
 static struct mailbox *
index d9949ba70093d3ee0863030c0ee12268f3b6eda3..ba8a35a72aa34d595160abd7194749b0a5b448d1 100644 (file)
@@ -10,8 +10,6 @@
 #define IMAPC_LIST_STORAGE_NAME_ESCAPE_CHAR '%'
 /* fs_name separator */
 #define IMAPC_LIST_FS_NAME_ESCAPE_CHAR '%'
-/* vname separator */
-#define IMAPC_LIST_VNAME_ESCAPE_CHAR '~'
 
 struct imap_arg;
 struct imapc_untagged_reply;
index ace29d83bacc498b1ff3ab6a7d6264ef6dd280a0..9d667eac063f948a7c52abccc1577d11b1d3803e 100644 (file)
@@ -81,6 +81,7 @@ static const struct setting_define mail_storage_setting_defines[] = {
        DEF(BOOL_HIDDEN, mailbox_list_iter_from_index_dir),
        DEF(BOOL_HIDDEN, mailbox_list_drop_noselect),
        DEF(BOOL_HIDDEN, mailbox_list_validate_fs_names),
+       DEF(STR, mailbox_list_visible_escape_char),
        DEF(STR_HIDDEN, mailbox_root_directory_name),
        DEF(STR_HIDDEN, mailbox_subscriptions_filename),
        DEF(STR, mail_index_path),
@@ -155,6 +156,7 @@ const struct mail_storage_settings mail_storage_default_settings = {
        .mailbox_list_iter_from_index_dir = FALSE,
        .mailbox_list_drop_noselect = TRUE,
        .mailbox_list_validate_fs_names = TRUE,
+       .mailbox_list_visible_escape_char = "",
        .mailbox_root_directory_name = "",
        .mailbox_subscriptions_filename = "subscriptions",
        .mail_index_path = "",
@@ -769,6 +771,12 @@ mail_storage_settings_ext_check(struct event *event, void *_set, pool_t pool,
                        set->mailbox_root_directory_name, "/", NULL);
        }
 
+       if (set->mailbox_list_visible_escape_char != set_value_unknown &&
+           strlen(set->mailbox_list_visible_escape_char) > 1) {
+               *error_r = "mailbox_list_visible_escape_char value must be a single character";
+               return FALSE;
+       }
+
        if (!mail_storage_settings_check_namespaces(event, set, error_r))
                return FALSE;
        return TRUE;
@@ -1016,6 +1024,7 @@ static const size_t mail_storage_2nd_reset_offsets[] = {
        OFFSET(mailbox_list_layout),
        OFFSET(mailbox_list_index_prefix),
        OFFSET(mailbox_list_iter_from_index_dir),
+       OFFSET(mailbox_list_visible_escape_char),
        OFFSET(mailbox_root_directory_name),
        OFFSET(mailbox_subscriptions_filename),
        OFFSET(mail_index_path),
index 05b8f0c6e7524ab5c60d07bc4bb73e6aff6fdd17..aca2ebb8a36be1aafabaecb1943eadcb84a53cc4 100644 (file)
@@ -64,6 +64,7 @@ struct mail_storage_settings {
        bool mailbox_list_iter_from_index_dir;
        bool mailbox_list_drop_noselect;
        bool mailbox_list_validate_fs_names;
+       const char *mailbox_list_visible_escape_char;
        const char *mailbox_root_directory_name;
        const char *mailbox_subscriptions_filename;
        const char *mail_index_path;
index e81b8858f82a4712b30934c575cc8bad3773d5bf..ea346673affffcff3e1f92347637e58e2abbba87 100644 (file)
@@ -160,7 +160,6 @@ int mailbox_list_create(struct event *event, struct mail_namespace *ns,
 
        if (set->storage_name_escape_char != '\0')
                list->set.storage_name_escape_char = set->storage_name_escape_char;
-       list->set.vname_escape_char = set->vname_escape_char;
        list->set.utf8 = set->utf8;
 
        if (list->v.init != NULL) {
@@ -290,13 +289,6 @@ mailbox_list_settings_parse_full(struct mail_user *user, const char *data,
                else if (strcmp(key, "FULLDIRNAME") == 0) {
                        set_r->index_control_use_maildir_name = TRUE;
                        dest = &set_r->maildir_name;
-               } else if (strcmp(key, "BROKENCHAR") == 0) {
-                       if (strlen(value) != 1) {
-                               *error_r = "BROKENCHAR value must be a single character";
-                               return -1;
-                       }
-                       set_r->vname_escape_char = value[0];
-                       continue;
                } else {
                        *error_r = t_strdup_printf("Unknown setting: %s", key);
                        return -1;
@@ -506,13 +498,13 @@ mailbox_list_default_get_storage_name_part(struct mailbox_list *list,
                /* UTF-8 -> mUTF-7 conversion */
                str = t_str_new(strlen(storage_name)*2);
                if (imap_escaped_utf8_to_utf7(storage_name,
-                                             list->set.vname_escape_char,
-                                             str) < 0)
+                               list->mail_set->mailbox_list_visible_escape_char[0],
+                               str) < 0)
                        i_panic("Mailbox name not UTF-8: %s", vname_part);
                storage_name = str_c(str);
-       } else if (list->set.vname_escape_char != '\0') {
+       } else if (list->mail_set->mailbox_list_visible_escape_char[0] != '\0') {
                mailbox_list_name_unescape(&storage_name,
-                                          list->set.vname_escape_char);
+                       list->mail_set->mailbox_list_visible_escape_char[0]);
        }
        if (list->set.storage_name_escape_char != '\0') {
                storage_name = mailbox_list_escape_name_params(storage_name,
@@ -654,7 +646,7 @@ mailbox_list_default_get_vname_part(struct mailbox_list *list,
 {
        const char *vname = storage_name_part;
        char escape_chars[] = {
-               list->set.vname_escape_char,
+               list->mail_set->mailbox_list_visible_escape_char[0],
                mail_namespace_get_sep(list->ns),
                '\0'
        };
@@ -679,7 +671,7 @@ mailbox_list_default_get_vname_part(struct mailbox_list *list,
                           can't be accessible, so just return it as the
                           original mUTF7 name. */
                }
-       } else if (list->set.vname_escape_char != '\0') {
+       } else if (list->mail_set->mailbox_list_visible_escape_char[0] != '\0') {
                string_t *str = t_str_new(strlen(vname));
                mailbox_list_name_escape(vname, escape_chars, str);
                vname = str_c(str);
index 040f00872c0575e2a2ccb90182578a916fb7f5ba..414cc5c02ecafb021e9da5e2f29250c3e90712d9 100644 (file)
@@ -139,17 +139,6 @@ struct mailbox_list_settings {
           { vname="A/B.C%D", storage_name_escape_char='%', namespace_sep='/',
           storage_sep='.' } -> storage_name="A.B%2eC%25D". */
        char storage_name_escape_char;
-       /* Used for escaping the user/client-visible UTF-8 vname. If the
-          storage_name can't be converted reversibly to the vname and back,
-          encode the problematic parts using <vname_escape_char><hex>. The
-          vname_escape_char itself also has to be encoded the same way. For
-          example { storage_name="A/B.C%D", vname_escape_char='%',
-          namespace_sep='/', storage_sep='.' } -> vname="A%2fB/C%25D".
-
-          Note that it's possible for escape_char and broken_char to be the
-          same character. They're just used for different directions in
-          conversion. */
-       char vname_escape_char;
        /* Use UTF-8 mailbox names on filesystem instead of mUTF-7 */
        bool utf8:1;
        /* Use maildir_name also for index/control directories. This should
index 567c0c65f6944a98d385d52943ca53653063f91a..31e59e3a6b2093d41d9a6962b934f85bf6e2548e 100644 (file)
@@ -269,6 +269,12 @@ test_maibox_list_name_init(struct mailbox_list *list,
                           const struct test_mailbox_list_name *test,
                           bool mutf7)
 {
+       static char vname_escape_char[2];
+       static struct mail_storage_settings mail_set = {
+               .mailbox_list_visible_escape_char = vname_escape_char,
+       };
+
+       list->mail_set = &mail_set;
        list->ns->prefix = test->ns_prefix == NULL ? "" :
                test->ns_prefix;
        list->ns->prefix_len = strlen(list->ns->prefix);
@@ -276,7 +282,7 @@ test_maibox_list_name_init(struct mailbox_list *list,
        ns_sep[0] = test->ns_sep;
        list_hierarchy_sep = test->list_sep;
        list->set.utf8 = !mutf7;
-       list->set.vname_escape_char = test->vname_escape_char;
+       vname_escape_char[0] = test->vname_escape_char;
        list->set.storage_name_escape_char =
                test->storage_name_escape_char;
        list->set.maildir_name = test->maildir_name == NULL ? "" :