changeset 9533:530bbade4e3f HEAD

Added support for creating/updating mailboxes with given metadata (guid, uid validity, etc).
author Timo Sirainen <tss@iki.fi>
date Fri, 26 Jun 2009 16:11:59 -0400
parents 29733d23d903
children 8760bc0b1c3a
files src/imap/cmd-create.c src/lib-lda/mail-deliver.c src/lib-storage/index/cydir/cydir-storage.c src/lib-storage/index/dbox/dbox-save.c src/lib-storage/index/dbox/dbox-storage-rebuild.c src/lib-storage/index/dbox/dbox-storage.c src/lib-storage/index/dbox/dbox-storage.h src/lib-storage/index/dbox/dbox-sync-rebuild.c src/lib-storage/index/index-storage.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/index/maildir/maildir-uidlist.h src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/index/mbox/mbox-storage.h src/lib-storage/index/mbox/mbox-sync.c src/lib-storage/index/raw/raw-storage.c src/lib-storage/index/shared/shared-storage.c src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/lib-storage/test-mail-storage.c src/lib-storage/test-mailbox.c src/plugins/acl/acl-mailbox.c src/plugins/acl/acl-storage.c src/plugins/autocreate/autocreate-plugin.c src/plugins/convert/convert-storage.c src/plugins/lazy-expunge/lazy-expunge-plugin.c src/plugins/listescape/listescape-plugin.c src/plugins/virtual/virtual-storage.c
diffstat 29 files changed, 443 insertions(+), 299 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/cmd-create.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/imap/cmd-create.c	Fri Jun 26 16:11:59 2009 -0400
@@ -7,8 +7,8 @@
 bool cmd_create(struct client_command_context *cmd)
 {
 	struct mail_namespace *ns;
-	struct mail_storage *storage;
 	const char *mailbox, *full_mailbox;
+	struct mailbox *box;
 	bool directory;
 	size_t len;
 
@@ -40,10 +40,11 @@
 					CLIENT_VERIFY_MAILBOX_SHOULD_NOT_EXIST))
 		return TRUE;
 
-	storage = mail_namespace_get_default_storage(ns);
-	if (mail_storage_mailbox_create(storage, ns, mailbox, directory) < 0)
-		client_send_storage_error(cmd, storage);
+	box = mailbox_alloc(ns->list, mailbox, NULL, 0);
+	if (mailbox_create(box, NULL, directory) < 0)
+		client_send_storage_error(cmd, mailbox_get_storage(box));
 	else
 		client_send_tagline(cmd, "OK Create completed.");
+	mailbox_close(&box);
 	return TRUE;
 }
--- a/src/lib-lda/mail-deliver.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-lda/mail-deliver.c	Fri Jun 26 16:11:59 2009 -0400
@@ -107,13 +107,15 @@
 
 	storage = mailbox_get_storage(box);
 	*error_r = mail_storage_get_last_error(storage, &error);
-	mailbox_close(&box);
-	if (!ctx->set->lda_mailbox_autocreate || error != MAIL_ERROR_NOTFOUND)
+	if (!ctx->set->lda_mailbox_autocreate || error != MAIL_ERROR_NOTFOUND) {
+		mailbox_close(&box);
 		return NULL;
+	}
 
 	/* try creating it. */
-	if (mail_storage_mailbox_create(storage, ns, name, FALSE) < 0) {
+	if (mailbox_create(box, NULL, FALSE) < 0) {
 		*error_r = mail_storage_get_last_error(storage, &error);
+		mailbox_close(&box);
 		return NULL;
 	}
 	if (ctx->set->lda_mailbox_autosubscribe) {
@@ -122,8 +124,6 @@
 	}
 
 	/* and try opening again */
-	box = mailbox_alloc(ns->list, name, NULL, flags);
-	storage = mailbox_get_storage(box);
 	if (mailbox_open(box) < 0 ||
 	    mailbox_sync(box, 0, 0, NULL) < 0) {
 		*error_r = mail_storage_get_last_error(storage, &error);
--- a/src/lib-storage/index/cydir/cydir-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/cydir/cydir-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -128,21 +128,46 @@
 }
 
 static int
-cydir_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
-		     const char *name, bool directory ATTR_UNUSED)
+cydir_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
+{
+	struct cydir_mailbox *mbox = (struct cydir_mailbox *)box;
+	struct mail_index_transaction *trans;
+
+	trans = mail_index_transaction_begin(mbox->ibox.view, 0);
+	if (update->uid_validity != 0) {
+		mail_index_update_header(trans,
+			offsetof(struct mail_index_header, uid_validity),
+			&update->uid_validity, sizeof(update->uid_validity),
+			TRUE);
+	}
+	/* FIXME: update next_uid, highestmodseq. guid is also missing.. */
+	if (mail_index_transaction_commit(&trans) < 0) {
+		mail_storage_set_internal_error(box->storage);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+cydir_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
+		     bool directory)
 {
 	const char *path;
 	struct stat st;
 
-	path = mailbox_list_get_path(list, name,
+	path = mailbox_list_get_path(box->list, box->name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(path, &st) == 0) {
-		mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
+		mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
 		return -1;
 	}
 
-	return create_cydir(storage, list, path);
+	if (create_cydir(box->storage, box->list, path) < 0)
+		return -1;
+
+	return directory || update == NULL ? 0 :
+		cydir_mailbox_update(box, update);
 }
 
 static int
@@ -345,7 +370,6 @@
 		cydir_storage_get_list_settings,
 		NULL,
 		cydir_mailbox_alloc,
-		cydir_mailbox_create,
 		NULL
 	}
 };
@@ -361,6 +385,8 @@
 		index_storage_mailbox_enable,
 		cydir_mailbox_open,
 		index_storage_mailbox_close,
+		cydir_mailbox_create,
+		cydir_mailbox_update,
 		index_storage_get_status,
 		NULL,
 		NULL,
--- a/src/lib-storage/index/dbox/dbox-save.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/dbox/dbox-save.c	Fri Jun 26 16:11:59 2009 -0400
@@ -368,7 +368,7 @@
 		unsigned int i, count;
 		uint32_t next_map_uid = first_map_uid;
 
-		dbox_update_header(ctx->mbox, ctx->trans);
+		dbox_update_header(ctx->mbox, ctx->trans, NULL);
 
 		memset(&rec, 0, sizeof(rec));
 		rec.save_date = ioloop_time;
--- a/src/lib-storage/index/dbox/dbox-storage-rebuild.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/dbox/dbox-storage-rebuild.c	Fri Jun 26 16:11:59 2009 -0400
@@ -543,17 +543,20 @@
 			break;
 
 		(void)mail_storage_get_last_error(box->storage, &error);
+		if (error == MAIL_ERROR_NOTFOUND && !created) {
+			/* mailbox doesn't exist currently? see if creating
+			   it helps. */
+			created = TRUE;
+			(void)mailbox_create(box, NULL, FALSE);
+			mailbox_close(&box);
+			continue;
+		}
+
 		mailbox_close(&box);
 		if (error == MAIL_ERROR_TEMP)
 			return -1;
 
