]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added support for creating/updating mailboxes with given metadata (guid, uid validity...
authorTimo Sirainen <tss@iki.fi>
Fri, 26 Jun 2009 20:11:59 +0000 (16:11 -0400)
committerTimo Sirainen <tss@iki.fi>
Fri, 26 Jun 2009 20:11:59 +0000 (16:11 -0400)
--HG--
branch : HEAD

29 files changed:
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

index 50335f295161783ba16a3d97addb2c72b7e26e95..b87485071228c9da707bd5619bd7f6ada6492055 100644 (file)
@@ -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 @@ bool cmd_create(struct client_command_context *cmd)
                                        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;
 }
index 5328b36fcbbad5d304c3e90c2ddca754e7bb651d..6e454e47f9a360ff0d231f55cffecf0abf8e4bd2 100644 (file)
@@ -107,13 +107,15 @@ mailbox_open_or_create_synced(struct mail_deliver_context *ctx,
 
        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 @@ mailbox_open_or_create_synced(struct mail_deliver_context *ctx,
        }
 
        /* 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);
index 872598e74a0b4e2fe1e57922a0101eecdf4963c5..422e8211171c8703be57b524a785b9d0fdbb58e7 100644 (file)
@@ -128,21 +128,46 @@ static int cydir_mailbox_open(struct mailbox *box)
 }
 
 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 @@ struct mail_storage cydir_storage = {
                cydir_storage_get_list_settings,
                NULL,
                cydir_mailbox_alloc,
-               cydir_mailbox_create,
                NULL
        }
 };
@@ -361,6 +385,8 @@ struct mailbox cydir_mailbox = {
                index_storage_mailbox_enable,
                cydir_mailbox_open,
                index_storage_mailbox_close,
+               cydir_mailbox_create,
+               cydir_mailbox_update,
                index_storage_get_status,
                NULL,
                NULL,
index 842414b47992793ac5d338eef774ca71fd298df1..acb5fa9fbf0fa5188ac2def52f2cfe08895a1a16 100644 (file)
@@ -368,7 +368,7 @@ int dbox_transaction_save_commit_pre(struct dbox_save_context *ctx)
                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;
index 090aadb67714406a0b1c7f4a4fadb7c63e611cd6..7a0ba0c153347370841e1a2710e3d41bec6d6ca0 100644 (file)
@@ -543,17 +543,20 @@ static int rebuild_restore_msg(struct dbox_storage_rebuild_context *ctx,
                        break;
 
                (void)mail_storage_get_last_error(box->storage, &error);
-               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) {
+                       (void)mailbox_create(box, NULL, FALSE);
+                       mailbox_close(&box);
+                       continue;
+               }
+
+               mailbox_close(&box);
+               if (error == MAIL_ERROR_TEMP)
+                       return -1;
+
+               if (strcmp(mailbox, "INBOX") != 0) {
                        /* see if we can save to INBOX instead. */
                        mailbox = "INBOX";
                } else {
index 11888241f421e1372a9e81df486524e50133a4f4..daef2d517ce2457beebcd083d1c911f6ef879ded 100644 (file)
@@ -191,24 +191,6 @@ uint32_t dbox_get_uidvalidity_next(struct mailbox_list *list)
        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 @@ 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 dbox_index_header hdr, new_hdr;
 
@@ -237,7 +220,14 @@ void dbox_update_header(struct dbox_mailbox *mbox,
                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 @@ void dbox_update_header(struct dbox_mailbox *mbox,
        }
 }
 
-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);
 
