From: Timo Sirainen Date: Mon, 3 Apr 2023 21:43:55 +0000 (+0300) Subject: dsync: Fix handling mailboxes with % character when BROKENCHAR isn't explicitly set... X-Git-Tag: 2.3.21~95 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4c74cf89f67df3a69061643797e3884c598b7dd5;p=thirdparty%2Fdovecot%2Fcore.git dsync: Fix handling mailboxes with % character when BROKENCHAR isn't explicitly set in config 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. --- diff --git a/src/doveadm/dsync/dsync-brain-mailbox-tree.c b/src/doveadm/dsync/dsync-brain-mailbox-tree.c index b66cf3edfe..ddf237063d 100644 --- a/src/doveadm/dsync/dsync-brain-mailbox-tree.c +++ b/src/doveadm/dsync/dsync-brain-mailbox-tree.c @@ -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; diff --git a/src/doveadm/dsync/dsync-mailbox-tree-fill.c b/src/doveadm/dsync/dsync-mailbox-tree-fill.c index 17c1eea0e5..b255122866 100644 --- a/src/doveadm/dsync/dsync-mailbox-tree-fill.c +++ b/src/doveadm/dsync/dsync-mailbox-tree-fill.c @@ -10,16 +10,51 @@ #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; diff --git a/src/doveadm/dsync/dsync-mailbox-tree.h b/src/doveadm/dsync/dsync-mailbox-tree.h index 526be182af..3542ef4a44 100644 --- a/src/doveadm/dsync/dsync-mailbox-tree.h +++ b/src/doveadm/dsync/dsync-mailbox-tree.h @@ -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. */