-		if (error == MAIL_ERROR_NOTFOUND && !created) {
-			/* mailbox doesn't exist currently? see if creating
-			   it helps. */
-			created = TRUE;
-			(void)mail_storage_mailbox_create(storage,
-				ctx->default_list->ns, mailbox, FALSE);
-		} else if (strcmp(mailbox, "INBOX") != 0) {
+		if (strcmp(mailbox, "INBOX") != 0) {
 			/* see if we can save to INBOX instead. */
 			mailbox = "INBOX";
 		} else {
--- a/src/lib-storage/index/dbox/dbox-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -191,24 +191,6 @@
 	return mailbox_uidvalidity_next(path);
 }
 
-static bool
-dbox_index_header_has_mailbox_guid(const struct dbox_index_header *hdr)
-{
-	unsigned int i;
-
-	for (i = 0; i < sizeof(hdr->mailbox_guid); i++) {
-		if (hdr->mailbox_guid[i] != 0)
-			return TRUE;
-	}
-	return FALSE;
-}
-
-void dbox_set_mailbox_guid(struct dbox_index_header *hdr)
-{
-	if (!dbox_index_header_has_mailbox_guid(hdr))
-		mail_generate_guid_128(hdr->mailbox_guid);
-}
-
 int dbox_read_header(struct dbox_mailbox *mbox, struct dbox_index_header *hdr)
 {
 	const void *data;
@@ -229,7 +211,8 @@
 }
 
 void dbox_update_header(struct dbox_mailbox *mbox,
-			struct mail_index_transaction *trans)
+			struct mail_index_transaction *trans,
+			const struct mailbox_update *update)
 {
 	struct dbox_index_header hdr, new_hdr;
 
@@ -237,7 +220,14 @@
 		memset(&hdr, 0, sizeof(hdr));
 
 	new_hdr = hdr;
-	dbox_set_mailbox_guid(&new_hdr);
+
+	if (update != NULL && !mailbox_guid_is_empty(update->mailbox_guid)) {
+		memcpy(new_hdr.mailbox_guid, update->mailbox_guid,
+		       sizeof(new_hdr.mailbox_guid));
+	} else if (!mailbox_guid_is_empty(new_hdr.mailbox_guid)) {
+		mail_generate_guid_128(new_hdr.mailbox_guid);
+	}
+
 	new_hdr.map_uid_validity =
 		dbox_map_get_uid_validity(mbox->storage->map);
 	if (memcmp(&hdr, &new_hdr, sizeof(hdr)) != 0) {
@@ -246,23 +236,39 @@
 	}
 }
 
-static int dbox_write_index_header(struct mailbox *box)
+static int dbox_write_index_header(struct mailbox *box,
+				   const struct mailbox_update *update)
 {
 	struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
 	struct mail_index_transaction *trans;
-	uint32_t uid_validity;
+	const struct mail_index_header *hdr;
+	uint32_t uid_validity, uid_next;
 
 	if (dbox_map_open(mbox->storage->map, TRUE) < 0)
 		return -1;
 
+	hdr = mail_index_get_header(mbox->ibox.view);
 	trans = mail_index_transaction_begin(mbox->ibox.view, 0);
-	dbox_update_header(mbox, trans);
+	dbox_update_header(mbox, trans, update);
+
+	if (update != NULL && update->uid_validity != 0)
+		uid_validity = update->uid_validity;
+	else if (hdr->uid_validity == 0) {
+		/* set uidvalidity */
+		uid_validity = dbox_get_uidvalidity_next(box->list);
+	}
 
-	/* set uidvalidity */
-	uid_validity = dbox_get_uidvalidity_next(box->list);
-	mail_index_update_header(trans,
-		offsetof(struct mail_index_header, uid_validity),
-		&uid_validity, sizeof(uid_validity), TRUE);
+	if (hdr->uid_validity != uid_validity) {
+		mail_index_update_header(trans,
+			offsetof(struct mail_index_header, uid_validity),
+			&uid_validity, sizeof(uid_validity), TRUE);
+	}
+	if (update != NULL && hdr->next_uid < update->min_next_uid) {
+		uid_next = update->min_next_uid;
+		mail_index_update_header(trans,
+			offsetof(struct mail_index_header, next_uid),
+			&uid_next, sizeof(uid_next), TRUE);
+	}
 
 	if (mail_index_transaction_commit(&trans) < 0) {
 		mail_storage_set_internal_error(box->storage);
@@ -272,7 +278,8 @@
 	return 0;
 }
 
-static int create_dbox(struct mailbox *box)
+static int dbox_mailbox_create_indexes(struct mailbox *box,
+				       const struct mailbox_update *update)
 {
 	struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
 	mode_t mode;
@@ -285,7 +292,7 @@
 		if (index_storage_mailbox_open(box) < 0)
 			return -1;
 		mbox->creating = TRUE;
-		ret = dbox_write_index_header(box);
+		ret = dbox_write_index_header(box, update);
 		mbox->creating = FALSE;
 		if (ret < 0)
 			return -1;
@@ -336,7 +343,7 @@
 		if (strcmp(box->name, "INBOX") == 0 &&
 		    (box->list->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
 			/* INBOX always exists, create it */
-			if (create_dbox(box) < 0)
+			if (dbox_mailbox_create_indexes(box, NULL) < 0)
 				return -1;
 			return box->opened ? 0 :
 				index_storage_mailbox_open(box);
@@ -373,9 +380,9 @@
 	if (dbox_read_header(mbox, &hdr) < 0)
 		memset(&hdr, 0, sizeof(hdr));
 
-	if (!dbox_index_header_has_mailbox_guid(&hdr)) {
+	if (!mailbox_guid_is_empty(hdr.mailbox_guid)) {
 		/* regenerate it */
-		if (dbox_write_index_header(box) < 0 ||
+		if (dbox_write_index_header(box, NULL) < 0 ||
 		    dbox_read_header(mbox, &hdr) < 0)
 			return;
 	}
@@ -394,19 +401,17 @@
 }
 
 static int
-dbox_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
-		    const char *name, bool directory)
+dbox_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
+		    bool directory)
 {
 	const char *path, *alt_path;
-	struct mailbox *box;
 	struct stat st;
-	int ret;
 
-	path = mailbox_list_get_path(list, name,
+	path = mailbox_list_get_path(box->list, box->name,
 				     directory ? MAILBOX_LIST_PATH_TYPE_DIR :
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(path, &st) == 0) {
-		mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
+		mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
 		return -1;
 	}
@@ -415,14 +420,14 @@
 		mode_t mode;
 		gid_t gid;
 
-		mailbox_list_get_dir_permissions(list, NULL, &mode, &gid);
+		mailbox_list_get_dir_permissions(box->list, NULL, &mode, &gid);
 		if (mkdir_parents_chown(path, mode, (uid_t)-1, gid) == 0)
 			return 0;
 		else if (errno == EEXIST) {
-			mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
+			mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
 					       "Mailbox already exists");
-		} else if (!mail_storage_set_error_from_errno(storage)) {
-			mail_storage_set_critical(storage,
+		} else if (!mail_storage_set_error_from_errno(box->storage)) {
+			mail_storage_set_critical(box->storage,
 						  "mkdir(%s) failed: %m", path);
 		}
 		return -1;
@@ -432,18 +437,24 @@
 	   race conditions with RENAME/DELETE), but if something crashed and
 	   left it lying around we don't want to start overwriting files in
 	   it. */
-	alt_path = dbox_get_alt_path(list, path);
+	alt_path = dbox_get_alt_path(box->list, path);
 	if (alt_path != NULL && stat(alt_path, &st) == 0) {
-		mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
+		mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
 		return -1;
 	}
 
-	box = dbox_mailbox_alloc(storage, list, name, NULL,
-				 MAILBOX_FLAG_KEEP_RECENT);
-	ret = create_dbox(box);
-	mailbox_close(&box);
-	return ret;
+	return dbox_mailbox_create_indexes(box, update);
+}
+
+static int
+dbox_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
+{
+	if (!box->opened) {
+		if (index_storage_mailbox_open(box) < 0)
+			return -1;
+	}
+	return dbox_write_index_header(box, update);
 }
 
 static int
@@ -848,7 +859,6 @@
 		dbox_storage_get_list_settings,
 		NULL,
 		dbox_mailbox_alloc,
-		dbox_mailbox_create,
 		dbox_sync_purge
 	}
 };
@@ -864,6 +874,8 @@
 		index_storage_mailbox_enable,
 		dbox_mailbox_open,
 		dbox_mailbox_close,
+		dbox_mailbox_create,
+		dbox_mailbox_update,
 		dbox_storage_get_status,
 		NULL,
 		NULL,
--- a/src/lib-storage/index/dbox/dbox-storage.h	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/dbox/dbox-storage.h	Fri Jun 26 16:11:59 2009 -0400
@@ -108,10 +108,10 @@
 int dbox_mail_lookup(struct dbox_mailbox *mbox, struct mail_index_view *view,
 		     uint32_t seq, uint32_t *map_uid_r);
 uint32_t dbox_get_uidvalidity_next(struct mailbox_list *list);
-void dbox_set_mailbox_guid(struct dbox_index_header *hdr);
 int dbox_read_header(struct dbox_mailbox *mbox, struct dbox_index_header *hdr);
 void dbox_update_header(struct dbox_mailbox *mbox,
-			struct mail_index_transaction *trans);
+			struct mail_index_transaction *trans,
+			const struct mailbox_update *update);
 
 struct mail_save_context *
 dbox_save_alloc(struct mailbox_transaction_context *_t);
