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;
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;
}
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) {
}
/* 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);
}
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
cydir_storage_get_list_settings,
NULL,
cydir_mailbox_alloc,
- cydir_mailbox_create,
NULL
}
};
index_storage_mailbox_enable,
cydir_mailbox_open,
index_storage_mailbox_close,
+ cydir_mailbox_create,
+ cydir_mailbox_update,
index_storage_get_status,
NULL,
NULL,
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;
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 {
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;
}
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;
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) {
}
}
-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);
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;
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;
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);
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;
}
}
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;
}
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;
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
dbox_storage_get_list_settings,
NULL,
dbox_mailbox_alloc,
- dbox_mailbox_create,
dbox_sync_purge
}
};
index_storage_mailbox_enable,
dbox_mailbox_open,
dbox_mailbox_close,
+ dbox_mailbox_create,
+ dbox_mailbox_update,
dbox_storage_get_status,
NULL,
NULL,
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);
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 :
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;
{
struct mailbox *box = &ibox->box;
const char *path;
+ gid_t dir_gid;
if (name != NULL)
box->name = p_strdup(box->pool, 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,
}
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;
}
/* 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
maildir_storage_get_list_settings,
maildir_storage_autodetect,
maildir_mailbox_alloc,
- maildir_mailbox_create,
NULL
}
};
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,
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
{
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);
}
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);
}
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;
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;
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;
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;
}
mbox_storage_get_list_settings,
mbox_storage_autodetect,
mbox_mailbox_alloc,
- mbox_mailbox_create,
NULL
}
};
index_storage_mailbox_enable,
mbox_mailbox_open,
mbox_mailbox_close,
+ mbox_mailbox_create,
+ mbox_mailbox_update,
mbox_storage_get_status,
NULL,
NULL,
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;
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 &&
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;
}
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;
}
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);
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;
}
}
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)
{
raw_storage_get_list_settings,
NULL,
raw_mailbox_alloc,
- raw_mailbox_create,
NULL
}
};
index_storage_mailbox_enable,
raw_mailbox_open,
index_storage_mailbox_close,
+ raw_mailbox_create,
+ raw_mailbox_update,
index_storage_get_status,
NULL,
NULL,
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 */
shared_storage_get_list_settings,
NULL,
NULL,
- shared_mailbox_create,
NULL
}
};
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);
};
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);
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
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);
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;
"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;
+}
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;
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);
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. */
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,
test_storage_get_list_settings,
NULL,
test_mailbox_alloc,
- test_mailbox_create,
NULL
}
};
{
}
+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)
test_mailbox_enable,
test_mailbox_open,
test_mailbox_close,
+ test_mailbox_create,
+ test_mailbox_update,
test_mailbox_get_status,
NULL,
NULL,
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)
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;
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);
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);
}
if (acl_next_hook_mail_user_created != NULL)
acl_next_hook_mail_user_created(user);
}
-
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;
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)
"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;
/* 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);
}
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);
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));
/* 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));
}
}
- 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;
}
}
mailbox_close(&srcbox);
- mailbox_close(&destbox);
return ret;
}
{
struct mailbox_list_iterate_context *iter;
struct mail_namespace *dest_ns;
+ struct mailbox *destbox;
const struct mailbox_info *info;
int ret = 0;
"*", 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;
*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;
}
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)
{
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_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)
virtual_storage_get_list_settings,
NULL,
virtual_mailbox_alloc,
- virtual_mailbox_create,
NULL
}
};
index_storage_mailbox_enable,
virtual_mailbox_open,
virtual_mailbox_close,
+ virtual_mailbox_create,
+ virtual_mailbox_update,
index_storage_get_status,
NULL,
NULL,