dovecot-2.0: Implemented initial support for renaming mailboxes ...

dovecot at dovecot.org dovecot at dovecot.org
Sat May 23 02:16:51 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/c86b65e4a510
changeset: 9353:c86b65e4a510
user:      Timo Sirainen <tss at iki.fi>
date:      Fri May 22 19:16:03 2009 -0400
description:
Implemented initial support for renaming mailboxes across namespaces.

diffstat:

12 files changed, 348 insertions(+), 222 deletions(-)
src/imap/cmd-rename.c                           |   41 +++----
src/lib-storage/index/dbox/dbox-storage.c       |  122 ++++++++++++++---------
src/lib-storage/index/maildir/maildir-storage.c |   26 ++--
src/lib-storage/index/shared/shared-list.c      |   74 +++++++------
src/lib-storage/list/mailbox-list-fs.c          |   99 +++++++++++++-----
src/lib-storage/list/mailbox-list-maildir.c     |   73 +++++++------
src/lib-storage/mailbox-list-private.h          |   11 +-
src/lib-storage/mailbox-list.c                  |   43 ++++++--
src/lib-storage/mailbox-list.h                  |   16 +--
src/plugins/acl/acl-mailbox-list.c              |   28 +++--
src/plugins/listescape/listescape-plugin.c      |   20 ++-
src/plugins/mail-log/mail-log-plugin.c          |   17 +--

diffs (truncated from 965 to 300 lines):