--- a/src/lib-storage/index/dbox/dbox-sync-rebuild.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/dbox/dbox-sync-rebuild.c	Fri Jun 26 16:11:59 2009 -0400
@@ -352,7 +352,8 @@
 
 	if (dbox_read_header(ctx->mbox, &hdr) < 0)
 		memset(&hdr, 0, sizeof(hdr));
-	dbox_set_mailbox_guid(&hdr);
+	if (!mailbox_guid_is_empty(hdr.mailbox_guid))
+		mail_generate_guid_128(hdr.mailbox_guid);
 	if (hdr.highest_maildir_uid < ctx->mbox->highest_maildir_uid)
 		hdr.highest_maildir_uid = ctx->mbox->highest_maildir_uid;
 	hdr.map_uid_validity = !ctx->storage_rebuild ? 0 :
--- a/src/lib-storage/index/index-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/index-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -377,23 +377,10 @@
 	enum mail_index_open_flags index_flags;
 	const char *index_dir;
 	struct stat st;
-	gid_t dir_gid;
 	int ret;
 
 	i_assert(!box->opened);
 
-	if (box->file_create_mode == 0) {
-		mailbox_list_get_permissions(box->list, box->name,
-					     &box->file_create_mode,
-					     &box->file_create_gid);
-		mailbox_list_get_dir_permissions(box->list, box->name,
-						 &box->dir_create_mode,
-						 &dir_gid);
-		mail_index_set_permissions(ibox->index,
-					   box->file_create_mode,
-					   box->file_create_gid);
-	}
-
 	index_flags = mail_storage_settings_to_index_flags(box->storage->set);
 	if (!ibox->move_to_memory)
 		index_flags |= MAIL_INDEX_OPEN_FLAG_CREATE;
@@ -461,6 +448,7 @@
 {
 	struct mailbox *box = &ibox->box;
 	const char *path;
+	gid_t dir_gid;
 
 	if (name != NULL)
 		box->name = p_strdup(box->pool, name);
@@ -492,6 +480,18 @@
 	ibox->index = index_storage_alloc(box->list, name, flags, index_prefix);
 	ibox->md5hdr_ext_idx =
 		mail_index_ext_register(ibox->index, "header-md5", 0, 16, 1);
+
+	if (box->file_create_mode == 0) {
+		mailbox_list_get_permissions(box->list, name,
+					     &box->file_create_mode,
+					     &box->file_create_gid);
+		mailbox_list_get_dir_permissions(box->list, name,
+						 &box->dir_create_mode,
+						 &dir_gid);
+		mail_index_set_permissions(ibox->index,
+					   box->file_create_mode,
+					   box->file_create_gid);
+	}
 }
 
 int index_storage_mailbox_enable(struct mailbox *box,
--- a/src/lib-storage/index/maildir/maildir-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -475,30 +475,55 @@
 }
 
 static int
