mail-storage.c revision f8e4a8eac59e2847b63b57d290fa8223f4a4ce67
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenextern struct mail_search_register *mail_search_register_imap;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenextern struct mail_search_register *mail_search_register_human;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainenstruct mail_module_register mail_module_register = { 0 };
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen mail_search_register_deinit(&mail_search_register_human);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen mail_search_register_deinit(&mail_search_register_imap);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* append it after the list, so the autodetection order is correct */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int i, count;
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen classes = array_get(&mail_storage_classes, &count);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen for (i = 0; i < count; i++) {
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen unsigned int i, count;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen classes = array_get(&mail_storage_classes, &count);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen for (i = 0; i < count; i++) {
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen unsigned int i, count;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen classes = array_get(&mail_storage_classes, &count);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen for (i = 0; i < count; i++) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen const char *p;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen while (i_isalnum(*p)) p++;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* no autodetection if the storage driver is given. */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen enum mail_storage_flags flags, const char **error_r)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* no mail_location, autodetect */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* explicit autodetection with "auto" driver. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* handle the same as with driver=NULL */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen storage_class = mail_storage_find_class(driver);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (list_set->root_dir == NULL || *list_set->root_dir == '\0') {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* no root directory given. is this allowed? */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* autodetection should take care of this */
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen (storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen /* root not required for this storage */
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen (list->props & MAILBOX_LIST_PROP_NO_ROOT) != 0) {
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen /* root not required for this layout */
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen storage_class->v.get_list_settings(ns, list_set);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen "Mail storage autodetection failed with home=%s", home);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "Ambiguous mail location setting, "
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen "don't know what to do with it: %s "
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen "(try prefixing it with mbox: or maildir:)",
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainenmail_storage_verify_root(const char *root_dir, bool autocreate,
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen const char **error_r)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen } else if (errno != ENOENT && errno != ENOTDIR) {
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen } else if (!autocreate) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen "Root mail directory doesn't exist: %s", root_dir);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen /* doesn't exist */
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainenmail_storage_create_root(struct mailbox_list *list,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen enum mail_storage_flags flags, const char **error_r)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* storage doesn't use directories (e.g. shared root) */
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOVERIFY) != 0) {
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen /* we don't need to verify, but since debugging is
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen enabled, check and log if the root doesn't exist */
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen if (mail_storage_verify_root(root_dir, FALSE, &error) < 0) {
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen i_debug("Namespace %s: Creating storage despite: %s",
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen autocreate = (flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) == 0;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret = mail_storage_verify_root(root_dir, autocreate, error_r);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* we need to create the root directory. */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen mailbox_list_get_root_permissions(list, &file_mode, &dir_mode,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (mkdir_parents_chgrp(root_dir, dir_mode, gid, origin) < 0 &&
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen *error_r = mail_error_create_eacces_msg("mkdir", root_dir);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* created */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenmail_storage_match_class(struct mail_storage *storage,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (strcmp(storage->name, storage_class->name) != 0)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if ((storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0 &&
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen strcmp(storage->unique_root_dir, set->root_dir) != 0)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* allow multiple independent shared namespaces */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct mail_storage *storage = user->storages;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (; storage != NULL; storage = storage->next) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail_storage_match_class(storage, storage_class, set))
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen enum mail_storage_flags flags, const char **error_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_storage *storage_class, *storage = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *p;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen header MD5 sums stored even if we're not running POP3
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen right now. */
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen /* autodetect */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen /* internal shared namespace */
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen mail_storage_set_autodetection(&data, &driver);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen if (mailbox_list_settings_parse(ns->user, data, &list_set,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, flags,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* first storage for namespace */
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen if (mail_storage_is_mailbox_file(storage_class))
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *error_r = t_strdup_printf("Mailbox list driver %s: %s",
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen /* using an existing storage */
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen storage->v.create(storage, ns, error_r) < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* set *_storage=NULL only after calling destroy() callback.
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen for example mdbox wants to access ns->storage */
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen i_panic("Trying to deinit storage before freeing its objects");
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen DLLIST_REMOVE(&storage->user->storages, storage);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainenvoid mail_storage_obj_ref(struct mail_storage *storage)
14175321ddb88619015866978c05a27786ca4814Timo Sirainenvoid mail_storage_obj_unref(struct mail_storage *storage)
14175321ddb88619015866978c05a27786ca4814Timo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
14175321ddb88619015866978c05a27786ca4814Timo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen i_strdup(str) : i_strdup(MAIL_ERRSTR_CRITICAL_MSG);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen const char *fmt, ...)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* critical errors may contain sensitive data, so let user
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen see only "Internal error" with a timestamp to make it
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen easier to look from log files the actual error message. */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenvoid mail_storage_copy_list_error(struct mail_storage *storage,
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen const char *str;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen str = mailbox_list_get_last_error(list, &error);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenvoid mail_storage_set_index_error(struct mailbox *box)
9511a40d933181045343110c8101b75887062aaeTimo Sirainen mail_storage_set_internal_error(box->storage);
9511a40d933181045343110c8101b75887062aaeTimo Sirainenmail_storage_get_settings(struct mail_storage *storage)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenstruct mail_user *mail_storage_get_user(struct mail_storage *storage)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenvoid mail_storage_set_callbacks(struct mail_storage *storage,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenint mail_storage_purge(struct mail_storage *storage)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenconst char *mail_storage_get_last_error(struct mail_storage *storage,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* We get here only in error situations, so we have to return some
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen error. If storage->error is NONE, it means we forgot to set it at
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen some point.. */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return storage->error_string != NULL ? storage->error_string :
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen "BUG: Unknown internal error";
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* This shouldn't happen.. */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenconst char *mailbox_get_last_error(struct mailbox *box,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return mail_storage_get_last_error(box->storage, error_r);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenenum mail_error mailbox_get_last_mail_error(struct mailbox *box)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen (void)mail_storage_get_last_error(box->storage, &error);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenbool mail_storage_is_mailbox_file(struct mail_storage *storage)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE) != 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenbool mail_storage_set_error_from_errno(struct mail_storage *storage)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* debugging is enabled - admin may be debugging a
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen (permission) problem, so return FALSE to get the caller to
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen log the full error message. */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_storage_set_error(storage, error, error_string);
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainenstruct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* make sure INBOX shows up in uppercase everywhere */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen else if (vname[5] == mail_namespace_get_sep(list->ns))
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen vname = t_strconcat("INBOX", vname + 5, NULL);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mailbox_list_get_storage(&new_list, vname, &storage) < 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* just use the first storage. FIXME: does this break? */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen box = storage->v.mailbox_alloc(storage, new_list, vname, flags);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstruct mailbox *mailbox_alloc_guid(struct mailbox_list *list,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mailbox_guid_cache_find(list, guid, &vname) < 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID,
return box;
return box;
const char *name)
NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
return TRUE;
return FALSE;
case MAIL_ERROR_NOTFOUND:
vname++;
if (*p == list_sep) {
list_sep));
int ret;
case MAIL_ERROR_NOTFOUND:
MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) == 0) {
T_BEGIN {
} T_END;
} T_END;
if (ret < 0) {
bool directory)
int ret;
if (directory ||
return ret;
int ret;
if (ret < 0)
if (del)
return FALSE;
return FALSE;
return FALSE;
return TRUE;
int ret;
return ret;
const char **error_r)
return TRUE;
return FALSE;
return FALSE;
return TRUE;
const char **error_r)
return FALSE;
return FALSE;
return FALSE;
return TRUE;
bool rename_children)
const char *subs_name;
struct mail_namespace *
return FALSE;
i_unreached();
struct mailbox_sync_context *
T_BEGIN {
} T_END;
return ctx;
const char *errormsg;
int ret;
return ret;
struct mail_search_context *
int ret;
return ret;
bool tryagain;
if (!tryagain)
return FALSE;
return TRUE;
return FALSE;
return TRUE;
int ret;
if (ret < 0)
return ret;
struct mailbox_transaction_context *
return trans;
int ret;
return ret;
int ret;
T_BEGIN {
} T_END;
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;
struct mailbox_transaction_context *
int ret;
return ret;
const char *path;
int *fd_r)
int fd;
unsigned int secs)