]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dsync: Fix handling mailboxes with % character when BROKENCHAR isn't explicitly set...
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 3 Apr 2023 21:43:55 +0000 (00:43 +0300)
committerMarkus Valentin <markus.valentin@open-xchange.com>
Thu, 6 Apr 2023 11:00:35 +0000 (13:00 +0200)
When vname_escape_char (= BROKENCHAR) isn't explicitly set in configuration,
'%' character (or if it was hierarchy separator, '~') was used as the default
internal escape character. However, this was used inconsistently between local
and remote mailbox trees. The remote tree stored the mailbox names unescaped,
while the local mailbox names were escaped. This inconsistency caused dsync
to do unnecessary mailbox renames, which might have ended up failing.

This especially fixes dsync failures when mailbox name ended with the '%'
character.

src/doveadm/dsync/dsync-brain-mailbox-tree.c
src/doveadm/dsync/dsync-mailbox-tree-fill.c
src/doveadm/dsync/dsync-mailbox-tree.h

index b66cf3edfe9f685b4765e01c786452dc2765c48d..ddf237063dad3be192563504540e19383ecc43d0 100644 (file)
@@ -74,6 +74,7 @@ void dsync_brain_mailbox_trees_init(struct dsync_brain *brain)
                                            brain->sync_box,
                                            brain->sync_box_guid,
                                            brain->exclude_mailboxes,