-maildir_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
-		       const char *name, bool directory ATTR_UNUSED)
+maildir_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
+{
+	struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
+	struct maildir_uidlist *uidlist = mbox->uidlist;
+	int ret;
+
+	if (maildir_uidlist_lock(uidlist) <= 0)
+		return -1;
+
+	if (!mailbox_guid_is_empty(update->mailbox_guid))
+		maildir_uidlist_set_mailbox_guid(uidlist, update->mailbox_guid);
+	if (update->uid_validity != 0)
+		maildir_uidlist_set_uid_validity(uidlist, update->uid_validity);
+	if (update->min_next_uid != 0) {
+		maildir_uidlist_set_next_uid(uidlist, update->min_next_uid,
+					     FALSE);
+	}
+	/* FIXME: update highestmodseq */
+
+	ret = maildir_uidlist_update(uidlist);
+	maildir_uidlist_unlock(uidlist);
+	return ret;
+}
+
+static int
+maildir_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
+		       bool directory)
 {
 	struct stat st;
 	const char *path, *root_dir, *shared_path;
 	mode_t old_mask;
 	int fd;
 
-	path = mailbox_list_get_path(list, name,
+	path = mailbox_list_get_path(box->list, box->name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
-	root_dir = mailbox_list_get_path(list, NULL,
+	root_dir = mailbox_list_get_path(box->list, NULL,
 					 MAILBOX_LIST_PATH_TYPE_MAILBOX);
 
 	/* if dovecot-shared exists in the root dir, create the mailbox using
 	   its permissions and gid, and copy the dovecot-shared inside it. */
 	shared_path = t_strconcat(root_dir, "/dovecot-shared", NULL);
 	if (stat(shared_path, &st) == 0) {
-		if (maildir_create_shared(storage, list->ns, path,
+		if (maildir_create_shared(box->storage, box->list->ns, path,
 					  st.st_mode & 0666, st.st_gid) < 0)
 			return -1;
 	} else {
-		mailbox_list_get_dir_permissions(list, NULL,
+		mailbox_list_get_dir_permissions(box->list, NULL,
 						 &st.st_mode, &st.st_gid);
-		if (create_maildir(storage, list->ns, path,
+		if (create_maildir(box->storage, box->list->ns, path,
 				   st.st_mode, st.st_gid, FALSE) < 0)
 			return -1;
 	}
@@ -513,19 +538,20 @@
 		/* if dovecot-shared exists, use the same group */
 		if (st.st_gid != (gid_t)-1 &&
 		    fchown(fd, (uid_t)-1, st.st_gid) < 0) {
-			mail_storage_set_critical(storage,
+			mail_storage_set_critical(box->storage,
 				"fchown(%s) failed: %m", path);
 		}
 		(void)close(fd);
 	} else if (errno == ENOENT) {
-		mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
+		mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
 			"Mailbox was deleted while it was being created");
 		return -1;
 	} else {
-		mail_storage_set_critical(storage,
+		mail_storage_set_critical(box->storage,
 			"open(%s, O_CREAT) failed: %m", path);
 	}
-	return 0;
+	return directory || update == NULL ? 0 :
+		maildir_mailbox_update(box, update);
 }
 
 static void
@@ -1026,7 +1052,6 @@
 		maildir_storage_get_list_settings,
 		maildir_storage_autodetect,
 		maildir_mailbox_alloc,
-		maildir_mailbox_create,
 		NULL
 	}
 };
@@ -1042,6 +1067,8 @@
 		index_storage_mailbox_enable,
 		maildir_mailbox_open,
 		maildir_mailbox_close,
+		maildir_mailbox_create,
+		maildir_mailbox_update,
 		maildir_storage_get_status,
 		maildir_list_index_has_changed,
 		maildir_list_index_update_sync,
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Fri Jun 26 16:11:59 2009 -0400
@@ -1080,19 +1080,35 @@
 	return 0;
 }
 
+void maildir_uidlist_set_mailbox_guid(struct maildir_uidlist *uidlist,
+				      const uint8_t mailbox_guid[MAILBOX_GUID_SIZE])
+{
+	if (memcmp(uidlist->mailbox_guid, mailbox_guid,
+		   sizeof(uidlist->mailbox_guid)) != 0) {
+		memcpy(uidlist->mailbox_guid, mailbox_guid,
+		       sizeof(uidlist->mailbox_guid));
+		uidlist->recreate = TRUE;
+	}
+}
+
 void maildir_uidlist_set_uid_validity(struct maildir_uidlist *uidlist,
 				      uint32_t uid_validity)
 {
 	i_assert(uid_validity != 0);
 
-	uidlist->uid_validity = uid_validity;
+	if (uid_validity != uidlist->uid_validity) {
+		uidlist->uid_validity = uid_validity;
+		uidlist->recreate = TRUE;
+	}
 }
 
 void maildir_uidlist_set_next_uid(struct maildir_uidlist *uidlist,
 				  uint32_t next_uid, bool force)
 {
-	if (uidlist->next_uid < next_uid || force)
+	if (uidlist->next_uid < next_uid || force) {
 		uidlist->next_uid = next_uid;
+		uidlist->recreate = TRUE;
+	}
 }
 
 static void
@@ -1163,8 +1179,14 @@
 {
 	const struct mail_index_header *hdr;
 
-	hdr = mail_index_get_header(uidlist->ibox->view);
-	uidlist->uid_validity = hdr->uid_validity != 0 ? hdr->uid_validity :
+	if (uidlist->ibox->box.opened) {
+		hdr = mail_index_get_header(uidlist->ibox->view);
+		if (hdr->uid_validity != 0) {
+			uidlist->uid_validity = hdr->uid_validity;
+			return;
+		}
+	}
+	uidlist->uid_validity =
 		maildir_get_uidvalidity_next(uidlist->ibox->box.list);
 }
 
--- a/src/lib-storage/index/maildir/maildir-uidlist.h	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-uidlist.h	Fri Jun 26 16:11:59 2009 -0400
@@ -84,6 +84,8 @@
 uint32_t maildir_uidlist_get_next_uid(struct maildir_uidlist *uidlist);
 int maildir_uidlist_get_mailbox_guid(struct maildir_uidlist *uidlist,
 				     uint8_t mailbox_guid[MAILBOX_GUID_SIZE]);
+void maildir_uidlist_set_mailbox_guid(struct maildir_uidlist *uidlist,
+				      const uint8_t mailbox_guid[MAILBOX_GUID_SIZE]);
 
 void maildir_uidlist_set_uid_validity(struct maildir_uidlist *uidlist,
 				      uint32_t uid_validity);
--- a/src/lib-storage/index/mbox/mbox-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -487,9 +487,28 @@
 }
 
 static int
-mbox_mailbox_create(struct mail_storage *_storage, struct mailbox_list *list,
-		    const char *name, bool directory)
+mbox_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
 {
+	struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
+	int ret;
+
+	if (!box->opened) {
+		if (mailbox_open(box) < 0)
+			return -1;
+	}
+
+	mbox->sync_hdr_update = update;
+	ret = mbox_sync(mbox, MBOX_SYNC_HEADER | MBOX_SYNC_FORCE_SYNC |
+			MBOX_SYNC_REWRITE);
+	mbox->sync_hdr_update = NULL;
+	return ret;
+}
+
+static int
+mbox_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
+		    bool directory)
+{
+	struct mail_storage *storage = box->storage;
 	const char *path, *p;
 	struct stat st;
 	mode_t mode;
@@ -497,20 +516,20 @@
 	int fd;
 
 	/* make sure it doesn't exist already */
-	path = mailbox_list_get_path(list, name,
+	path = mailbox_list_get_path(box->list, box->name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(path, &st) == 0) {
-		mail_storage_set_error(_storage, MAIL_ERROR_EXISTS,
+		mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
 		return -1;
 	}
 
 	if (errno != ENOENT) {
 		if (errno == ENOTDIR) {
-			mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+			mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE,
 				"Mailbox doesn't allow inferior mailboxes");
-		} else if (!mail_storage_set_error_from_errno(_storage)) {
-			mail_storage_set_critical(_storage,
+		} else if (!mail_storage_set_error_from_errno(storage)) {
+			mail_storage_set_critical(storage,
 				"stat() failed for mbox file %s: %m", path);
 		}
 		return -1;
@@ -520,11 +539,11 @@
 	p = directory ? path + strlen(path) : strrchr(path, '/');
 	if (p != NULL) {
 		p = t_strdup_until(path, p);
-		mailbox_list_get_dir_permissions(list, NULL, &mode, &gid);
+		mailbox_list_get_dir_permissions(box->list, NULL, &mode, &gid);
 		if (mkdir_parents_chown(p, mode, (uid_t)-1, gid) < 0 &&
 		    errno != EEXIST) {
-			if (!mail_storage_set_error_from_errno(_storage)) {
-				mail_storage_set_critical(_storage,
+			if (!mail_storage_set_error_from_errno(storage)) {
+				mail_storage_set_critical(storage,
 					"mkdir_parents(%s) failed: %m", p);
 			}
 			return -1;
@@ -540,16 +559,16 @@
 	fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0660);
 	if (fd != -1) {
 		(void)close(fd);
-		return 0;
+		return update == NULL ? 0 : mbox_mailbox_update(box, update);
 	}
 
 	if (errno == EEXIST) {
 		/* mailbox was just created between stat() and open() call.. */
-		mail_storage_set_error(_storage, MAIL_ERROR_EXISTS,
+		mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
-	} else if (!mail_storage_set_error_from_errno(_storage)) {
-		mail_storage_set_critical(_storage,
-			"Can't create mailbox %s: %m", name);
+	} else if (!mail_storage_set_error_from_errno(storage)) {
+		mail_storage_set_critical(storage,
+			"Can't create mailbox %s: %m", box->name);
 	}
 	return -1;
 }
@@ -842,7 +861,6 @@
 		mbox_storage_get_list_settings,
 		mbox_storage_autodetect,
 		mbox_mailbox_alloc,
-		mbox_mailbox_create,
 		NULL
 	}
 };
@@ -858,6 +876,8 @@
 		index_storage_mailbox_enable,
 		mbox_mailbox_open,
 		mbox_mailbox_close,
+		mbox_mailbox_create,
+		mbox_mailbox_update,
 		mbox_storage_get_status,
 		NULL,
 		NULL,
--- a/src/lib-storage/index/mbox/mbox-storage.h	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/mbox/mbox-storage.h	Fri Jun 26 16:11:59 2009 -0400
@@ -48,6 +48,7 @@
 
 	uint32_t mbox_ext_idx;
 	struct mbox_index_header mbox_hdr;
+	const struct mailbox_update *sync_hdr_update;
 
 	unsigned int no_mbox_file:1;
 	unsigned int invalid_mbox_file:1;
--- a/src/lib-storage/index/mbox/mbox-sync.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/mbox/mbox-sync.c	Fri Jun 26 16:11:59 2009 -0400
@@ -957,7 +957,26 @@
 	return ret;
 }
 
-static bool mbox_sync_uidvalidity_changed(struct mbox_sync_context *sync_ctx)
+static void mbox_sync_hdr_update(struct mbox_sync_context *sync_ctx,
+				 struct mbox_sync_mail_context *mail_ctx)
+{
+	const struct mailbox_update *update = sync_ctx->mbox->sync_hdr_update;
+
+	if (update->uid_validity != 0) {
+		sync_ctx->base_uid_validity = update->uid_validity;
+		mail_ctx->imapbase_rewrite = TRUE;
+		mail_ctx->need_rewrite = TRUE;
+	}
+	if (update->min_next_uid != 0 &&
+	    sync_ctx->base_uid_last <= update->min_next_uid) {
+		sync_ctx->base_uid_last = update->min_next_uid-1;
+		mail_ctx->imapbase_rewrite = TRUE;
+		mail_ctx->need_rewrite = TRUE;
+	}
+}
+
+static bool mbox_sync_imapbase(struct mbox_sync_context *sync_ctx,
+			       struct mbox_sync_mail_context *mail_ctx)
 {
 	if (sync_ctx->base_uid_validity != 0 &&
 	    sync_ctx->hdr->uid_validity != 0 &&
@@ -969,6 +988,8 @@
 		sync_ctx->index_reset = TRUE;
 		return TRUE;
 	}
+	if (sync_ctx->mbox->sync_hdr_update != NULL)
+		mbox_sync_hdr_update(sync_ctx, mail_ctx);
 	return FALSE;
 }
 
@@ -1004,7 +1025,7 @@
 		uid = mail_ctx->mail.uid;
 
 		if (mail_ctx->seq == 1) {
-			if (mbox_sync_uidvalidity_changed(sync_ctx)) {
+			if (mbox_sync_imapbase(sync_ctx, mail_ctx)) {
 				sync_ctx->mbox->mbox_hdr.dirty_flag = TRUE;
 				return 0;
 			}
@@ -1332,26 +1353,20 @@
 	return 0;
 }
 
-static bool mbox_has_mailbox_guid(struct mbox_mailbox *mbox)
-{
-	unsigned int i;
-
-	for (i = 0; i < sizeof(mbox->mbox_hdr.mailbox_guid); i++) {
-		if (mbox->mbox_hdr.mailbox_guid[i] != 0)
-			return TRUE;
-	}
-	return FALSE;
-}
-
 static void
 mbox_sync_index_update_ext_header(struct mbox_sync_context *sync_ctx)
 {
+	const struct mailbox_update *update = sync_ctx->mbox->sync_hdr_update;
 	struct mbox_mailbox *mbox = sync_ctx->mbox;
 	const void *data;
 	size_t data_size;
 
-	if (!mbox_has_mailbox_guid(mbox))
+	if (update != NULL && !mailbox_guid_is_empty(update->mailbox_guid)) {
+		memcpy(mbox->mbox_hdr.mailbox_guid, update->mailbox_guid,
+		       sizeof(mbox->mbox_hdr.mailbox_guid));
+	} else if (mailbox_guid_is_empty(mbox->mbox_hdr.mailbox_guid)) {
 		mail_generate_guid_128(mbox->mbox_hdr.mailbox_guid);
+	}
 
 	mail_index_get_header_ext(mbox->ibox.view, mbox->mbox_ext_idx,
 				  &data, &data_size);
@@ -1655,7 +1670,7 @@
 	if (mbox_sync_header_refresh(mbox) < 0)
 		return -1;
 
-	if (!mbox_has_mailbox_guid(mbox)) {
+	if (mailbox_guid_is_empty(mbox->mbox_hdr.mailbox_guid)) {
 		/* need to assign mailbox GUID */
 		return 1;
 	}
--- a/src/lib-storage/index/raw/raw-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/raw/raw-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -90,15 +90,24 @@
 }
 
 static int
-raw_mailbox_create(struct mail_storage *storage,
-		   struct mailbox_list *list ATTR_UNUSED,
-		   const char *name ATTR_UNUSED, bool directory ATTR_UNUSED)
+raw_mailbox_create(struct mailbox *box,
+		   const struct mailbox_update *update ATTR_UNUSED,
+		   bool directory ATTR_UNUSED)
 {
-	mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE,
+	mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
 			       "Raw mailbox creation isn't supported");
 	return -1;
 }
 
+static int
+raw_mailbox_update(struct mailbox *box,
+		   const struct mailbox_update *update ATTR_UNUSED)
+{
+	mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
+			       "Raw mailbox update isn't supported");
+	return -1;
+}
+
 static int raw_list_delete_mailbox(struct mailbox_list *list,
 				   const char *name ATTR_UNUSED)
 {
@@ -185,7 +194,6 @@
 		raw_storage_get_list_settings,
 		NULL,
 		raw_mailbox_alloc,
-		raw_mailbox_create,
 		NULL
 	}
 };
@@ -201,6 +209,8 @@
 		index_storage_mailbox_enable,
 		raw_mailbox_open,
 		index_storage_mailbox_close,
+		raw_mailbox_create,
+		raw_mailbox_update,
 		index_storage_get_status,
 		NULL,
 		NULL,
--- a/src/lib-storage/index/shared/shared-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/index/shared/shared-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -282,35 +282,6 @@
 	return 0;
 }
 
-static int
-shared_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
-		      const char *name, bool directory)
-{
-	struct mail_namespace *ns = list->ns;
-	struct mailbox_list *new_list;
-	struct mail_storage *new_storage;
-	const char *str;
-	enum mail_error error;
-	int ret;
-
-	if (shared_storage_get_namespace(&ns, &name) < 0) {
-		str = mailbox_list_get_last_error(list, &error);
-		mail_storage_set_error(storage, error, str);
-		return -1;
-	}
-
-	new_list = ns->list;
-	if (mailbox_list_get_storage(&new_list, &name, &new_storage) < 0)
-		return -1;
-
-	ret = mail_storage_mailbox_create(new_storage, ns, name, directory);
-	if (ret < 0) {
-		str = mail_storage_get_last_error(new_storage, &error);
-		mail_storage_set_error(storage, error, str);
-	}
-	return ret;
-}
-
 struct mail_storage shared_storage = {
 	MEMBER(name) SHARED_STORAGE_NAME,
 	MEMBER(class_flags) 0, /* unknown at this point */
@@ -326,7 +297,6 @@
 		shared_storage_get_list_settings,
 		NULL,
 		NULL,
-		shared_mailbox_create,
 		NULL
 	}
 };
--- a/src/lib-storage/mail-storage-private.h	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/mail-storage-private.h	Fri Jun 26 16:11:59 2009 -0400
@@ -48,10 +48,6 @@
 					 const char *name,
 					 struct istream *input,
 					 enum mailbox_flags flags);
-
-	int (*mailbox_create)(struct mail_storage *storage,
-			      struct mailbox_list *list, const char *name,
-			      bool directory);
 	int (*purge)(struct mail_storage *storage);
 };
 
@@ -104,6 +100,10 @@
 	int (*open)(struct mailbox *box);
 	void (*close)(struct mailbox *box);
 
+	int (*create)(struct mailbox *box, const struct mailbox_update *update,
+		      bool directory);
+	int (*update)(struct mailbox *box, const struct mailbox_update *update);
+
 	void (*get_status)(struct mailbox *box, enum mailbox_status_items items,
 			   struct mailbox_status *status_r);
 
@@ -427,6 +427,6 @@
 int mail_set_aborted(struct mail *mail);
 void mail_set_expunged(struct mail *mail);
 void mailbox_set_deleted(struct mailbox *box);
-
+bool mailbox_guid_is_empty(const uint8_t guid[MAILBOX_GUID_SIZE]);
 
 #endif
--- a/src/lib-storage/mail-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/mail-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -391,21 +391,6 @@
 	storage->callback_context = context;
 }
 