-       /* 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 (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);
+       }
+
+       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 @@ static int dbox_write_index_header(struct mailbox *box)
        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 @@ static int create_dbox(struct mailbox *box)
                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 @@ int dbox_mailbox_open(struct mailbox *box)
                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 @@ static void dbox_storage_get_status_guid(struct mailbox *box,
        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 @@ dbox_storage_get_status(struct mailbox *box, enum mailbox_status_items items,
 }
 
 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 @@ dbox_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
                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 @@ dbox_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
           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 @@ struct mail_storage dbox_storage = {
                dbox_storage_get_list_settings,
                NULL,
                dbox_mailbox_alloc,
-               dbox_mailbox_create,
                dbox_sync_purge
        }
 };
@@ -864,6 +874,8 @@ struct mailbox dbox_mailbox = {
                index_storage_mailbox_enable,
                dbox_mailbox_open,
                dbox_mailbox_close,
+               dbox_mailbox_create,
+               dbox_mailbox_update,
                dbox_storage_get_status,
                NULL,
                NULL,
index bfb27dd4f005999dab84645a4c567635bdfc328a..2d9bc9319f4d12aa43bdff1b5fa42b12fc2f97e2 100644 (file)
@@ -108,10 +108,10 @@ dbox_mail_alloc(struct mailbox_transaction_context *t,
 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);
index 6c0c54b9aa2cf182e2e8e81ea8ca1e1a73ad1805..b591053e7b56557cbb5d0bd70f10b633b19936c3 100644 (file)
@@ -352,7 +352,8 @@ static void dbox_sync_update_header(struct dbox_sync_rebuild_context *ctx)
 
        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 :
index 062ad63f8963fe7d85db160309b897c1ca7b694a..f815c57777f7d1ec419b503d8eed58a103f3ac87 100644 (file)
@@ -377,23 +377,10 @@ int index_storage_mailbox_open(struct mailbox *box)
        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 @@ void index_storage_mailbox_alloc(struct index_mailbox *ibox, const char *name,
 {
        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 @@ void index_storage_mailbox_alloc(struct index_mailbox *ibox, const char *name,
        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,
index c4ecb46012604b11aa927b4be2729b0d6258cd8b..90776a44094a1281ddc59c7966f88b8888bff25c 100644 (file)
@@ -475,30 +475,55 @@ maildir_create_shared(struct mail_storage *storage, struct mail_namespace *ns,
 }
 
 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 @@ maildir_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
                /* 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 @@ struct mail_storage maildir_storage = {
                maildir_storage_get_list_settings,
                maildir_storage_autodetect,
                maildir_mailbox_alloc,
-               maildir_mailbox_create,
                NULL
        }
 };
@@ -1042,6 +1067,8 @@ struct mailbox maildir_mailbox = {
                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,
index 3e1d910972b5e024e17b5a327025dd279de85acb..262f6f1c671fd410021ac0e74dcd31ddb9c9ea68 100644 (file)
@@ -1080,19 +1080,35 @@ int maildir_uidlist_get_mailbox_guid(struct maildir_uidlist *uidlist,
        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 @@ maildir_uidlist_generate_uid_validity(struct maildir_uidlist *uidlist)
 {
        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);
 }
 
index a4bf86446ab035ce8e282f106a150c68664ea854..985fb71ac7eda529b63d2b810edfb731501f46c1 100644 (file)
@@ -84,6 +84,8 @@ uint32_t maildir_uidlist_get_uid_validity(struct maildir_uidlist *uidlist);
 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);
index 58464c30059abf159c9bcac35edb978662efbd0f..824287ce2fc6bf07aba8c6bdd520a94992cc1e69 100644 (file)
@@ -487,9 +487,28 @@ static int mbox_mailbox_open(struct mailbox *box)
 }
 
 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 @@ mbox_mailbox_create(struct mail_storage *_storage, struct mailbox_list *list,
        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 @@ mbox_mailbox_create(struct mail_storage *_storage, struct mailbox_list *list,
        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 @@ mbox_mailbox_create(struct mail_storage *_storage, struct mailbox_list *list,
        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 @@ struct mail_storage mbox_storage = {
                mbox_storage_get_list_settings,
                mbox_storage_autodetect,
                mbox_mailbox_alloc,
-               mbox_mailbox_create,
                NULL
        }
 };
@@ -858,6 +876,8 @@ struct mailbox mbox_mailbox = {
                index_storage_mailbox_enable,
                mbox_mailbox_open,
                mbox_mailbox_close,
+               mbox_mailbox_create,
+               mbox_mailbox_update,
                mbox_storage_get_status,
                NULL,
                NULL,
index 51b5de421b029fcc72f9a72c65eaafa29ff9f298..8571728e5192ba55deb41fb4a78150f3a6ac0742 100644 (file)
@@ -48,6 +48,7 @@ struct mbox_mailbox {
 
        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;
index 6e268955bc6feaf25e056ef4c27bf8b284472ae2..5dd4cdef20dec0659c9736fd1804f7ab8a43900c 100644 (file)
@@ -957,7 +957,26 @@ static int mbox_sync_partial_seek_next(struct mbox_sync_context *sync_ctx,
        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 @@ static bool mbox_sync_uidvalidity_changed(struct mbox_sync_context *sync_ctx)
                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 @@ static int mbox_sync_loop(struct mbox_sync_context *sync_ctx,
                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 @@ static int mbox_sync_handle_eof_updates(struct mbox_sync_context *sync_ctx,
        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 @@ int mbox_sync_has_changed_full(struct mbox_mailbox *mbox, bool leave_dirty,
        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;
        }
index db04876a7723da49a2bfb22f928963ec099a222d..4dde12ef0b6fda0d2384147b1390de9dbc1cadd6 100644 (file)
@@ -90,15 +90,24 @@ static int raw_mailbox_open(struct mailbox *box)
 }
 
 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 @@ struct mail_storage raw_storage = {
                raw_storage_get_list_settings,
                NULL,
                raw_mailbox_alloc,
-               raw_mailbox_create,
                NULL
        }
 };
@@ -201,6 +209,8 @@ struct mailbox raw_mailbox = {
                index_storage_mailbox_enable,
                raw_mailbox_open,
                index_storage_mailbox_close,
+               raw_mailbox_create,
+               raw_mailbox_update,
                index_storage_get_status,
                NULL,
                NULL,
index e624daff9e934f6863ac62eee54ef34b5e463c4f..a7b14a3b2388368dd47cfe561f412fc75a0e0a70 100644 (file)
@@ -282,35 +282,6 @@ int shared_storage_get_namespace(struct mail_namespace **_ns,
        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 @@ struct mail_storage shared_storage = {
                shared_storage_get_list_settings,
                NULL,
                NULL,
-               shared_mailbox_create,
                NULL
        }
 };
index d3ac3ea3f3d67b1daefb0259e0f1b79485d754f3..566c7bbeb960e5f0dc0eb1adc876ad182ce29ff7 100644 (file)
@@ -48,10 +48,6 @@ struct mail_storage_vfuncs {
                                         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 @@ struct mailbox_vfuncs {
        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 @@ void mail_generate_guid_128(uint8_t guid[16]);
 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
index 5f7c36b373bfd08f484f3e26ad222addb0d32224..22f3252c52cdca822d94887acadd1517b85b2379 100644 (file)
@@ -391,21 +391,6 @@ void mail_storage_set_callbacks(struct mail_storage *storage,
        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 @@ void mailbox_close(struct mailbox **_box)
        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 @@ void mailbox_set_deleted(struct mailbox *box)
                               "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;
+}
index e020068df93e0c7610bae5f4485f3d907ad02784..6f3d6d90cc4f20936dd648677c12638fa31ba29c 100644 (file)
@@ -191,6 +191,14 @@ struct mailbox_status {
        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 @@ void mail_storage_set_callbacks(struct mail_storage *storage,
                                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 @@ bool mail_storage_is_mailbox_file(struct mail_storage *storage) ATTR_PURE;
    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. */