+                                           brain->alt_char,
                                            &brain->mail_error) < 0) {
                        brain->failed = TRUE;
                        break;
index 17c1eea0e55f907ea272545b35e9b7437109c4c4..b255122866df8d657ee73787bbfb56879ff43279 100644 (file)
 #include "mail-namespace.h"
 #include "mail-storage.h"
 #include "mailbox-list-iter.h"
+#include "dsync-brain.h"
 #include "dsync-mailbox-tree-private.h"
 
+static const char *
+dsync_mailbox_tree_name_unescape(struct mail_namespace *ns,
+                                const char *old_vname, char alt_char)
+{
+       const char ns_sep = mail_namespace_get_sep(ns);
+       const char escape_char =
+               mailbox_list_get_settings(ns->list)->vname_escape_char;
+       const char *const *old_vname_parts =
+               dsync_mailbox_name_to_parts(old_vname, ns_sep, escape_char);
+
+       string_t *new_vname = t_str_new(128);
+       for (; *old_vname_parts != NULL; old_vname_parts++) {
+               for (const char *p = *old_vname_parts; *p != '\0'; p++) {
+                       if (*p != ns_sep)
+                               str_append_c(new_vname, *p);
+                       else
+                               str_append_c(new_vname, alt_char);
+               }
+               str_append_c(new_vname, ns_sep);
+       }
+       str_truncate(new_vname, str_len(new_vname)-1);
+       return str_c(new_vname);
+};
+
 static int
 dsync_mailbox_tree_add_node(struct dsync_mailbox_tree *tree,
                            const struct mailbox_info *info,
+                           char alt_char,
                            struct dsync_mailbox_node **node_r)
 {
        struct dsync_mailbox_node *node;
+       const char *vname = info->vname;
+
+       struct dsync_mailbox_list *dlist = DSYNC_LIST_CONTEXT(info->ns->list);
+       if (dlist != NULL && !dlist->have_orig_escape_char) {
+               /* The escape character was added only for dsync internally.
+                  Normally there is no escape character configured. Change
+                  the mailbox names so that it doesn't rely on it. */
+               vname = dsync_mailbox_tree_name_unescape(info->ns, vname, alt_char);
+       }
 
-       node = dsync_mailbox_tree_get(tree, info->vname);
+       node = dsync_mailbox_tree_get(tree, vname);
        if (node->ns == info->ns)
                ;
        else if (node->ns == NULL) {
@@ -38,9 +73,10 @@ static int
 dsync_mailbox_tree_add_exists_node(struct dsync_mailbox_tree *tree,
                                   const struct mailbox_info *info,
                                   struct dsync_mailbox_node **node_r,
+                                  char alt_char,
                                   enum mail_error *error_r)
 {
-       if (dsync_mailbox_tree_add_node(tree, info, node_r) < 0) {
+       if (dsync_mailbox_tree_add_node(tree, info, alt_char, node_r) < 0) {
                *error_r = MAIL_ERROR_TEMP;
                return -1;
        }
@@ -75,6 +111,7 @@ dsync_mailbox_tree_get_selectable(struct mailbox *box,
 static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree,
                                  const struct mailbox_info *info,
                                  const guid_128_t box_guid,
+                                 char alt_char,
                                  enum mail_error *error_r)
 {
        struct dsync_mailbox_node *node;
@@ -90,7 +127,8 @@ static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree,
                return 0;
        if ((info->flags & MAILBOX_NOSELECT) != 0) {
                return !guid_128_is_empty(box_guid) ? 0 :
-                       dsync_mailbox_tree_add_exists_node(tree, info, &node, error_r);
+                       dsync_mailbox_tree_add_exists_node(
+                               tree, info, &node, alt_char, error_r);
        }
 
        /* get GUID and UIDVALIDITY for selectable mailbox */
@@ -102,7 +140,7 @@ static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree,
                if (existence == MAILBOX_EXISTENCE_NOSELECT) {
                        return !guid_128_is_empty(box_guid) ? 0 :
                                dsync_mailbox_tree_add_exists_node(
-                                       tree, info, &node, error_r);
+                                       tree, info, &node, alt_char, error_r);
                } else {
                        return 0;
                }
@@ -135,7 +173,8 @@ static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree,
                /* unwanted mailbox */
                return 0;
        }
-       if (dsync_mailbox_tree_add_exists_node(tree, info, &node, error_r) < 0)
+       if (dsync_mailbox_tree_add_exists_node(
+               tree, info, &node, alt_char, error_r) < 0)
                return -1;
        memcpy(node->mailbox_guid, metadata.guid,
               sizeof(node->mailbox_guid));
@@ -338,6 +377,7 @@ int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree,
                            struct mail_namespace *ns, const char *box_name,
                            const guid_128_t box_guid,
                            const char *const *exclude_mailboxes,
+                           char alt_char,
                            enum mail_error *error_r)
 {
        const enum mailbox_list_iter_flags list_flags =
@@ -369,7 +409,8 @@ int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree,
                        .vname = vname,
                        .ns = ns,
                };
-               if (dsync_mailbox_tree_add(tree, &ns_info, box_guid, error_r) < 0)
+               if (dsync_mailbox_tree_add(
+                       tree, &ns_info, box_guid, alt_char, error_r) < 0)
                        return -1;
        } else {
                tree->root.ns = ns;
@@ -380,7 +421,8 @@ int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree,
        while ((info = mailbox_list_iter_next(iter)) != NULL) T_BEGIN {
                if (dsync_mailbox_info_is_wanted(info, box_name,
                                                 exclude_mailboxes)) {
-                       if (dsync_mailbox_tree_add(tree, info, box_guid, error_r) < 0)
+                       if (dsync_mailbox_tree_add(
+                               tree, info, box_guid, alt_char, error_r) < 0)
                                ret = -1;
                }
        } T_END;
@@ -393,7 +435,7 @@ int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree,
        /* add subscriptions */
        iter = mailbox_list_iter_init(ns->list, list_pattern, subs_list_flags);
        while ((info = mailbox_list_iter_next(iter)) != NULL) {
-               if (dsync_mailbox_tree_add_node(tree, info, &node) == 0)
+               if (dsync_mailbox_tree_add_node(tree, info, alt_char, &node) == 0)
                        node->subscribed = TRUE;
                else {
                        *error_r = MAIL_ERROR_TEMP;
index 526be182af6654f75cf628c8529acf7d76bc43e5..3542ef4a447182d94e1f017722dd71bb57e66587 100644 (file)
@@ -155,6 +155,7 @@ int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree,
                            struct mail_namespace *ns, const char *box_name,
                            const guid_128_t box_guid,
                            const char *const *exclude_mailboxes,
+                           char alt_char,
                            enum mail_error *error_r);
 
 /* Return all known deleted mailboxes and directories. */