]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dsync: Added support for different source/dest hierarchy separators.
authorTimo Sirainen <tss@iki.fi>
Wed, 18 Nov 2009 01:55:04 +0000 (20:55 -0500)
committerTimo Sirainen <tss@iki.fi>
Wed, 18 Nov 2009 01:55:04 +0000 (20:55 -0500)
--HG--
branch : HEAD

src/dsync/dsync-brain.c
src/dsync/dsync-data.h
src/dsync/dsync-proxy.c
src/dsync/dsync-worker-local.c
src/dsync/dsync-worker.h
src/dsync/dsync.c
src/dsync/test-dsync-brain.c
src/dsync/test-dsync-proxy-server-cmd.c
src/dsync/test-dsync-proxy.c

index 63b2417b4422ec1275d49ffe50180f0fad5809fb..90f02e62bb04f0003d1d7beadc541394f4c0cd75 100644 (file)
@@ -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);
index dcfea986046798358d0a3e2ce7f7814ba558cbc3..abff6be2d01cf94a4d6a084d20a1e7a1886c1514 100644 (file)
@@ -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;
index ff4f4a5ee3b06639fe3fa439d989e194dc600707..ee644e56d9f317ca1ac151be26b74e9e22c8d727 100644 (file)
@@ -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]);
index edcddc0b9618d2705a34b246159876152c528062..5cdaf8da48f29091854a29a5f4f0605ffc38da13 100644 (file)
@@ -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);
 }
 
index 03fbead71bc680a00bead358ce8a04b4237de702..726c81c221b37298459b4b3d5c70f715d56dfdd8 100644 (file)
@@ -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);
 
index 8494d72f13535baeade93ffa10472e40646161d4..880a1018df094c1e2b9ee2b11b9bc2c390821f9e 100644 (file)
@@ -58,7 +58,7 @@ static void ATTR_NORETURN
 usage(void)
 {
        fprintf(stderr,
-"usage: dsync [-b <mailbox>] [-r] [-u <user>] [-v]\n"
+"usage: dsync [-a <alt hierarchy sep>] [-b <mailbox>] [-r] [-u <user>] [-v]\n"
 "  mirror  <command to execute remote dsync>\n"
 "  convert <source mail_location>\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,
index 1a51eb449687d035a8804d361a3eaf0cc9aba7ca..c8ce958a867aadee7f914dcf738e8fe9926c08b8 100644 (file)
@@ -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;
index c46c099933573f5a3a66d65912dfc18547e078e7..11ed2f83a6d2fd796f00e6ea676cebddc036a952 100644 (file)
@@ -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);
index 0bd0c0867a0187d122d052edb473e7ef4cd82c3c..679088fda8c3fbf674eda82841c2068caec511ef 100644 (file)
@@ -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);