index 1c218e55e756a12be1d61958a6d3076eb62f7803..afd4d1bbd0cec642db5d2f01d79c294771a3d62a 100644 (file)
@@ -30,17 +30,6 @@ test_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
                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 @@ struct mail_storage test_storage = {
                test_storage_get_list_settings,
                NULL,
                test_mailbox_alloc,
-               test_mailbox_create,
                NULL
        }
 };
index 0d3614f2efb086c840945063b432d9498904fe48..4d752047635b285c6462aa5d7ac5fe6c1564f02c 100644 (file)
@@ -33,6 +33,25 @@ static void test_mailbox_close(struct mailbox *box ATTR_UNUSED)
 {
 }
 
+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 @@ struct mailbox test_mailbox = {
                test_mailbox_enable,
                test_mailbox_open,
                test_mailbox_close,
+               test_mailbox_create,
+               test_mailbox_update,
                test_mailbox_get_status,
                NULL,
                NULL,
index 7971b7a8c8fca8be0db7f1a8379cdff25c1ef8da..8550c47e8cc871b71821637ea3a388257d290dfd 100644 (file)
@@ -103,6 +103,41 @@ static void acl_mailbox_close(struct mailbox *box)
        abox->module_ctx.super.close(box);
 }
 
+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 @@ acl_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
                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;
