dovecot-2.0-sslstream: dsync: Fixed problems with syncing mailbo...

dovecot at dovecot.org dovecot at dovecot.org
Sat Feb 13 02:56:36 EET 2010


details:   http://hg.dovecot.org/dovecot-2.0-sslstream/rev/036db604f86c
changeset: 10374:036db604f86c
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Nov 19 17:28:48 2009 -0500
description:
dsync: Fixed problems with syncing mailbox names that are invalid on other side.

diffstat:

10 files changed, 145 insertions(+), 51 deletions(-)
src/dsync/dsync-brain.c                 |   10 +-
src/dsync/dsync-proxy-client.c          |   14 ++-
src/dsync/dsync-proxy-server-cmd.c      |   10 +-
src/dsync/dsync-worker-local.c          |  122 +++++++++++++++++++++++++------
src/dsync/dsync-worker-private.h        |    3 
src/dsync/dsync-worker.c                |    8 +-
src/dsync/dsync-worker.h                |    7 +
src/dsync/dsync.c                       |    9 +-
src/dsync/test-dsync-proxy-server-cmd.c |    8 +-
src/dsync/test-dsync-worker.c           |    5 -

diffs (truncated from 452 to 300 lines):

diff -r 0b101a864534 -r 036db604f86c src/dsync/dsync-brain.c
--- 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 @@ dsync_brain_sync_rename_mailbox(struct d
 	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 @@ dsync_brain_sync_update_mailboxes(struct
 	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);
 	}
 }
 
diff -r 0b101a864534 -r 036db604f86c src/dsync/dsync-proxy-client.c
--- 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
 static void
 proxy_client_worker_rename_mailbox(struct dsync_worker *_worker,
 				   const mailbox_guid_t *mailbox,
-				   const char *name)
-{
-	struct proxy_client_dsync_worker *worker =
-		(struct proxy_client_dsync_worker *)_worker;
+				   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 @@ proxy_client_worker_rename_mailbox(struc
 		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;
diff -r 0b101a864534 -r 036db604f86c src/dsync/dsync-proxy-server-cmd.c
--- 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
 cmd_box_rename(struct dsync_proxy_server *server, const char *const *args)
 {
 	mailbox_guid_t guid;
-
-	if (str_array_length(args) < 2)
+	struct dsync_mailbox dsync_box;
+
+	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;
 }
 
diff -r 0b101a864534 -r 036db604f86c src/dsync/dsync-worker-local.c
--- 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 @@ struct local_dsync_worker {
 	/* 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 @@ static unsigned int mailbox_guid_hash(co
 }
 
 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,20 +882,83 @@ mailbox_name_convert(struct local_dsync_
 
 	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);
@@ -895,11 +967,10 @@ local_worker_mailbox_alloc(struct local_
 		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 @@ local_worker_create_mailbox(struct dsync
 	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 @@ local_worker_rename_children(struct loca
 
 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 @@ local_worker_rename_mailbox(struct dsync
 		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 @@ local_worker_update_mailbox(struct dsync
 	if (selected)
 		local_worker_mailbox_close(worker);


More information about the dovecot-cvs mailing list