-int mail_storage_mailbox_create(struct mail_storage *storage,
-				struct mail_namespace *ns, const char *name,
-				bool directory)
-{
-	mail_storage_clear_error(storage);
-
-	if (!mailbox_list_is_valid_create_name(ns->list, name)) {
-		mail_storage_set_error(storage, MAIL_ERROR_PARAMS,
-				       "Invalid mailbox name");
-		return -1;
-	}
-
-	return storage->v.mailbox_create(storage, ns->list, name, directory);
-}
-
 int mail_storage_purge(struct mail_storage *storage)
 {
 	mail_storage_clear_error(storage);
@@ -531,6 +516,27 @@
 	box->v.close(box);
 }
 
+int mailbox_create(struct mailbox *box, const struct mailbox_update *update,
+		   bool directory)
+{
+	mail_storage_clear_error(box->storage);
+
+	if (!mailbox_list_is_valid_create_name(box->list, box->name)) {
+		mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
+				       "Invalid mailbox name");
+		return -1;
+	}
+
+	return box->v.create(box, update, directory);
+}
+
+int mailbox_update(struct mailbox *box, const struct mailbox_update *update)
+{
+	mail_storage_clear_error(box->storage);
+
+	return box->v.update(box, update);
+}
+
 struct mail_storage *mailbox_get_storage(const struct mailbox *box)
 {
 	return box->storage;
@@ -1035,3 +1041,14 @@
 			       "Mailbox was deleted under us");
 	box->mailbox_deleted = TRUE;
 }
