mail-storage.c revision a04d8941a885f1d1972a76bd85e60ec946bc02c0
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenextern struct mail_search_register *mail_search_register_imap;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenextern struct mail_search_register *mail_search_register_human;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
af1f4b17a92ca7b2661737e65c7849df289d3070Timo Sirainenstruct mail_module_register mail_module_register = { 0 };
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
d22301419109ed4a38351715e6760011421dadecTimo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen mail_search_register_deinit(&mail_search_register_human);
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen mail_search_register_deinit(&mail_search_register_imap);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen /* append it after the list, so the autodetection order is correct */
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen unsigned int i, count;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen classes = array_get(&mail_storage_classes, &count);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen for (i = 0; i < count; i++) {
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
597dce34068d603fb759b4dff404b34049213e51Timo Sirainen unsigned int i, count;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen classes = array_get(&mail_storage_classes, &count);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen for (i = 0; i < count; i++) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen unsigned int i, count;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen classes = array_get(&mail_storage_classes, &count);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen for (i = 0; i < count; i++) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const char *p;
4b41116563110d00330896a568eff1078c382827Timo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen while (i_isalnum(*p)) p++;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen /* no autodetection if the storage driver is given. */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen enum mail_storage_flags flags, const char **error_r)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* no mail_location, autodetect */
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen /* explicit autodetection with "auto" driver. */
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen /* handle the same as with driver=NULL */
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen storage_class = mail_user_get_storage_class(ns->user, driver);
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if (list_set->root_dir == NULL || *list_set->root_dir == '\0') {
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen /* no root directory given. is this allowed? */
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen (flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0) {
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen /* autodetection should take care of this */
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen (storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen /* root not required for this storage */
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen (list->props & MAILBOX_LIST_PROP_NO_ROOT) != 0) {
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen /* root not required for this layout */
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen storage_class->v.get_list_settings(ns, list_set);
4b41116563110d00330896a568eff1078c382827Timo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
ee3e01f75b1db691bf20dd4e2558965421b8f937Timo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen "Mail storage autodetection failed with home=%s", home);
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen } else if (strncmp(ns->set->location, "auto:", 5) == 0) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen "Autodetection failed for %s (home=%s)",
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen "Ambiguous mail location setting, "
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen "don't know what to do with it: %s "
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen "(try prefixing it with mbox: or maildir:)",
e48c10b9db945fd72e2315e3ec343174fa55c7c7Timo Sirainenmail_storage_verify_root(const char *root_dir, bool autocreate,
e48c10b9db945fd72e2315e3ec343174fa55c7c7Timo Sirainen const char **error_r)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen } else if (errno != ENOENT && errno != ENOTDIR) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen } else if (!autocreate) {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen "Root mail directory doesn't exist: %s", root_dir);
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen /* doesn't exist */
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainenmail_storage_create_root(struct mailbox_list *list,
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen enum mail_storage_flags flags, const char **error_r)
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_MAILBOX,
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen /* storage doesn't use directories (e.g. shared root) */
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOVERIFY) != 0) {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen /* we don't need to verify, but since debugging is
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen enabled, check and log if the root doesn't exist */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (mail_storage_verify_root(root_dir, FALSE, &error) < 0) {
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen i_debug("Namespace %s: Creating storage despite: %s",
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen autocreate = (flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) == 0;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen ret = mail_storage_verify_root(root_dir, autocreate, error_r);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen ret = mailbox_list_try_mkdir_root(list, root_dir,
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainenmail_storage_match_class(struct mail_storage *storage,
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen if (strcmp(storage->name, storage_class->name) != 0)
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen if ((storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0 &&
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen strcmp(storage->unique_root_dir, set->root_dir) != 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* allow multiple independent shared namespaces */
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen struct mail_storage *storage = user->storages;
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen for (; storage != NULL; storage = storage->next) {
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen if (mail_storage_match_class(storage, storage_class, set))
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen enum mail_storage_flags flags, const char **error_r)
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen struct mail_storage *storage_class, *storage = NULL;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen const char *p;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen header MD5 sums stored even if we're not running POP3
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen right now. */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* autodetect */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* internal shared namespace */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen mail_storage_set_autodetection(&data, &driver);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (mailbox_list_settings_parse(ns->user, data, &list_set,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, flags,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* first storage for namespace */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (mail_storage_is_mailbox_file(storage_class))
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_NO_MAIL_FILES;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen *error_r = t_strdup_printf("Mailbox list driver %s: %s",
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) == 0) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* using an existing storage */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen storage->v.create(storage, ns, error_r) < 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen /* set *_storage=NULL only after calling destroy() callback.
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen for example mdbox wants to access ns->storage */
const char *str;
const char *fmt, ...)
const char *str;
const char *str;
const struct mail_storage_settings *
void *context)
return error;
const char *error_string;
return FALSE;
return FALSE;
return TRUE;
const struct mailbox_settings *
return NULL;
return *box_set;
return NULL;
T_BEGIN {
} T_END;
return box;
const char *vname;
&metadata) < 0) {
return box;
return box;
return TRUE;
const char *errstr;
MAILBOX_SET_AUTO_SUBSCRIBE) == 0) {
int ret;
return ret;
const char **error_r)
if (prev_sep) {
return FALSE;
if (prev_sep && i > 0) {
return FALSE;
return TRUE;
vname++;
const char *path;
&path) < 0)
return TRUE;
return FALSE;
const char *name)
NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
return TRUE;
return FALSE;
case MAIL_ERROR_NOTFOUND:
int ret;
case MAIL_ERROR_NOTFOUND:
MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) == 0) {
T_BEGIN {
} T_END;
} T_END;
if (ret < 0) {
return FALSE;
return FALSE;
return FALSE;
return FALSE;
return TRUE;
const char *index_dir;
int ret;
&index_dir);
if (ret <= 0)
int ret;
return ret;
const char *name1;
return FALSE;
return TRUE;
bool directory)
int ret;
return ret;
int ret;
if (ret < 0)
if (del)
int ret;
return ret;
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;
struct mail_namespace *
return FALSE;
i_unreached();
const char **str_r)
const unsigned char *data;
int ret;
return ret;
int ret;
return ret;
struct mailbox_attribute_iter *
const char *prefix)
struct mailbox_sync_context *
T_BEGIN {
} T_END;
return ctx;
const char *errormsg;
int ret;
if (ret == 0)
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)
unsigned int order)
int ret;
if (ret < 0) {
int ret;
if (pvt_flags != 0)
t->save_count++;
return ret;
struct mailbox_transaction_context *
int ret;
if (ret == 0) {
if (pvt_flags != 0)
t->save_count++;
return ret;
const char **path_r)
int ret;
if (ret < 0) {
return ret;
int *fd_r)
int fd;
const char *root_dir;
int ret;
return ret;
&mail_dir) < 0)
unsigned int secs)
#ifndef MMAP_CONFLICTS_WRITE
return index_flags;