Mercurial > dovecot > core-2.2
changeset 10373:036db604f86c HEAD
dsync: Fixed problems with syncing mailbox names that are invalid on other side.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 19 Nov 2009 17:28:48 -0500 |
parents | 0b101a864534 |
children | 17eac5a18ce4 |
files | src/dsync/dsync-brain.c src/dsync/dsync-proxy-client.c src/dsync/dsync-proxy-server-cmd.c src/dsync/dsync-worker-local.c src/dsync/dsync-worker-private.h src/dsync/dsync-worker.c src/dsync/dsync-worker.h src/dsync/dsync.c src/dsync/test-dsync-proxy-server-cmd.c src/dsync/test-dsync-worker.c |
diffstat | 10 files changed, 138 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- a/src/dsync/dsync-brain.c Thu Nov 19 17:21:03 2009 -0500 +++ b/src/dsync/dsync-brain.c Thu Nov 19 17:28:48 2009 -0500 @@ -535,11 +535,11 @@ if (mailbox->src->last_renamed > mailbox->dest->last_renamed) { dsync_worker_rename_mailbox(brain->dest_worker, &mailbox->box.mailbox_guid, - mailbox->src->name); + mailbox->src); } else { dsync_worker_rename_mailbox(brain->src_worker, &mailbox->box.mailbox_guid, - mailbox->dest->name); + mailbox->dest); } } @@ -549,12 +549,12 @@ const struct dsync_brain_mailbox *mailbox; array_foreach(&brain->mailbox_sync->mailboxes, mailbox) { + dsync_worker_update_mailbox(brain->src_worker, &mailbox->box); + dsync_worker_update_mailbox(brain->dest_worker, &mailbox->box); + if (mailbox->src != NULL && mailbox->dest != NULL && strcmp(mailbox->src->name, mailbox->dest->name) != 0) dsync_brain_sync_rename_mailbox(brain, mailbox); - - dsync_worker_update_mailbox(brain->src_worker, &mailbox->box); - dsync_worker_update_mailbox(brain->dest_worker, &mailbox->box); } }
--- a/src/dsync/dsync-proxy-client.c Thu Nov 19 17:21:03 2009 -0500 +++ b/src/dsync/dsync-proxy-client.c Thu Nov 19 17:28:48 2009 -0500 @@ -698,10 +698,11 @@ static void proxy_client_worker_rename_mailbox(struct dsync_worker *_worker, const mailbox_guid_t *mailbox, - const char *name) + const struct dsync_mailbox *dsync_box) { struct proxy_client_dsync_worker *worker = (struct proxy_client_dsync_worker *)_worker; + char sep[2]; i_assert(worker->save_input == NULL); @@ -711,7 +712,10 @@ str_append(str, "BOX-RENAME\t"); dsync_proxy_mailbox_guid_export(str, mailbox); str_append_c(str, '\t'); - str_tabescape_write(str, name); + str_tabescape_write(str, dsync_box->name); + str_append_c(str, '\t'); + sep[0] = dsync_box->name_sep; sep[1] = '\0'; + str_tabescape_write(str, sep); str_append_c(str, '\n'); o_stream_send(worker->output, str_data(str), str_len(str)); } T_END;
--- a/src/dsync/dsync-proxy-server-cmd.c Thu Nov 19 17:21:03 2009 -0500 +++ b/src/dsync/dsync-proxy-server-cmd.c Thu Nov 19 17:28:48 2009 -0500 @@ -259,15 +259,19 @@ cmd_box_rename(struct dsync_proxy_server *server, const char *const *args) { mailbox_guid_t guid; + struct dsync_mailbox dsync_box; - if (str_array_length(args) < 2) + if (str_array_length(args) < 3) return -1; if (dsync_proxy_mailbox_guid_import(args[0], &guid) < 0) { i_error("box-delete: Invalid mailbox GUID '%s'", args[0]); return -1; } - dsync_worker_rename_mailbox(server->worker, &guid, args[1]); + memset(&dsync_box, 0, sizeof(dsync_box)); + dsync_box.name = args[1]; + dsync_box.name_sep = args[2][0]; + dsync_worker_rename_mailbox(server->worker, &guid, &dsync_box); return 1; }
--- a/src/dsync/dsync-worker-local.c Thu Nov 19 17:21:03 2009 -0500 +++ b/src/dsync/dsync-worker-local.c Thu Nov 19 17:28:48 2009 -0500 @@ -14,6 +14,8 @@ #include "mail-search-build.h" #include "dsync-worker-private.h" +#include <ctype.h> + struct local_dsync_worker_mailbox_iter { struct dsync_worker_mailbox_iter iter; struct mailbox_list_iterate_context *list_iter; @@ -71,7 +73,7 @@ /* mailbox_guid_t -> struct local_dsync_subscription_change */ struct hash_table *subscription_changes_hash; - char alt_hierarchy_char; + char alt_char; mailbox_guid_t selected_box_guid; struct mailbox *selected_box; @@ -121,17 +123,24 @@ } struct dsync_worker * -dsync_worker_init_local(struct mail_user *user, char alt_hierarchy_char) +dsync_worker_init_local(struct mail_user *user, char alt_char) { struct local_dsync_worker *worker; + struct mail_namespace *ns; pool_t pool; + /* whatever we do, we do it because we're trying to sync, + not because of a user action. don't log these mailbox list changes + so we don't do wrong decisions on future syncs. */ + for (ns = user->namespaces; ns != NULL; ns = ns->next) + mailbox_list_set_changelog_writable(ns->list, FALSE); + pool = pool_alloconly_create("local dsync worker", 10240); worker = p_new(pool, struct local_dsync_worker, 1); worker->worker.v = local_dsync_worker; worker->user = user; worker->pool = pool; - worker->alt_hierarchy_char = alt_hierarchy_char; + worker->alt_char = alt_char; worker->mailbox_hash = hash_table_create(default_pool, pool, 0, mailbox_guid_hash, mailbox_guid_cmp); @@ -873,21 +882,84 @@ dest_name = t_strdup_noconst(name); for (p = dest_name; *p != '\0'; p++) { - if (*p == dest_sep && worker->alt_hierarchy_char != '\0') - *p = worker->alt_hierarchy_char; + if (*p == dest_sep && worker->alt_char != '\0') + *p = worker->alt_char; else if (*p == src_sep) *p = dest_sep; } return dest_name; } +static const char * +mailbox_name_cleanup(const char *input, char real_sep, char alt_char) +{ + char *output, *p; + + output = t_strdup_noconst(input); + for (p = output; *p != '\0'; p++) { + if (*p == real_sep || (uint8_t)*input < 32 || + (uint8_t)*input >= 0x80) + *p = alt_char; + } + return output; +} + +static const char *mailbox_name_force_cleanup(const char *input, char alt_char) +{ + char *output, *p; + + output = t_strdup_noconst(input); + for (p = output; *p != '\0'; p++) { + if (!i_isalnum(*p)) + *p = alt_char; + } + return output; +} + +static const char * +local_worker_convert_mailbox_name(struct local_dsync_worker *worker, + const char *name, struct mail_namespace *ns, + const struct dsync_mailbox *dsync_box, + bool creating) +{ + if (dsync_box->name_sep != ns->sep) { + /* mailbox names use different separators. convert them. */ + name = mailbox_name_convert(worker, name, + dsync_box->name_sep, ns->sep); + } + if (creating) { + if (!mailbox_list_is_valid_create_name(ns->list, name)) { + /* change any real separators to alt separators, + drop any potentially invalid characters */ + name = mailbox_name_cleanup(name, ns->real_sep, + worker->alt_char); + } + if (!mailbox_list_is_valid_create_name(ns->list, name)) { + /* still not working, apparently it's not valid mUTF-7. + just drop all non-alphanumeric characters. */ + name = mailbox_name_force_cleanup(name, + worker->alt_char); + } + } + return name; +} + static struct mailbox * local_worker_mailbox_alloc(struct local_dsync_worker *worker, - const struct dsync_mailbox *dsync_box) + const struct dsync_mailbox *dsync_box, bool creating) { struct mail_namespace *ns; + struct local_dsync_mailbox *lbox; const char *name; + lbox = hash_table_lookup(worker->mailbox_hash, + &dsync_box->mailbox_guid); + if (lbox != NULL) { + /* use the existing known mailbox name */ + return mailbox_alloc(lbox->ns->list, lbox->storage_name, + NULL, 0); + } + name = dsync_box->name; ns = mail_namespace_find(worker->user->namespaces, &name); if (ns == NULL) { @@ -895,11 +967,10 @@ return NULL; } - if (dsync_box->name_sep != ns->sep) { - /* mailbox names use different separators. convert them. */ - name = mailbox_name_convert(worker, name, - dsync_box->name_sep, ns->sep); - } + name = local_worker_convert_mailbox_name(worker, name, ns, + dsync_box, creating); + local_dsync_worker_add_mailbox(worker, ns, name, + &dsync_box->mailbox_guid); return mailbox_alloc(ns->list, name, NULL, 0); } @@ -913,7 +984,7 @@ struct mailbox_update update; int ret; - box = local_worker_mailbox_alloc(worker, dsync_box); + box = local_worker_mailbox_alloc(worker, dsync_box, TRUE); if (box == NULL) { dsync_worker_set_failure(_worker); return; @@ -989,12 +1060,14 @@ static void local_worker_rename_mailbox(struct dsync_worker *_worker, - const mailbox_guid_t *mailbox, const char *name) + const mailbox_guid_t *mailbox, + const struct dsync_mailbox *dsync_box) { struct local_dsync_worker *worker = (struct local_dsync_worker *)_worker; struct local_dsync_mailbox *lbox; - const char *oldname; + struct mailbox_list *list; + const char *oldname, *newname; lbox = hash_table_lookup(worker->mailbox_hash, mailbox); if (lbox == NULL) { @@ -1004,15 +1077,24 @@ return; } - if (mailbox_list_rename_mailbox(lbox->ns->list, lbox->storage_name, - lbox->ns->list, name, TRUE) < 0) { + list = lbox->ns->list; + newname = local_worker_convert_mailbox_name(worker, dsync_box->name, + lbox->ns, dsync_box, TRUE); + if (strcmp(lbox->storage_name, newname) == 0) { + /* nothing changed after all. probably because some characters + in mailbox name weren't valid. */ + return; + } + + if (mailbox_list_rename_mailbox(list, lbox->storage_name, + list, newname, TRUE) < 0) { i_error("Can't rename mailbox %s to %s: %s", lbox->storage_name, - name, mailbox_list_get_last_error(lbox->ns->list, NULL)); + newname, mailbox_list_get_last_error(list, NULL)); dsync_worker_set_failure(_worker); } else { oldname = lbox->storage_name; - lbox->storage_name = p_strdup(worker->pool, name); - local_worker_rename_children(worker, oldname, name, + lbox->storage_name = p_strdup(worker->pool, newname); + local_worker_rename_children(worker, oldname, newname, lbox->ns->sep); } } @@ -1091,7 +1173,7 @@ if (selected) local_worker_mailbox_close(worker); - box = local_worker_mailbox_alloc(worker, dsync_box); + box = local_worker_mailbox_alloc(worker, dsync_box, FALSE); if (box == NULL) { dsync_worker_set_failure(_worker); return;
--- a/src/dsync/dsync-worker-private.h Thu Nov 19 17:21:03 2009 -0500 +++ b/src/dsync/dsync-worker-private.h Thu Nov 19 17:28:48 2009 -0500 @@ -41,7 +41,8 @@ void (*delete_mailbox)(struct dsync_worker *worker, const mailbox_guid_t *mailbox); void (*rename_mailbox)(struct dsync_worker *worker, - const mailbox_guid_t *mailbox, const char *name); + const mailbox_guid_t *mailbox, + const struct dsync_mailbox *dsync_box); void (*update_mailbox)(struct dsync_worker *worker, const struct dsync_mailbox *dsync_box);
--- a/src/dsync/dsync-worker.c Thu Nov 19 17:21:03 2009 -0500 +++ b/src/dsync/dsync-worker.c Thu Nov 19 17:28:48 2009 -0500 @@ -140,10 +140,10 @@ void dsync_worker_rename_mailbox(struct dsync_worker *worker, const mailbox_guid_t *mailbox, - const char *name) + const struct dsync_mailbox *dsync_box) { if (!worker->readonly) - worker->v.rename_mailbox(worker, mailbox, name); + worker->v.rename_mailbox(worker, mailbox, dsync_box); } void dsync_worker_update_mailbox(struct dsync_worker *worker,
--- a/src/dsync/dsync-worker.h Thu Nov 19 17:21:03 2009 -0500 +++ b/src/dsync/dsync-worker.h Thu Nov 19 17:28:48 2009 -0500 @@ -29,7 +29,7 @@ typedef void dsync_worker_finish_callback_t(bool success, void *context); struct dsync_worker * -dsync_worker_init_local(struct mail_user *user, char alt_hierarchy_char); +dsync_worker_init_local(struct mail_user *user, char alt_char); struct dsync_worker *dsync_worker_init_proxy_client(int fd_in, int fd_out); void dsync_worker_deinit(struct dsync_worker **worker); @@ -100,10 +100,11 @@ /* Delete mailbox/dir with given GUID. */ void dsync_worker_delete_mailbox(struct dsync_worker *worker, const mailbox_guid_t *mailbox); -/* Change a mailbox and its childrens' name */ +/* Change a mailbox and its childrens' name. The name is taken from the given + dsync_box (applying name_sep if necessary). */ void dsync_worker_rename_mailbox(struct dsync_worker *worker, const mailbox_guid_t *mailbox, - const char *name); + const struct dsync_mailbox *dsync_box); /* Find mailbox with given GUID and make sure its uid_next and highest_modseq are up to date (but don't shrink them). */ void dsync_worker_update_mailbox(struct dsync_worker *worker,
--- a/src/dsync/dsync.c Thu Nov 19 17:21:03 2009 -0500 +++ b/src/dsync/dsync.c Thu Nov 19 17:28:48 2009 -0500 @@ -85,7 +85,7 @@ const char *error, *username, *mailbox = NULL, *mirror_cmd = NULL; const char *convert_location = NULL; bool dsync_server = FALSE, readonly = FALSE, unexpected_changes = FALSE; - char alt_hierarchy_char = '_'; + char alt_char = '_'; int c, ret, fd_in = STDIN_FILENO, fd_out = STDOUT_FILENO; master_service = master_service_init("dsync", @@ -99,7 +99,7 @@ break; switch (c) { case 'A': - alt_hierarchy_char = optarg[0]; + alt_char = optarg[0]; break; case 'b': mailbox = optarg; @@ -159,7 +159,7 @@ } /* create the first local worker */ - worker1 = dsync_worker_init_local(mail_user, alt_hierarchy_char); + worker1 = dsync_worker_init_local(mail_user, alt_char); if (convert_location != NULL) { /* update mail_location and create another user for the second location. */ @@ -174,8 +174,7 @@ &mail_user2, &error) < 0) i_fatal("User init failed: %s", error); - worker2 = dsync_worker_init_local(mail_user2, - alt_hierarchy_char); + worker2 = dsync_worker_init_local(mail_user2, alt_char); i_set_failure_prefix(t_strdup_printf("dsync(%s): ", username)); brain = dsync_brain_init(worker1, worker2,
--- a/src/dsync/test-dsync-proxy-server-cmd.c Thu Nov 19 17:21:03 2009 -0500 +++ b/src/dsync/test-dsync-proxy-server-cmd.c Thu Nov 19 17:28:48 2009 -0500 @@ -274,17 +274,19 @@ test_begin("proxy server box rename"); - test_assert(run_cmd("BOX-RENAME", TEST_MAILBOX_GUID1, "name\t1", NULL) == 1); + test_assert(run_cmd("BOX-RENAME", TEST_MAILBOX_GUID1, "name\t1", "/", NULL) == 1); test_assert(test_dsync_worker_next_box_event(test_worker, &event)); test_assert(event.type == LAST_BOX_TYPE_RENAME); test_assert(memcmp(event.box.mailbox_guid.guid, test_mailbox_guid1, MAIL_GUID_128_SIZE) == 0); test_assert(strcmp(event.box.name, "name\t1") == 0); + test_assert(event.box.name_sep == '/'); - test_assert(run_cmd("BOX-RENAME", TEST_MAILBOX_GUID2, "", NULL) == 1); + test_assert(run_cmd("BOX-RENAME", TEST_MAILBOX_GUID2, "", "?", NULL) == 1); test_assert(test_dsync_worker_next_box_event(test_worker, &event)); test_assert(event.type == LAST_BOX_TYPE_RENAME); test_assert(memcmp(event.box.mailbox_guid.guid, test_mailbox_guid2, MAIL_GUID_128_SIZE) == 0); test_assert(strcmp(event.box.name, "") == 0); + test_assert(event.box.name_sep == '?'); test_end(); }
--- a/src/dsync/test-dsync-worker.c Thu Nov 19 17:21:03 2009 -0500 +++ b/src/dsync/test-dsync-worker.c Thu Nov 19 17:28:48 2009 -0500 @@ -247,7 +247,8 @@ static void test_worker_rename_mailbox(struct dsync_worker *_worker, - const mailbox_guid_t *mailbox, const char *name) + const mailbox_guid_t *mailbox, + const struct dsync_mailbox *dsync_box) { struct test_dsync_worker *worker = (struct test_dsync_worker *)_worker; struct test_dsync_box_event event; @@ -255,8 +256,8 @@ memset(&event, 0, sizeof(event)); event.type = LAST_BOX_TYPE_RENAME; + event.box = *dsync_box; event.box.mailbox_guid = *mailbox; - event.box.name = name; array_append(&worker->box_events, &event, 1); }