diff -r 9f2403f3e345 -r c86b65e4a510 src/imap/cmd-rename.c
--- a/src/imap/cmd-rename.c	Fri May 22 18:28:08 2009 -0400
+++ b/src/imap/cmd-rename.c	Fri May 22 19:16:03 2009 -0400
@@ -7,8 +7,8 @@ bool cmd_rename(struct client_command_co
 bool cmd_rename(struct client_command_context *cmd)
 {
 	struct mail_storage *old_storage, *new_storage;
-	struct mailbox_list *list;
-	struct mail_namespace *ns;
+	struct mailbox_list *old_list, *new_list;
+	struct mail_namespace *old_ns;
 	const char *oldname, *newname;
 	unsigned int oldlen;
 
@@ -22,33 +22,30 @@ bool cmd_rename(struct client_command_co
 	old_storage = client_find_storage(cmd, &oldname);
 	if (old_storage == NULL)
 		return TRUE;
+	old_list = mail_storage_get_list(old_storage);
 
 	new_storage = client_find_storage(cmd, &newname);
 	if (new_storage == NULL)
 		return TRUE;
+	new_list = mail_storage_get_list(new_storage);
 
-	if (old_storage != new_storage) {
-		client_send_tagline(cmd,
-			"NO Can't rename mailbox to another storage type.");
-		return TRUE;
+	if (old_storage == new_storage) {
+		/* disallow box -> box/child, because it may break clients and
+		   there's really no point in doing it anyway. */
+		old_ns = mailbox_list_get_namespace(old_list);
+		oldlen = strlen(oldname);
+		if (strncmp(oldname, newname, oldlen) == 0 &&
+		    newname[oldlen] == old_ns->real_sep) {
+			client_send_tagline(cmd,
+				"NO Can't rename mailbox under its own child.");
+			return TRUE;
+		}
 	}
 
-	/* disallow box -> box/child, because it may break clients and there's
-	   really no point in doing it anyway. */
-	list = mail_storage_get_list(old_storage);
-	ns = mailbox_list_get_namespace(list);
-	oldlen = strlen(oldname);
-	if (strncmp(oldname, newname, oldlen) == 0 &&
-	    newname[oldlen] == ns->real_sep) {
-		client_send_tagline(cmd,
-			"NO Can't rename mailbox under its own child.");
-		return TRUE;
-	}
-
-	if (mailbox_list_rename_mailbox(list, oldname, newname) < 0)
-		client_send_list_error(cmd, list);
-	else {
+	if (mailbox_list_rename_mailbox(old_list, oldname,
+					new_list, newname, TRUE) < 0)
+		client_send_list_error(cmd, old_list);
+	else
 		client_send_tagline(cmd, "OK Rename completed.");
-	}
 	return TRUE;
 }
diff -r 9f2403f3e345 -r c86b65e4a510 src/lib-storage/index/dbox/dbox-storage.c
--- a/src/lib-storage/index/dbox/dbox-storage.c	Fri May 22 18:28:08 2009 -0400
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Fri May 22 19:16:03 2009 -0400
@@ -39,11 +39,14 @@ static int
 static int
 dbox_list_delete_mailbox(struct mailbox_list *list, const char *name);
 static int
-dbox_list_rename_mailbox(struct mailbox_list *list,
-			 const char *oldname, const char *newname);
-static int
-dbox_list_rename_mailbox_pre(struct mailbox_list *list,
-			     const char *oldname, const char *newname);
+dbox_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
+			 struct mailbox_list *newlist, const char *newname,
+			 bool rename_children);
+static int
+dbox_list_rename_mailbox_pre(struct mailbox_list *oldlist,
+			     const char *oldname,
+			     struct mailbox_list *newlist,
+			     const char *newname);
 static int dbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
 				     const char *dir, const char *fname,
 				     const char *mailbox_name,
@@ -605,47 +608,59 @@ dbox_list_delete_mailbox(struct mailbox_
 	return -1;
 }
 
-static bool
-dbox_list_rename_get_alt_paths(struct mailbox_list *list,
-			       const char *oldname, const char *newname,
+static int
+dbox_list_rename_get_alt_paths(struct mailbox_list *oldlist,
+			       const char *oldname,
+			       struct mailbox_list *newlist,
+			       const char *newname,
+			       enum mailbox_list_path_type path_type,
 			       const char **oldpath_r, const char **newpath_r)
 {
-	struct dbox_storage *storage = DBOX_LIST_CONTEXT(list);
+	struct dbox_storage *oldstorage = DBOX_LIST_CONTEXT(oldlist);
+	struct dbox_storage *newstorage = DBOX_LIST_CONTEXT(newlist);
 	const char *path;
 
-	if (storage->alt_dir == NULL)
-		return FALSE;
-
-	path = mailbox_list_get_path(list, oldname, MAILBOX_LIST_PATH_TYPE_DIR);
-	*oldpath_r = dbox_get_alt_path(storage, path);
+	path = mailbox_list_get_path(oldlist, oldname, path_type);
+	*oldpath_r = dbox_get_alt_path(oldstorage, path);
 	if (*oldpath_r == NULL)
-		return FALSE;
-
-	path = mailbox_list_get_path(list, newname, MAILBOX_LIST_PATH_TYPE_DIR);
-	*newpath_r = dbox_get_alt_path(storage, path);
-	i_assert(*newpath_r != NULL);
-	return TRUE;
-}
-
-static int
-dbox_list_rename_mailbox_pre(struct mailbox_list *list,
-			     const char *oldname, const char *newname)
+		return 0;
+
+	path = mailbox_list_get_path(newlist, newname, path_type);
+	*newpath_r = dbox_get_alt_path(newstorage, path);
+	if (*newpath_r == NULL) {
+		/* destination dbox storage doesn't have alt-path defined.
+		   we can't do the rename easily. */
+		mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
+			"Can't rename mailboxes across specified storages.");
+		return -1;
+	}
+	return 1;
+}
+
+static int
+dbox_list_rename_mailbox_pre(struct mailbox_list *oldlist,
+			     const char *oldname,
+			     struct mailbox_list *newlist,
+			     const char *newname)
 {
 	const char *alt_oldpath, *alt_newpath;
 	struct stat st;
-
-	if (!dbox_list_rename_get_alt_paths(list, oldname, newname,
-					    &alt_oldpath, &alt_newpath))
-		return 0;
+	int ret;
+
+	ret = dbox_list_rename_get_alt_paths(oldlist, oldname, newlist, newname,
+					     MAILBOX_LIST_PATH_TYPE_DIR,
+					     &alt_oldpath, &alt_newpath);
+	if (ret <= 0)
+		return ret;
 
 	if (stat(alt_newpath, &st) == 0) {
 		/* race condition or a directory left there lying around?
 		   safest to just report error. */
-		mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
+		mailbox_list_set_error(oldlist, MAIL_ERROR_EXISTS,
 				       "Target mailbox already exists");
 		return -1;
 	} else if (errno != ENOENT) {
-		mailbox_list_set_critical(list, "stat(%s) failed: %m",
+		mailbox_list_set_critical(oldlist, "stat(%s) failed: %m",
 					  alt_newpath);
 		return -1;
 	}
@@ -653,25 +668,42 @@ dbox_list_rename_mailbox_pre(struct mail
 }
 
 static int
-dbox_list_rename_mailbox(struct mailbox_list *list,
-			 const char *oldname, const char *newname)
-{
-	struct dbox_storage *storage = DBOX_LIST_CONTEXT(list);
-	const char *alt_oldpath, *alt_newpath;
-
-	if (storage->list_module_ctx.super.rename_mailbox(list, oldname,
-							  newname) < 0)
-		return -1;
-
-	if (!dbox_list_rename_get_alt_paths(list, oldname, newname,
-					    &alt_oldpath, &alt_newpath))
-		return 0;
+dbox_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
+			 struct mailbox_list *newlist, const char *newname,
+			 bool rename_children)
+{
+	struct dbox_storage *oldstorage = DBOX_LIST_CONTEXT(oldlist);
+	enum mailbox_list_path_type path_type;
+	const char *alt_oldpath, *alt_newpath, *path;
+	int ret;
+
+	if (oldstorage->list_module_ctx.super.
+	    		rename_mailbox(oldlist, oldname, newlist, newname,
+				       rename_children) < 0)
+		return -1;
+
+	path_type = rename_children ? MAILBOX_LIST_PATH_TYPE_DIR :
+		MAILBOX_LIST_PATH_TYPE_MAILBOX;
+	ret = dbox_list_rename_get_alt_paths(oldlist, oldname, newlist, newname,
+					     path_type, &alt_oldpath,
+					     &alt_newpath);
+	if (ret <= 0)
+		return ret;
 
 	if (rename(alt_oldpath, alt_newpath) == 0) {
 		/* ok */
+		if (!rename_children) {
+			path = mailbox_list_get_path(oldlist, oldname,
+						     MAILBOX_LIST_PATH_TYPE_DIR);
+			if (rmdir(path) < 0 &&
+			    errno != ENOENT && errno != ENOTEMPTY) {
+				mailbox_list_set_critical(oldlist,
+					"rmdir(%s) failed: %m", path);
+			}
+		}
 	} else if (errno != ENOENT) {
 		/* renaming is done already, so just log the error */
-		mailbox_list_set_critical(list, "rename(%s, %s) failed: %m",
+		mailbox_list_set_critical(oldlist, "rename(%s, %s) failed: %m",
 					  alt_oldpath, alt_newpath);
 	}
 	return 0;
diff -r 9f2403f3e345 -r c86b65e4a510 src/lib-storage/index/maildir/maildir-storage.c
--- a/src/lib-storage/index/maildir/maildir-storage.c	Fri May 22 18:28:08 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Fri May 22 19:16:03 2009 -0400
@@ -43,8 +43,9 @@ static int
 static int
 maildir_list_delete_mailbox(struct mailbox_list *list, const char *name);
 static int
-maildir_list_rename_mailbox(struct mailbox_list *list,
-			    const char *oldname, const char *newname);
+maildir_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
+			    struct mailbox_list *newlist, const char *newname,
+			    bool rename_children);
 static int
 maildir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
 			     const char *dir, const char *fname,
@@ -829,28 +830,31 @@ maildir_list_delete_mailbox(struct mailb
 	return 0;
 }
 
-static int maildir_list_rename_mailbox(struct mailbox_list *list,
-				       const char *oldname, const char *newname)
-{
-	struct maildir_storage *storage = MAILDIR_LIST_CONTEXT(list);
+static int
+maildir_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
+			    struct mailbox_list *newlist, const char *newname,
+			    bool rename_children)
+{
+	struct maildir_storage *oldstorage = MAILDIR_LIST_CONTEXT(oldlist);
 	const char *path1, *path2;
 
 	if (strcmp(oldname, "INBOX") == 0) {
 		/* INBOX often exists as the root ~/Maildir.
 		   We can't rename it then. */
-		path1 = mailbox_list_get_path(list, oldname,
+		path1 = mailbox_list_get_path(oldlist, oldname,
 					      MAILBOX_LIST_PATH_TYPE_MAILBOX);
-		path2 = mailbox_list_get_path(list, NULL,
+		path2 = mailbox_list_get_path(oldlist, NULL,
 					      MAILBOX_LIST_PATH_TYPE_MAILBOX);
 		if (strcmp(path1, path2) == 0) {
-			mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+			mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
 				"Renaming INBOX isn't supported.");
 			return -1;
 		}
 	}
 
-	return storage->list_module_ctx.super.
-		rename_mailbox(list, oldname, newname);
+	return oldstorage->list_module_ctx.super.
+		rename_mailbox(oldlist, oldname, newlist, newname,
+			       rename_children);
 }
 
 static int maildir_storage_mailbox_close(struct mailbox *box)
diff -r 9f2403f3e345 -r c86b65e4a510 src/lib-storage/index/shared/shared-list.c
--- a/src/lib-storage/index/shared/shared-list.c	Fri May 22 18:28:08 2009 -0400
+++ b/src/lib-storage/index/shared/shared-list.c	Fri May 22 19:16:03 2009 -0400
@@ -245,52 +245,62 @@ shared_list_delete_mailbox(struct mailbo
 	return ret;
 }
 
-static int shared_list_rename_get_ns(struct mailbox_list *list,
-				     const char **oldname, const char **newname,
+static int shared_list_rename_get_ns(struct mailbox_list *oldlist,
+				     const char **oldname,
+				     struct mailbox_list *newlist,
+				     const char **newname,


More information about the dovecot-cvs mailing list