+
+bool mailbox_guid_is_empty(const uint8_t guid[MAILBOX_GUID_SIZE])
+{
+	unsigned int i;
+
+	for (i = 0; i < MAILBOX_GUID_SIZE; i++) {
+		if (guid[i] != 0)
+			return FALSE;
+	}
+	return TRUE;
+}
--- a/src/lib-storage/mail-storage.h	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/mail-storage.h	Fri Jun 26 16:11:59 2009 -0400
@@ -191,6 +191,14 @@
 	unsigned int nonpermanent_modseqs:1;
 };
 
+struct mailbox_update {
+	/* All non-zero fields are changed. */
+	uint8_t mailbox_guid[MAILBOX_GUID_SIZE];
+	uint32_t uid_validity;
+	uint32_t min_next_uid;
+	uint64_t min_highest_modseq;
+};
+
 struct mailbox_sync_rec {
 	uint32_t seq1, seq2;
 	enum mailbox_sync_type type;
@@ -271,13 +279,6 @@
 				struct mail_storage_callbacks *callbacks,
 				void *context);
 
-/* name is allowed to contain multiple new hierarchy levels.
-   If directory is TRUE, the mailbox should be created so that it
-   can contain children. The mailbox itself doesn't have to be
-   created as long as it shows in LIST. */
-int mail_storage_mailbox_create(struct mail_storage *storage,
-				struct mail_namespace *ns, const char *name,
-				bool directory);
 /* Purge storage's mailboxes (freeing disk space from expunged mails),
    if supported by the storage. Otherwise just a no-op. */
 int mail_storage_purge(struct mail_storage *storage);
@@ -296,14 +297,24 @@
    Note that append and copy may open the selected mailbox again
    with possibly different readonly-state. */
 struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *name,
-			      struct istream *input,
-			      enum mailbox_flags flags);
+			      struct istream *input, enum mailbox_flags flags);
 /* Open the mailbox. If this function isn't called explicitly, it's also called
    internally by lib-storage when necessary. */
 int mailbox_open(struct mailbox *box);
 /* Close the box. */
 void mailbox_close(struct mailbox **box);
 
+/* Create a mailbox. Returns failure if it already exists. Mailbox name is
+   allowed to contain multiple new non-existing hierarchy levels. If directory
+   is TRUE, the mailbox should be created so that it can contain children. The
+   mailbox itself doesn't have to be created as long as it shows up in LIST.
+   If update is non-NULL, its contents are used to set initial mailbox
+   metadata. */
+int mailbox_create(struct mailbox *box, const struct mailbox_update *update,
+		   bool directory);
+/* Update existing mailbox's metadata. */
+int mailbox_update(struct mailbox *box, const struct mailbox_update *update);
+
 /* Enable the given feature for the mailbox. */
 int mailbox_enable(struct mailbox *box, enum mailbox_feature features);
 /* Returns all enabled features. */
--- a/src/lib-storage/test-mail-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/test-mail-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -30,17 +30,6 @@
 		set->subscription_fname = "subscriptions";
 }
 
-static int
-test_mailbox_create(struct mail_storage *storage,
-		    struct mailbox_list *list ATTR_UNUSED,
-		    const char *name ATTR_UNUSED,
-		    bool directory ATTR_UNUSED)
-{
-	mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE,
-			       "Test mailbox creation isn't supported");
-	return -1;
-}
-
 struct mail_storage test_storage = {
 	MEMBER(name) "test",
 	MEMBER(class_flags) 0,
@@ -56,7 +45,6 @@
 		test_storage_get_list_settings,
 		NULL,
 		test_mailbox_alloc,
-		test_mailbox_create,
 		NULL
 	}
 };
--- a/src/lib-storage/test-mailbox.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/lib-storage/test-mailbox.c	Fri Jun 26 16:11:59 2009 -0400
@@ -33,6 +33,25 @@
 {
 }
 
+static int
+test_mailbox_create(struct mailbox *box,
+		    const struct mailbox_update *update ATTR_UNUSED,
+		    bool directory ATTR_UNUSED)
+{
+	mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
+			       "Test mailbox creation isn't supported");
+	return -1;
+}
+
+static int
+test_mailbox_update(struct mailbox *box,
+		    const struct mailbox_update *update ATTR_UNUSED)
+{
+	mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
+			       "Test mailbox update isn't supported");
+	return -1;
+}
+
 static void test_mailbox_get_status(struct mailbox *box ATTR_UNUSED,
 				    enum mailbox_status_items items ATTR_UNUSED,
 				    struct mailbox_status *status_r)
