From: Timo Sirainen Date: Wed, 18 Nov 2009 01:55:04 +0000 (-0500) Subject: dsync: Added support for different source/dest hierarchy separators. X-Git-Tag: 2.0.beta1~123 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0a906df9e4a8b4624ee3328256b8696b26d7949a;p=thirdparty%2Fdovecot%2Fcore.git dsync: Added support for different source/dest hierarchy separators. --HG-- branch : HEAD --- diff --git a/src/dsync/dsync-brain.c b/src/dsync/dsync-brain.c index 63b2417b44..90f02e62bb 100644 --- a/src/dsync/dsync-brain.c +++ b/src/dsync/dsync-brain.c @@ -525,8 +525,6 @@ dsync_brain_msg_sync_update_mailbox(struct dsync_brain *brain) { const struct dsync_brain_mailbox *mailbox; - /* FIXME: handle different hierarchy separators? */ - 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); diff --git a/src/dsync/dsync-data.h b/src/dsync/dsync-data.h index dcfea98604..abff6be2d0 100644 --- a/src/dsync/dsync-data.h +++ b/src/dsync/dsync-data.h @@ -15,6 +15,7 @@ enum dsync_mailbox_flags { struct dsync_mailbox { const char *name; + char name_sep; /* Mailbox directory's GUID. Not necessarily set if mailbox is deleted. */ mailbox_guid_t dir_guid; diff --git a/src/dsync/dsync-proxy.c b/src/dsync/dsync-proxy.c index ff4f4a5ee3..ee644e56d9 100644 --- a/src/dsync/dsync-proxy.c +++ b/src/dsync/dsync-proxy.c @@ -155,8 +155,13 @@ int dsync_proxy_msg_static_import(pool_t pool, const char *str, void dsync_proxy_mailbox_export(string_t *str, const struct dsync_mailbox *box) { + char s[2]; + str_tabescape_write(str, box->name); str_append_c(str, '\t'); + s[0] = box->name_sep; s[1] = '\0'; + str_tabescape_write(str, s); + str_append_c(str, '\t'); dsync_proxy_mailbox_guid_export(str, &box->dir_guid); str_printfa(str, "\t%lu\t%u", (unsigned long)box->last_renamed, box->flags); @@ -178,65 +183,72 @@ int dsync_proxy_mailbox_import_unescaped(pool_t pool, const char *const *args, struct dsync_mailbox *box_r, const char **error_r) { - unsigned int i, count; + unsigned int i = 0, count; char *p; memset(box_r, 0, sizeof(*box_r)); count = str_array_length(args); - if (count != 4 && count < 8) { + if (count != 5 && count < 9) { *error_r = "Mailbox missing parameters"; return -1; } /* name dir_guid mailbox_guid uid_validity uid_next highest_modseq */ - box_r->name = p_strdup(pool, args[0]); + box_r->name = p_strdup(pool, args[i++]); + + if (strlen(args[i]) != 1) { + *error_r = "Invalid mailbox name hierarchy separator"; + return -1; + } + box_r->name_sep = args[i++][0]; - if (dsync_proxy_mailbox_guid_import(args[1], &box_r->dir_guid) < 0) { + if (dsync_proxy_mailbox_guid_import(args[i++], &box_r->dir_guid) < 0) { *error_r = "Invalid dir GUID"; return -1; } - box_r->last_renamed = strtoul(args[2], &p, 10); + box_r->last_renamed = strtoul(args[i++], &p, 10); if (*p != '\0') { *error_r = "Invalid mailbox last_renamed"; return -1; } - box_r->flags = strtoul(args[3], &p, 10); + box_r->flags = strtoul(args[i++], &p, 10); if (*p != '\0') { *error_r = "Invalid mailbox flags"; return -1; } - if (args[4] == NULL) { + if (args[i] == NULL) { /* \noselect mailbox */ return 0; } - if (dsync_proxy_mailbox_guid_import(args[4], &box_r->mailbox_guid) < 0) { + if (dsync_proxy_mailbox_guid_import(args[i++], + &box_r->mailbox_guid) < 0) { *error_r = "Invalid mailbox GUID"; return -1; } - box_r->uid_validity = strtoul(args[5], &p, 10); + box_r->uid_validity = strtoul(args[i++], &p, 10); if (box_r->uid_validity == 0 || *p != '\0') { *error_r = "Invalid mailbox uid_validity"; return -1; } - box_r->uid_next = strtoul(args[6], &p, 10); + box_r->uid_next = strtoul(args[i++], &p, 10); if (box_r->uid_validity == 0 || *p != '\0') { *error_r = "Invalid mailbox uid_next"; return -1; } - box_r->highest_modseq = strtoull(args[7], &p, 10); + box_r->highest_modseq = strtoull(args[i++], &p, 10); if (*p != '\0') { *error_r = "Invalid mailbox highest_modseq"; return -1; } - args += 8; - count -= 8; + args += i; + count -= i; p_array_init(&box_r->cache_fields, pool, count + 1); for (i = 0; i < count; i++) { const char *field_name = p_strdup(pool, args[i]); diff --git a/src/dsync/dsync-worker-local.c b/src/dsync/dsync-worker-local.c index edcddc0b96..5cdaf8da48 100644 --- a/src/dsync/dsync-worker-local.c +++ b/src/dsync/dsync-worker-local.c @@ -71,6 +71,8 @@ struct local_dsync_worker { /* mailbox_guid_t -> struct local_dsync_subscription_change */ struct hash_table *subscription_changes_hash; + char alt_hierarchy_char; + mailbox_guid_t selected_box_guid; struct mailbox *selected_box; struct mail *mail, *ext_mail; @@ -116,7 +118,8 @@ static unsigned int mailbox_guid_hash(const void *p) return h; } -struct dsync_worker *dsync_worker_init_local(struct mail_user *user) +struct dsync_worker * +dsync_worker_init_local(struct mail_user *user, char alt_hierarchy_char) { struct local_dsync_worker *worker; pool_t pool; @@ -126,6 +129,7 @@ struct dsync_worker *dsync_worker_init_local(struct mail_user *user) worker->worker.v = local_dsync_worker; worker->user = user; worker->pool = pool; + worker->alt_hierarchy_char = alt_hierarchy_char; worker->mailbox_hash = hash_table_create(default_pool, pool, 0, mailbox_guid_hash, mailbox_guid_cmp); @@ -416,6 +420,7 @@ local_worker_mailbox_iter_next(struct dsync_worker_mailbox_iter *_iter, storage_name = mail_namespace_get_storage_name(info->ns, info->name); dsync_box_r->name = info->name; + dsync_box_r->name_sep = info->ns->sep; if (mailbox_list_get_guid(info->ns->list, storage_name, dsync_box_r->dir_guid.guid) < 0) { i_error("Failed to get dir GUID for mailbox %s: %s", info->name, @@ -856,6 +861,22 @@ local_worker_copy_mailbox_update(const struct dsync_mailbox *dsync_box, update_r->min_highest_modseq = dsync_box->highest_modseq; } +static const char * +mailbox_name_convert(struct local_dsync_worker *worker, + const char *name, char src_sep, char dest_sep) +{ + char *dest_name, *p; + + 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; + else if (*p == src_sep) + *p = dest_sep; + } + return dest_name; +} + static struct mailbox * local_worker_mailbox_alloc(struct local_dsync_worker *worker, const struct dsync_mailbox *dsync_box) @@ -870,6 +891,11 @@ local_worker_mailbox_alloc(struct local_dsync_worker *worker, 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); + } return mailbox_alloc(ns->list, name, NULL, 0); } diff --git a/src/dsync/dsync-worker.h b/src/dsync/dsync-worker.h index 03fbead71b..726c81c221 100644 --- a/src/dsync/dsync-worker.h +++ b/src/dsync/dsync-worker.h @@ -28,7 +28,8 @@ typedef void dsync_worker_msg_callback_t(enum dsync_msg_get_result result, void *context); typedef void dsync_worker_finish_callback_t(bool success, void *context); -struct dsync_worker *dsync_worker_init_local(struct mail_user *user); +struct dsync_worker * +dsync_worker_init_local(struct mail_user *user, char alt_hierarchy_char); struct dsync_worker *dsync_worker_init_proxy_client(int fd_in, int fd_out); void dsync_worker_deinit(struct dsync_worker **worker); diff --git a/src/dsync/dsync.c b/src/dsync/dsync.c index 8494d72f13..880a1018df 100644 --- a/src/dsync/dsync.c +++ b/src/dsync/dsync.c @@ -58,7 +58,7 @@ static void ATTR_NORETURN usage(void) { fprintf(stderr, -"usage: dsync [-b ] [-r] [-u ] [-v]\n" +"usage: dsync [-a ] [-b ] [-r] [-u ] [-v]\n" " mirror \n" " convert \n" ); @@ -84,18 +84,22 @@ int main(int argc, char *argv[]) const char *error, *username, *mailbox = NULL, *mirror_cmd = NULL; const char *convert_location = NULL; bool dsync_server = FALSE, readonly = FALSE; + char alt_hierarchy_char = '_'; int c, ret, fd_in = STDIN_FILENO, fd_out = STDOUT_FILENO; master_service = master_service_init("dsync", MASTER_SERVICE_FLAG_STANDALONE | MASTER_SERVICE_FLAG_STD_CLIENT, - &argc, &argv, "b:fru:v"); + &argc, &argv, "A:b:fru:v"); username = getenv("USER"); while ((c = master_getopt(master_service)) > 0) { if (c == '-') break; switch (c) { + case 'A': + alt_hierarchy_char = optarg[0]; + break; case 'b': mailbox = optarg; break; @@ -152,7 +156,7 @@ int main(int argc, char *argv[]) } /* create the first local worker */ - worker1 = dsync_worker_init_local(mail_user); + worker1 = dsync_worker_init_local(mail_user, alt_hierarchy_char); if (convert_location != NULL) { /* update mail_location and create another user for the second location. */ @@ -168,7 +172,8 @@ int main(int argc, char *argv[]) &error) <= 0) i_fatal("%s", error); - worker2 = dsync_worker_init_local(mail_user2); + worker2 = dsync_worker_init_local(mail_user2, + alt_hierarchy_char); i_set_failure_prefix(t_strdup_printf("dsync(%s): ", username)); brain = dsync_brain_init(worker1, worker2, diff --git a/src/dsync/test-dsync-brain.c b/src/dsync/test-dsync-brain.c index 1a51eb4496..c8ce958a86 100644 --- a/src/dsync/test-dsync-brain.c +++ b/src/dsync/test-dsync-brain.c @@ -121,28 +121,28 @@ dsync_brain_mailbox_name_cmp(const struct dsync_brain_mailbox *box1, static void test_dsync_brain(void) { static struct dsync_mailbox src_boxes[] = { - { "box1", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box2", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box3", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box4", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box5", { { 0, } }, { { 0, } }, 1234567890, 5433, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box6", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123124ULL, 3636, 0, ARRAY_INIT }, - { "boxx", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "boxd1", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "boxd2", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, DSYNC_MAILBOX_FLAG_DELETED_MAILBOX, ARRAY_INIT }, - { NULL, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, ARRAY_INIT } + { "box1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box2", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box3", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box4", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box5", '/', { { 0, } }, { { 0, } }, 1234567890, 5433, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box6", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123124ULL, 3636, 0, ARRAY_INIT }, + { "boxx", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "boxd1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "boxd2", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, DSYNC_MAILBOX_FLAG_DELETED_MAILBOX, ARRAY_INIT }, + { NULL, 0, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, ARRAY_INIT } }; static struct dsync_mailbox dest_boxes[] = { - { "box1", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box2", { { 0, } }, { { 0, } }, 1234567891, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box3", { { 0, } }, { { 0, } }, 1234567890, 5433, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box4", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123124ULL, 3636, 0, ARRAY_INIT }, - { "box5", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box6", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "boxy", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "boxd1", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, DSYNC_MAILBOX_FLAG_DELETED_MAILBOX, ARRAY_INIT }, - { "boxd2", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { NULL, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, ARRAY_INIT } + { "box1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box2", '/', { { 0, } }, { { 0, } }, 1234567891, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box3", '/', { { 0, } }, { { 0, } }, 1234567890, 5433, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box4", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123124ULL, 3636, 0, ARRAY_INIT }, + { "box5", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box6", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "boxy", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "boxd1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, DSYNC_MAILBOX_FLAG_DELETED_MAILBOX, ARRAY_INIT }, + { "boxd2", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { NULL, 0, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, ARRAY_INIT } }; struct dsync_brain *brain; struct dsync_worker *src_worker, *dest_worker; @@ -231,8 +231,8 @@ static void test_dsync_brain(void) static void test_dsync_brain_full(void) { static struct dsync_mailbox boxes[] = { - { "box1", { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 2352, 0, ARRAY_INIT }, - { NULL, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, ARRAY_INIT } + { "box1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 123123123123ULL, 2352, 0, ARRAY_INIT }, + { NULL, 0, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, ARRAY_INIT } }; struct dsync_brain *brain; struct dsync_worker *src_worker, *dest_worker; diff --git a/src/dsync/test-dsync-proxy-server-cmd.c b/src/dsync/test-dsync-proxy-server-cmd.c index c46c099933..11ed2f83a6 100644 --- a/src/dsync/test-dsync-proxy-server-cmd.c +++ b/src/dsync/test-dsync-proxy-server-cmd.c @@ -74,18 +74,20 @@ static void test_dsync_proxy_box_list(void) /* \noselect mailbox */ memset(&box, 0, sizeof(box)); box.name = "\t\001\r\nname\t\001\n\r"; + box.name_sep = '/'; box.last_renamed = 992; box.flags = 123; memcpy(box.dir_guid.guid, test_mailbox_guid1, MAIL_GUID_128_SIZE); test_worker->box_iter.next_box = &box; test_assert(run_more() == 0); test_assert(strcmp(str_c(out), t_strconcat(str_tabescape(box.name), - "\t"TEST_MAILBOX_GUID1"\t992\t123\n", NULL)) == 0); + "\t/\t"TEST_MAILBOX_GUID1"\t992\t123\n", NULL)) == 0); out_clear(); /* selectable mailbox */ memset(&box, 0, sizeof(box)); box.name = "foo/bar"; + box.name_sep = '/'; memcpy(box.dir_guid.guid, test_mailbox_guid2, MAIL_GUID_128_SIZE); memcpy(box.mailbox_guid.guid, test_mailbox_guid1, MAIL_GUID_128_SIZE); box.uid_validity = 4275878552; @@ -95,7 +97,7 @@ static void test_dsync_proxy_box_list(void) test_assert(run_more() == 0); - test_assert(strcmp(str_c(out), "foo/bar\t" + test_assert(strcmp(str_c(out), "foo/bar\t/\t" TEST_MAILBOX_GUID2"\t0\t0\t" TEST_MAILBOX_GUID1"\t" "4275878552\t" @@ -218,22 +220,24 @@ static void test_dsync_proxy_box_create(void) test_begin("proxy server box create"); - test_assert(run_cmd("BOX-CREATE", "noselect", + test_assert(run_cmd("BOX-CREATE", "noselect", "/", TEST_MAILBOX_GUID2, "553", "99", NULL) == 1); test_assert(test_dsync_worker_next_box_event(test_worker, &event)); test_assert(event.type == LAST_BOX_TYPE_CREATE); test_assert(strcmp(event.box.name, "noselect") == 0); + test_assert(event.box.name_sep == '/'); test_assert(memcmp(event.box.dir_guid.guid, test_mailbox_guid2, MAIL_GUID_128_SIZE) == 0); test_assert(event.box.last_renamed == 553); test_assert(event.box.flags == 99); test_assert(event.box.uid_validity == 0); - test_assert(run_cmd("BOX-CREATE", "selectable", TEST_MAILBOX_GUID1, + test_assert(run_cmd("BOX-CREATE", "selectable", "?", TEST_MAILBOX_GUID1, "61", "2", TEST_MAILBOX_GUID2, "1234567890", "9876", "28427847284728", NULL) == 1); test_assert(test_dsync_worker_next_box_event(test_worker, &event)); test_assert(event.type == LAST_BOX_TYPE_CREATE); test_assert(strcmp(event.box.name, "selectable") == 0); + test_assert(event.box.name_sep == '?'); test_assert(memcmp(event.box.dir_guid.guid, test_mailbox_guid1, MAIL_GUID_128_SIZE) == 0); test_assert(memcmp(event.box.mailbox_guid.guid, test_mailbox_guid2, MAIL_GUID_128_SIZE) == 0); test_assert(event.box.flags == 2); @@ -291,12 +295,13 @@ static void test_dsync_proxy_box_update(void) test_begin("proxy server box update"); - test_assert(run_cmd("BOX-UPDATE", "updated", TEST_MAILBOX_GUID2, + test_assert(run_cmd("BOX-UPDATE", "updated", "/", TEST_MAILBOX_GUID2, "53", "9", TEST_MAILBOX_GUID1, "34343", "22", "2238427847284728", NULL) == 1); test_assert(test_dsync_worker_next_box_event(test_worker, &event)); test_assert(event.type == LAST_BOX_TYPE_UPDATE); test_assert(strcmp(event.box.name, "updated") == 0); + test_assert(event.box.name_sep == '/'); test_assert(memcmp(event.box.dir_guid.guid, test_mailbox_guid2, MAIL_GUID_128_SIZE) == 0); test_assert(memcmp(event.box.mailbox_guid.guid, test_mailbox_guid1, MAIL_GUID_128_SIZE) == 0); test_assert(event.box.flags == 9); diff --git a/src/dsync/test-dsync-proxy.c b/src/dsync/test-dsync-proxy.c index 0bd0c0867a..679088fda8 100644 --- a/src/dsync/test-dsync-proxy.c +++ b/src/dsync/test-dsync-proxy.c @@ -102,6 +102,7 @@ static void test_dsync_proxy_mailbox(void) /* test \noselect mailbox */ box_in.name = "\t\001\r\nname\t\001\n\r"; + box_in.name_sep = '/'; box_in.flags = 1234567890; memcpy(box_in.dir_guid.guid, test_mailbox_guid2, MAIL_GUID_128_SIZE); dsync_proxy_mailbox_export(str, &box_in);