mail-storage.c revision 6acaa359928215b48e97373fb96a3dc326bbd65b
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstruct mail_module_register mail_module_register = { 0 };
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid (*hook_mail_storage_created)(struct mail_storage *storage);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid (*hook_mailbox_allocated)(struct mailbox *box) = NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid (*hook_mailbox_index_opened)(struct mailbox *box) = NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
15a07b47846c47a81d69a14d649564e222d6f742Timo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* append it after the list, so the autodetection order is correct */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen unsigned int i, count;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen classes = array_get(&mail_storage_classes, &count);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen for (i = 0; i < count; i++) {
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen unsigned int i, count;
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen classes = array_get(&mail_storage_classes, &count);
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen for (i = 0; i < count; i++) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int i, count;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen classes = array_get(&mail_storage_classes, &count);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen for (i = 0; i < count; i++) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen const char *p;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen while (i_isalnum(*p)) p++;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* no autodetection if the storage driver is given. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char **error_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen storage_class = mail_storage_find_class(driver);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen storage_class->v.get_list_settings(ns, list_set);
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "Mail storage autodetection failed with home=%s", home);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "Ambiguous mail location setting, "
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "don't know what to do with it: %s "
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "(try prefixing it with mbox: or maildir:)",
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmail_storage_create_root(struct mailbox_list *list,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen enum mail_storage_flags flags, const char **error_r)
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* storage doesn't use directories (e.g. shared root) */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen } else if (errno != ENOENT && errno != ENOTDIR) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen } else if (list->ns->type == NAMESPACE_SHARED) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* can't create a new user, but we don't want to fail
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen the storage creation. */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen } else if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen "Root mail directory doesn't exist: %s", root_dir);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* we need to create the root directory. */
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi mailbox_list_get_dir_permissions(list, NULL, &mode, &gid, &origin);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (mkdir_parents_chgrp(root_dir, mode, gid, origin) < 0 &&
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen *error_r = mail_error_create_eacces_msg("mkdir", root_dir);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* created */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct mail_storage *storage = user->storages;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen for (; storage != NULL; storage = storage->next) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (strcmp(storage->name, storage_class->name) == 0 &&
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen strcmp(storage->unique_root_dir, set->root_dir) == 0))
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen enum mail_storage_flags flags, const char **error_r)
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi struct mail_storage *storage_class, *storage = NULL;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen const char *p;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen header MD5 sums stored even if we're not running POP3
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen right now. */
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen /* autodetect */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen /* internal shared namespace */
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen mail_storage_set_autodetection(&data, &driver);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if (mailbox_list_settings_parse(data, &list_set, ns,
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0 &&
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, error_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* first storage for namespace */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (mail_storage_is_mailbox_file(storage_class))
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* using an existing storage */
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen storage->v.create(storage, ns, error_r) < 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (hook_mail_storage_created != NULL) T_BEGIN {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid mail_storage_ref(struct mail_storage *storage)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen DLLIST_REMOVE(&storage->user->storages, storage);
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_strdup(str) : i_strdup(MAIL_ERRSTR_CRITICAL_MSG);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char *fmt, ...)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* critical errors may contain sensitive data, so let user
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen see only "Internal error" with a timestamp to make it
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen easier to look from log files the actual error message. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmail_storage_get_settings(struct mail_storage *storage)
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainenvoid mail_storage_set_callbacks(struct mail_storage *storage,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint mail_storage_purge(struct mail_storage *storage)
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainenconst char *mail_storage_get_last_error(struct mail_storage *storage,
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen /* We get here only in error situations, so we have to return some
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen error. If storage->error is NONE, it means we forgot to set it at
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen some point.. */
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen return storage->error_string != NULL ? storage->error_string :
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen "BUG: Unknown internal error";
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen /* This shouldn't happen.. */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenbool mail_storage_is_mailbox_file(struct mail_storage *storage)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE) != 0;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenbool mail_storage_set_error_from_errno(struct mail_storage *storage)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen /* debugging is enabled - admin may be debugging a
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen (permission) problem, so return FALSE to get the caller to
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen log the full error message. */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen mail_storage_set_error(storage, error, error_string);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstruct mailbox *mailbox_alloc(struct mailbox_list *list, const char *name,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (mailbox_list_get_storage(&new_list, &name, &storage) < 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* just use the first storage. FIXME: does this break? */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen box = storage->v.mailbox_alloc(storage, new_list,
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen if (!mailbox_list_is_valid_existing_name(box->list, box->name)) {
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen "Invalid mailbox name");
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainenint mailbox_enable(struct mailbox *box, enum mailbox_feature features)
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainenenum mailbox_feature mailbox_get_enabled_features(struct mailbox *box)
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen i_panic("Trying to close mailbox %s with open transactions",
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainenint mailbox_create(struct mailbox *box, const struct mailbox_update *update,
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen if (!mailbox_list_is_valid_create_name(box->list, box->name)) {
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen "Invalid mailbox name");
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainenint mailbox_update(struct mailbox *box, const struct mailbox_update *update)
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainenstruct mail_storage *mailbox_get_storage(const struct mailbox *box)
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainenmailbox_get_namespace(const struct mailbox *box)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenconst struct mail_storage_settings *mailbox_get_settings(struct mailbox *box)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenconst char *mailbox_get_name(const struct mailbox *box)
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainenconst char *mailbox_get_vname(const struct mailbox *box)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenbool mailbox_allow_new_keywords(struct mailbox *box)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenbool mailbox_backends_equal(const struct mailbox *box1,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct mail_namespace *ns1 = box1->list->ns, *ns2 = box2->list->ns;
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainenmailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen i_panic("Trying to sync mailbox %s with open transactions",
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainenbool mailbox_sync_next(struct mailbox_sync_context *ctx,
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen return ctx->box->v.sync_next(ctx, sync_rec_r);
411f318ed3a25fa66c1b932e10df43841e2725c9Timo Sirainenint mailbox_sync_deinit(struct mailbox_sync_context **_ctx,
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen return ctx->box->v.sync_deinit(ctx, status_items, status_r);
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainenint mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags,
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen /* we don't care about mailbox's current state, so we might
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen as well fix inconsistency state */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return mailbox_sync_deinit(&ctx, status_items, status_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid mailbox_notify_changes(struct mailbox *box, unsigned int min_interval,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mailbox_notify_callback_t *callback, void *context)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid mailbox_notify_changes_stop(struct mailbox *box)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint mailbox_keywords_create(struct mailbox *box, const char *const keywords[],
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return box->v.keywords_create(box, keywords, keywords_r, FALSE);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmailbox_keywords_create_valid(struct mailbox *box,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char *const keywords[])
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (box->v.keywords_create(box, keywords, &kw, TRUE) < 0)
2c719bcb92302f45df4badb71d1d97f57235d0ccTimo Sirainenmailbox_keywords_create_from_indexes(struct mailbox *box,
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen return box->v.keywords_create_from_indexes(box, idx);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid mailbox_keywords_ref(struct mailbox *box, struct mail_keywords *keywords)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid mailbox_keywords_unref(struct mailbox *box,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenbool mailbox_keyword_is_valid(struct mailbox *box, const char *keyword,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char **error_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return box->v.keyword_is_valid(box, keyword, error_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid mailbox_get_seq_range(struct mailbox *box, uint32_t uid1, uint32_t uid2,
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen box->v.get_seq_range(box, uid1, uid2, seq1_r, seq2_r);
23fdad6c7e2581921f511e24cd9371c9eaebcef9Timo Sirainenvoid mailbox_get_uid_range(struct mailbox *box,
return FALSE;
bool only_with_msgs)
struct mailbox_header_lookup_ctx *
struct mail_search_context *
int ret;
return ret;
bool tryagain;
int ret;
&tryagain)) == 0) {
if (!tryagain)
return ret;
int ret;
if (ret > 0)
return ret;
int ret;
if (ret < 0)
return ret;
struct mailbox_transaction_context *
return trans;
int ret;
return ret;
struct mailbox *
return t->box;
struct mail_save_context *
return ctx;
const char *const *keywords_list;
const char *envelope)
int ret;
if (ret < 0) {
int ret;
return ret;
int ret;
return ret;