@@ -294,6 +313,8 @@
 		test_mailbox_enable,
 		test_mailbox_open,
 		test_mailbox_close,
+		test_mailbox_create,
+		test_mailbox_update,
 		test_mailbox_get_status,
 		NULL,
 		NULL,
--- a/src/plugins/acl/acl-mailbox.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/plugins/acl/acl-mailbox.c	Fri Jun 26 16:11:59 2009 -0400
@@ -104,6 +104,41 @@
 }
 
 static int
+acl_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
+		   bool directory)
+{
+	struct acl_mailbox *abox = ACL_CONTEXT(box);
+	int ret;
+
+	/* we're looking up CREATE permission from our parent's rights */
+	ret = acl_mailbox_list_have_right(box->list, box->name, TRUE,
+					  ACL_STORAGE_RIGHT_CREATE, NULL);
+	if (ret <= 0) {
+		if (ret < 0)
+			return -1;
+		/* Note that if user didn't have LOOKUP permission to parent
+		   mailbox, this may reveal the mailbox's existence to user.
+		   Can't help it. */
+		mail_storage_set_error(box->storage, MAIL_ERROR_PERM,
+				       MAIL_ERRSTR_NO_PERMISSION);
+		return -1;
+	}
+	return abox->module_ctx.super.create(box, update, directory);
+}
+
+static int
+acl_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
+{
+	struct acl_mailbox *abox = ACL_CONTEXT(box);
+	int ret;
+
+	ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_ADMIN);
+	if (ret <= 0)
+		return -1;
+	return abox->module_ctx.super.update(box, update);
+}
+
+static int
 acl_get_write_rights(struct mailbox *box,
 		     bool *flags_r, bool *flag_seen_r, bool *flag_del_r)
 {
@@ -409,6 +444,8 @@
 		box->v.allow_new_keywords = acl_allow_new_keywords;
 		box->v.open = acl_mailbox_open;
 		box->v.close = acl_mailbox_close;
+		box->v.create = acl_mailbox_create;
+		box->v.update = acl_mailbox_update;
 		box->v.mail_alloc = acl_mail_alloc;
 		box->v.save_begin = acl_save_begin;
 		box->v.keywords_create = acl_keywords_create;
--- a/src/plugins/acl/acl-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/plugins/acl/acl-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -16,37 +16,6 @@
 struct acl_user_module acl_user_module =
 	MODULE_CONTEXT_INIT(&mail_user_module_register);
 
-static int
-acl_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
-		   const char *name, bool directory)
-{
-	union mail_storage_module_context *astorage = ACL_CONTEXT(storage);
-	int ret;
-
-	if ((list->ns->flags & NAMESPACE_FLAG_NOACL) != 0)
-		ret = 1;
-	else T_BEGIN {
-		ret = acl_mailbox_list_have_right(list, name, TRUE,
-						  ACL_STORAGE_RIGHT_CREATE,
-						  NULL);
-	} T_END;
-
-	if (ret <= 0) {
-		if (ret == 0) {
-			/* Note that if the mailbox didn't have LOOKUP
-			   permission, this not reveals to user the mailbox's
-			   existence. Can't help it. */
-			mail_storage_set_error(storage, MAIL_ERROR_PERM,
-					       MAIL_ERRSTR_NO_PERMISSION);
-		} else {
-			mail_storage_set_internal_error(storage);
-		}
-		return -1;
-	}
-
-	return astorage->super.mailbox_create(storage, list, name, directory);
-}
-
 void acl_mail_storage_created(struct mail_storage *storage)
 {
 	struct acl_user *auser = ACL_USER_CONTEXT(storage->user);
@@ -59,7 +28,6 @@
 				 union mail_storage_module_context, 1);
 		astorage->super = storage->v;
 		storage->v.mailbox_alloc = acl_mailbox_alloc;
-		storage->v.mailbox_create = acl_mailbox_create;
 
 		MODULE_CONTEXT_SET_SELF(storage, acl_storage_module, astorage);
 	}
@@ -112,4 +80,3 @@
 	if (acl_next_hook_mail_user_created != NULL)
 		acl_next_hook_mail_user_created(user);
 }
-
--- a/src/plugins/autocreate/autocreate-plugin.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/plugins/autocreate/autocreate-plugin.c	Fri Jun 26 16:11:59 2009 -0400
@@ -16,7 +16,7 @@
 autocreate_mailbox(struct mail_namespace *namespaces, const char *name)
 {
 	struct mail_namespace *ns;
-	struct mail_storage *storage;
+	struct mailbox *box;
 	const char *str;
 	enum mail_error error;
 
@@ -27,14 +27,16 @@
 		return;
 	}
 
-	storage = mail_namespace_get_default_storage(ns);
-	if (mail_storage_mailbox_create(storage, ns, name, FALSE) < 0) {
-		str = mail_storage_get_last_error(storage, &error);
+	box = mailbox_alloc(ns->list, name, NULL, 0);
+	if (mailbox_create(box, NULL, FALSE) < 0) {
+		str = mail_storage_get_last_error(mailbox_get_storage(box),
+						  &error);
 		if (error != MAIL_ERROR_EXISTS && ns->mail_set->mail_debug) {
 			i_info("autocreate: Failed to create mailbox %s: %s",
 			       name, str);
 		}
 	}
+	mailbox_close(&box);
 }
 
 static void autocreate_mailboxes(struct mail_namespace *namespaces)
--- a/src/plugins/convert/convert-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/plugins/convert/convert-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -135,9 +135,9 @@
 		"dovecot.index.log",
 		"dovecot.index.cache"
 	};
-	struct mail_storage *dest_storage;
 	string_t *src, *dest;
 	DIR *dir;
+	struct mailbox *destbox;
 	struct dirent *dp;
 	const char *src_path, *dest_path, *new_path, *cur_path;
 	unsigned int i, src_dir_len, dest_dir_len;
@@ -145,14 +145,15 @@
 
 	/* create as non-selectable mailbox so the dbox-Mails directory
 	   isn't created yet */
-	dest_storage = mail_namespace_get_default_storage(dest_ns);
-	if (mail_storage_mailbox_create(dest_storage, dest_ns,
-					dest_name, TRUE) < 0) {
+	destbox = mailbox_alloc(dest_ns->list, dest_name, NULL, 0);
+	if (mailbox_create(destbox, NULL, TRUE) < 0) {
 		i_error("Mailbox conversion: "
 			"Couldn't create mailbox %s: %s",
-			dest_name, storage_error(dest_storage));
+			dest_name, storage_error(mailbox_get_storage(destbox)));
+		mailbox_close(&destbox);
 		return -1;
 	}
+	mailbox_close(&destbox);
 
 	src_path = mailbox_list_get_path(source_ns->list, src_name,
 					 MAILBOX_LIST_PATH_TYPE_MAILBOX);
