mail-storage.c revision b28fc85b1d7261e06d8b725dabd4c0328f9eafbc
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenextern struct mail_search_register *mail_search_register_imap;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenextern struct mail_search_register *mail_search_register_human;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenstruct mail_module_register mail_module_register = { 0 };
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen mail_search_register_deinit(&mail_search_register_human);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen mail_search_register_deinit(&mail_search_register_imap);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* append it after the list, so the autodetection order is correct */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen unsigned int i, count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen classes = array_get(&mail_storage_classes, &count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (i = 0; i < count; i++) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen unsigned int i, count;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen classes = array_get(&mail_storage_classes, &count);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen for (i = 0; i < count; i++) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int i, count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen classes = array_get(&mail_storage_classes, &count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (i = 0; i < count; i++) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen const char *p;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen while (i_isalnum(*p)) p++;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen /* no autodetection if the storage driver is given. */
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen enum mail_storage_flags flags, const char **error_r)
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen /* no mail_location, autodetect */
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen /* explicit autodetection with "auto" driver. */
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen /* handle the same as with driver=NULL */
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen storage_class = mail_storage_find_class(driver);
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen if (list_set->root_dir == NULL || *list_set->root_dir == '\0') {
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen /* no root directory given. is this allowed? */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* autodetection should take care of this */
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen (storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* root not required for this storage */
596433ccbca59ce2328dc1d029586154cd937155Timo Sirainen (list->props & MAILBOX_LIST_PROP_NO_ROOT) != 0) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* root not required for this layout */
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen storage_class->v.get_list_settings(ns, list_set);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "Mail storage autodetection failed with home=%s", home);
7f3b826a89bcb7a72759912e99f574b28309fe1bTimo Sirainen } else if (strncmp(ns->set->location, "auto:", 5) == 0) {
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen "Autodetection failed for %s (home=%s)",
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen "Ambiguous mail location setting, "
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen "don't know what to do with it: %s "
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen "(try prefixing it with mbox: or maildir:)",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmail_storage_verify_root(const char *root_dir, bool autocreate,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char **error_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if (errno != ENOENT && errno != ENOTDIR) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else if (!autocreate) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "Root mail directory doesn't exist: %s", root_dir);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* doesn't exist */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenmail_storage_create_root(struct mailbox_list *list,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen enum mail_storage_flags flags, const char **error_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* storage doesn't use directories (e.g. shared root) */
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOVERIFY) != 0) {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen /* we don't need to verify, but since debugging is
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen enabled, check and log if the root doesn't exist */
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if (mail_storage_verify_root(root_dir, FALSE, &error) < 0) {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen i_debug("Namespace %s: Creating storage despite: %s",
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen autocreate = (flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) == 0;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen ret = mail_storage_verify_root(root_dir, autocreate, error_r);
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainenmail_storage_match_class(struct mail_storage *storage,
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainen if (strcmp(storage->name, storage_class->name) != 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0 &&
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen strcmp(storage->unique_root_dir, set->root_dir) != 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* allow multiple independent shared namespaces */
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen struct mail_storage *storage = user->storages;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen for (; storage != NULL; storage = storage->next) {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if (mail_storage_match_class(storage, storage_class, set))
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen enum mail_storage_flags flags, const char **error_r)
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen struct mail_storage *storage_class, *storage = NULL;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen const char *p;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen header MD5 sums stored even if we're not running POP3
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen right now. */
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen /* autodetect */
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen /* internal shared namespace */
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen mail_storage_set_autodetection(&data, &driver);
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (mailbox_list_settings_parse(ns->user, data, &list_set,
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, flags,
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen /* first storage for namespace */
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen if (mail_storage_is_mailbox_file(storage_class))
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen *error_r = t_strdup_printf("Mailbox list driver %s: %s",
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen /* using an existing storage */
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen storage->v.create(storage, ns, error_r) < 0) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen /* set *_storage=NULL only after calling destroy() callback.
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen for example mdbox wants to access ns->storage */
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_panic("Trying to deinit storage without freeing mailbox %s",
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_panic("Trying to deinit storage before freeing its objects");
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen DLLIST_REMOVE(&storage->user->storages, storage);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenvoid mail_storage_obj_ref(struct mail_storage *storage)
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainenvoid mail_storage_obj_unref(struct mail_storage *storage)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const char *str;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen str = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *fmt, ...)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen /* critical errors may contain sensitive data, so let user
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen see only "Internal error" with a timestamp to make it
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen easier to look from log files the actual error message. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mail_storage_copy_list_error(struct mail_storage *storage,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *str;
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen str = mailbox_list_get_last_error(list, &error);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenvoid mail_storage_set_index_error(struct mailbox *box)
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen mail_storage_set_internal_error(box->storage);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenmail_storage_get_settings(struct mail_storage *storage)
499fec3443374cc89fb8c83b8027c1614097d7a3Timo Sirainenstruct mail_user *mail_storage_get_user(struct mail_storage *storage)
void *context)
return error;
const char *error_string;
return FALSE;
return FALSE;
return TRUE;
const struct mailbox_settings *
return NULL;
return NULL;
return *box_set;
return NULL;
T_BEGIN {
} T_END;
return box;
const char *vname;
&metadata) < 0) {
return box;
return box;
const char *name)
NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
return TRUE;
return FALSE;
return TRUE;
case MAIL_ERROR_NOTFOUND:
vname++;
if (*p == list_sep) {
list_sep));
const char *errstr;
MAILBOX_SET_AUTO_SUBSCRIBE) == 0) {
int ret;
return ret;
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 TRUE;
bool directory)
int ret;
if (directory ||
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;
bool rename_children)
struct mail_namespace *
return FALSE;
i_unreached();
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;
return ret;
struct mailbox_transaction_context *
int ret;
return ret;
const char *path;
int *fd_r)
int fd;
unsigned int secs)