index 741e871c6935d8db6b7d051c306774aef5e3ec78..28540d61572a062255946ae19daf30f73b0935d0 100644 (file)
@@ -16,37 +16,6 @@ struct acl_storage_module acl_storage_module =
 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 @@ void acl_mail_storage_created(struct mail_storage *storage)
                                 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 @@ void acl_mail_user_created(struct mail_user *user)
        if (acl_next_hook_mail_user_created != NULL)
                acl_next_hook_mail_user_created(user);
 }
-
index ce924785573ff28d37e662797820dae95f98d484..3ad7019c193e3e1826c20518a3663ac3d3b8f15a 100644 (file)
@@ -16,7 +16,7 @@ static void
 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 @@ autocreate_mailbox(struct mail_namespace *namespaces, const char *name)
                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)
index 31a46c3a944c4d55ba43dc268c5db7104b99106c..0c2d3e5c671aef0b3a9015e6ca32e7ff39e430f6 100644 (file)
@@ -135,9 +135,9 @@ mailbox_convert_maildir_to_dbox(struct mail_namespace *source_ns,
                "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 @@ mailbox_convert_maildir_to_dbox(struct mail_namespace *source_ns,
 
        /* 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 @@ mailbox_convert_maildir_to_dbox(struct mail_namespace *source_ns,
 }
 
 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 @@ static int mailbox_convert_list_item(struct mail_namespace *source_ns,
                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 @@ static int mailbox_convert_list_item(struct mail_namespace *source_ns,
 
        /* 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 @@ static int mailbox_convert_list_item(struct mail_namespace *source_ns,
                }
        }
 
-       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 @@ static int mailbox_convert_list_item(struct mail_namespace *source_ns,
        }
 
        mailbox_close(&srcbox);
-       mailbox_close(&destbox);
        return ret;
 }
 
@@ -335,6 +332,7 @@ static int mailbox_list_copy(struct mail_namespace *source_ns,
 {
        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 @@ static int mailbox_list_copy(struct mail_namespace *source_ns,
                                      "*", 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;
index bb4516f3ca5da70b700bd28474fd14f3f5ff5cdb..dbd1cb8a6e077b44c36e201e723c3fa7874105fb 100644 (file)
@@ -92,22 +92,17 @@ mailbox_open_or_create(struct mailbox_list *list, const char *name,
 
        *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;
        }
index 93284e2eeb053222707beb6a066c7b299d9c2561..5623f4c9f9dd429aac5fc7f76bf67f59a4de1c11 100644 (file)
@@ -177,20 +177,6 @@ listescape_mailbox_alloc(struct mail_storage *storage,
                mailbox_alloc(storage, list, name, input, flags);
 }
 
-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)
 {
@@ -268,7 +254,6 @@ static void listescape_mail_storage_created(struct mail_storage *storage)
        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);
 }
index 12893d828e4f74c0802a0fbb2127e743a581347f..b768ef06210ac155eef3821da914c5a4b7d6e283 100644 (file)
@@ -271,16 +271,25 @@ static void virtual_mailbox_close(struct mailbox *box)
        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 @@ struct mail_storage virtual_storage = {
                virtual_storage_get_list_settings,
                NULL,
                virtual_mailbox_alloc,
-               virtual_mailbox_create,
                NULL
        }
 };
@@ -574,6 +582,8 @@ struct mailbox virtual_mailbox = {
                index_storage_mailbox_enable,
                virtual_mailbox_open,
                virtual_mailbox_close,
+               virtual_mailbox_create,
+               virtual_mailbox_update,
                index_storage_get_status,
                NULL,
                NULL,