changeset 625:fe017093e4d8 HEAD

Don't allow '*' and '%' characters in mailbox names. Maildir RENAME works now properly when renaming folders having subfolders.
author Timo Sirainen <tss@iki.fi>
date Wed, 20 Nov 2002 18:03:36 +0200
parents 8bc4876397cd
children 5ce5aafe28d9
files src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/mbox/mbox-storage.c
diffstat 2 files changed, 62 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/maildir/maildir-storage.c	Wed Nov 20 16:59:11 2002 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Wed Nov 20 18:03:36 2002 +0200
@@ -13,6 +13,12 @@
 
 #define CREATE_MODE 0770 /* umask() should limit it more */
 
+typedef struct {
+	int found;
+	size_t oldnamelen;
+	const char *newname;
+} RenameContext;
+
 extern MailStorage maildir_storage;
 extern Mailbox maildir_mailbox;
 
@@ -68,7 +74,9 @@
 static int maildir_is_valid_name(MailStorage *storage, const char *name)
 {
 	return name[0] != '\0' && name[0] != storage->hierarchy_sep &&
-		strchr(name, '/') == NULL && strchr(name, '\\') == NULL;
+		name[strlen(name)-1] != storage->hierarchy_sep &&
+		strchr(name, '/') == NULL && strchr(name, '\\') == NULL &&
+		strchr(name, '*') == NULL && strchr(name, '%') == NULL;
 }
 
 /* create or fix maildir, ignore if it already exists */
@@ -309,10 +317,39 @@
 	return TRUE;
 }
 
+static void rename_subfolder(MailStorage *storage, const char *name,
+			     MailboxFlags flags __attr_unused__, void *context)
+{
+	RenameContext *ctx = context;
+	char oldpath[1024], newpath[1024];
+
+	i_assert(ctx->oldnamelen <= strlen(name));
+
+	i_snprintf(oldpath, sizeof(oldpath), "%s/.%s", storage->dir, name);
+	i_snprintf(newpath, sizeof(newpath), "%s/.%s.%s",
+		   storage->dir, ctx->newname, name + ctx->oldnamelen);
+
+	/* FIXME: it's possible to merge two folders if either one of them
+	   doesn't have existing root folder. We could check this but I'm not
+	   sure if it's worth it. It could be even considered as a feature.
+
+	   Anyway, the bug with merging is that if both folders have
+	   identically named subfolder they conflict. Just ignore those and
+	   leave them under the old folder. */
+	if (rename(oldpath, newpath) == 0 || errno == EEXIST)
+		ctx->found = TRUE;
+	else {
+		mail_storage_set_critical(storage, "rename(%s, %s) failed: %m",
+					  oldpath, newpath);
+	}
+}
+
 static int maildir_rename_mailbox(MailStorage *storage, const char *oldname,
 				  const char *newname)
 {
+	RenameContext ctx;
 	char oldpath[1024], newpath[1024];
+	int ret;
 
 	mail_storage_clear_error(storage);
 
@@ -325,12 +362,31 @@
 
 	/* NOTE: renaming INBOX works just fine with us, it's simply created
 	   the next time it's needed. Only problem with it is that it's not
-	   atomic operation but that can't be really helped. */
+	   atomic operation but that can't be really helped.
+
+	   NOTE: is't possible to rename a nonexisting folder which has
+	   subfolders. In that case we should ignore the rename() error. */
 	i_snprintf(oldpath, sizeof(oldpath), "%s/.%s", storage->dir, oldname);
 	i_snprintf(newpath, sizeof(newpath), "%s/.%s", storage->dir, newname);
-	if (rename(oldpath, newpath) == 0) {
+
+	ret = rename(oldpath, newpath);
+	if (ret == 0 || (errno == ENOENT && strcmp(oldname, "INBOX") != 0)) {
 		if (strcmp(oldname, "INBOX") == 0)
 			return move_inbox_data(storage, newpath);
+
+		ctx.found = ret == 0;
+		ctx.oldnamelen = strlen(oldname)+1;
+		ctx.newname = newname;
+		if (!maildir_find_mailboxes(storage,
+					    t_strconcat(oldname, ".*", NULL),
+					    rename_subfolder, &ctx))
+			return FALSE;
+
+		if (!ctx.found) {
+			mail_storage_set_error(storage,
+					       "Mailbox doesn't exist");
+			return FALSE;
+		}
 		return TRUE;
 	}
 
--- a/src/lib-storage/index/mbox/mbox-storage.c	Wed Nov 20 16:59:11 2002 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Wed Nov 20 18:03:36 2002 +0200
@@ -91,7 +91,9 @@
 	const char *p;
 	int newdir;
 
-	if (name[0] == '\0' || name[0] == storage->hierarchy_sep)
+	if (name[0] == '\0' || name[0] == storage->hierarchy_sep ||
+	    name[strlen(name)-1] == storage->hierarchy_sep ||
+	    strchr(name, '*') != NULL || strchr(name, '%') != NULL)
 		return FALSE;
 
 	/* make sure there's no "../" or "..\" stuff */