@@ -237,19 +238,21 @@
 }
 
 static int mailbox_convert_list_item(struct mail_namespace *source_ns,
-				     struct mail_namespace *dest_ns,
+				     struct mailbox *destbox,
 				     const struct mailbox_info *info,
 				     struct dotlock *dotlock,
 				     const struct convert_plugin_settings *set)
 {
+	struct mail_namespace *dest_ns;
 	struct mail_storage *dest_storage;
 	const char *name, *dest_name, *error;
-	struct mailbox *srcbox, *destbox;
+	struct mailbox *srcbox;
 	int ret = 0;
 
 	if ((info->flags & MAILBOX_NONEXISTENT) != 0)
 		return 0;
 
+	dest_ns = mailbox_get_namespace(destbox);
 	name = strcasecmp(info->name, "INBOX") == 0 ? "INBOX" : info->name;
 	dest_name = mailbox_name_convert(dest_ns, source_ns, set, name);
 	dest_storage = mail_namespace_get_default_storage(dest_ns);
@@ -259,8 +262,7 @@
 		if (*info->name == '.' && set->skip_dotdirs)
 			return 0;
 
-		if (mail_storage_mailbox_create(dest_storage, dest_ns,
-						dest_name, TRUE) < 0) {
+		if (mailbox_create(destbox, NULL, TRUE) < 0) {
 			i_error("Mailbox conversion: Couldn't create mailbox "
 				"directory %s: %s", dest_name,
 				storage_error(dest_storage));
@@ -298,8 +300,7 @@
 
 	/* Create and open the destination mailbox. */
 	if (strcmp(dest_name, "INBOX") != 0) {
-		if (mail_storage_mailbox_create(dest_storage, dest_ns,
-						dest_name, FALSE) < 0) {
+		if (mailbox_create(destbox, NULL, FALSE) < 0) {
 			i_error("Mailbox conversion: "
 				"Couldn't create mailbox %s: %s",
 				dest_name, storage_error(dest_storage));
@@ -308,13 +309,10 @@
 		}
 	}
 
-	destbox = mailbox_alloc(dest_ns->list, dest_name, NULL,
-				MAILBOX_FLAG_KEEP_RECENT);
 	if (mailbox_open(destbox) < 0) {
 		i_error("Mailbox conversion: Couldn't open dest mailbox %s: %s",
 			dest_name, storage_error(mailbox_get_storage(destbox)));
 		mailbox_close(&srcbox);
-		mailbox_close(&destbox);
 		return -1;
 	}
 
@@ -324,7 +322,6 @@
 	}
 
 	mailbox_close(&srcbox);
-	mailbox_close(&destbox);
 	return ret;
 }
 
@@ -335,6 +332,7 @@
 {
 	struct mailbox_list_iterate_context *iter;
 	struct mail_namespace *dest_ns;
+	struct mailbox *destbox;
 	const struct mailbox_info *info;
 	int ret = 0;
 
@@ -343,8 +341,11 @@
 				      "*", MAILBOX_LIST_ITER_RETURN_NO_FLAGS);
 	while ((info = mailbox_list_iter_next(iter)) != NULL) {
 		T_BEGIN {
-			ret = mailbox_convert_list_item(source_ns, dest_ns,
+			destbox = mailbox_alloc(dest_ns->list, info->name, NULL,
+						MAILBOX_FLAG_KEEP_RECENT);
+			ret = mailbox_convert_list_item(source_ns, destbox,
 							info, dotlock, set);
+			mailbox_close(&destbox);
 		} T_END;
 		if (ret < 0)
 			break;
--- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Fri Jun 26 16:11:59 2009 -0400
@@ -92,22 +92,17 @@
 
 	*error_r = mail_storage_get_last_error(mailbox_get_storage(box),
 					       &error);
-	mailbox_close(&box);
-	if (error != MAIL_ERROR_NOTFOUND)
-		return NULL;
-
-	/* try creating it. */
-	storage = mail_namespace_get_default_storage(list->ns);
-	if (mail_storage_mailbox_create(storage, list->ns, name, FALSE) < 0) {
-		*error_r = mail_storage_get_last_error(storage, &error);
+	if (error != MAIL_ERROR_NOTFOUND) {
+		mailbox_close(&box);
 		return NULL;
 	}
 
-	/* and try opening again */
-	box = mailbox_alloc(list, name, NULL, MAILBOX_FLAG_KEEP_RECENT);
-	if (mailbox_open(box) < 0) {
+	/* try creating and re-opening it. */
+	storage = mail_namespace_get_default_storage(list->ns);
+	if (mailbox_create(box, NULL, FALSE) < 0 ||
+	    mailbox_open(box) < 0) {
 		*error_r = mail_storage_get_last_error(mailbox_get_storage(box),
-						       &error);
+						       NULL);
 		mailbox_close(&box);
 		return NULL;
 	}
--- a/src/plugins/listescape/listescape-plugin.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/plugins/listescape/listescape-plugin.c	Fri Jun 26 16:11:59 2009 -0400
@@ -178,20 +178,6 @@
 }
 
 static int
-listescape_mailbox_create(struct mail_storage *storage,
-			  struct mailbox_list *list,
-			  const char *name, bool directory)
-{
-	struct listescape_mail_storage *mstorage =
-		LIST_ESCAPE_CONTEXT(storage);
-
-	if (list->hierarchy_sep != list->ns->sep)
-		name = list_escape(list->ns, name, TRUE);
-	return mstorage->module_ctx.super.
-		mailbox_create(storage, list, name, directory);
-}
-
-static int
 listescape_delete_mailbox(struct mailbox_list *list, const char *name)
 {
 	struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
@@ -268,7 +254,6 @@
 	mstorage = p_new(storage->pool, struct listescape_mail_storage, 1);
 	mstorage->module_ctx.super = storage->v;
 	storage->v.mailbox_alloc = listescape_mailbox_alloc;
-	storage->v.mailbox_create = listescape_mailbox_create;
 
 	MODULE_CONTEXT_SET(storage, listescape_storage_module, mstorage);
 }
--- a/src/plugins/virtual/virtual-storage.c	Thu Jun 25 14:33:37 2009 -0400
+++ b/src/plugins/virtual/virtual-storage.c	Fri Jun 26 16:11:59 2009 -0400
@@ -271,17 +271,26 @@
 	index_storage_mailbox_close(box);
 }
 
-static int virtual_mailbox_create(struct mail_storage *_storage,
-				  struct mailbox_list *list ATTR_UNUSED,
-				  const char *name ATTR_UNUSED,
-				  bool directory ATTR_UNUSED)
+static int
+virtual_mailbox_create(struct mailbox *box,
+		       const struct mailbox_update *update ATTR_UNUSED,
+		       bool directory ATTR_UNUSED)
 {
-	mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+	mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
 			       "Can't create virtual mailboxes");
 	return -1;
 }
 
 static int
+virtual_mailbox_update(struct mailbox *box,
+		       const struct mailbox_update *update ATTR_UNUSED)
+{
+	mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
+			       "Can't update virtual mailboxes");
+	return -1;
+}
+
+static int
 virtual_delete_nonrecursive(struct mailbox_list *list, const char *path,
 			    const char *name)
 {
@@ -558,7 +567,6 @@
 		virtual_storage_get_list_settings,
 		NULL,
 		virtual_mailbox_alloc,
-		virtual_mailbox_create,
 		NULL
 	}
 };
@@ -574,6 +582,8 @@
 		index_storage_mailbox_enable,
 		virtual_mailbox_open,
 		virtual_mailbox_close,
+		virtual_mailbox_create,
+		virtual_mailbox_update,
 		index_storage_get_status,
 		NULL,
 		NULL,