mail-storage.c revision 13e130c3af3032982de6b1d13c6dcddda9164848
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct mail_search_register *mail_search_register_imap;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct mail_search_register *mail_search_register_human;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct mail_module_register mail_module_register = { 0 };
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_search_register_deinit(&mail_search_register_human);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_search_register_deinit(&mail_search_register_imap);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* append it after the list, so the autodetection order is correct */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen unsigned int i, count;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen classes = array_get(&mail_storage_classes, &count);
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen for (i = 0; i < count; i++) {
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i, count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen classes = array_get(&mail_storage_classes, &count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < count; i++) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i, count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen classes = array_get(&mail_storage_classes, &count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < count; i++) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen const char *p;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen while (i_isalnum(*p)) p++;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* no autodetection if the storage driver is given. */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen enum mail_storage_flags flags, const char **error_r)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* no mail_location, autodetect */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* explicit autodetection with "auto" driver. */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* handle the same as with driver=NULL */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen storage_class = mail_user_get_storage_class(ns->user, driver);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (list_set->root_dir == NULL || *list_set->root_dir == '\0') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* no root directory given. is this allowed? */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen (flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* autodetection should take care of this */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen (storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* root not required for this storage */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen (list->props & MAILBOX_LIST_PROP_NO_ROOT) != 0) {
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen /* root not required for this layout */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen storage_class->v.get_list_settings(ns, list_set);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Mail storage autodetection failed with home=%s", home);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else if (strncmp(ns->set->location, "auto:", 5) == 0) {
cd2ed64888b42b481cde6bb9548c8520516fa3e9Timo Sirainen "Autodetection failed for %s (home=%s)",
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen "Ambiguous mail location setting, "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "don't know what to do with it: %s "
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen "(try prefixing it with mbox: or maildir:)",
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainenmail_storage_verify_root(const char *root_dir, bool autocreate,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char **error_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (errno != ENOENT && errno != ENOTDIR) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen } else if (!autocreate) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen "Root mail directory doesn't exist: %s", root_dir);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* doesn't exist */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmail_storage_create_root(struct mailbox_list *list,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mail_storage_flags flags, const char **error_r)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_MAILBOX,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* storage doesn't use directories (e.g. shared root) */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOVERIFY) != 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* we don't need to verify, but since debugging is
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen enabled, check and log if the root doesn't exist */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (mail_storage_verify_root(root_dir, FALSE, &error) < 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen i_debug("Namespace %s: Creating storage despite: %s",
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen autocreate = (flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) == 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen ret = mail_storage_verify_root(root_dir, autocreate, error_r);
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen ret = mailbox_list_try_mkdir_root(list, root_dir,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmail_storage_match_class(struct mail_storage *storage,
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen if (strcmp(storage->name, storage_class->name) != 0)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if ((storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0 &&
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen strcmp(storage->unique_root_dir, set->root_dir) != 0)
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen /* allow multiple independent shared namespaces */
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen struct mail_storage *storage = user->storages;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen for (; storage != NULL; storage = storage->next) {
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen if (mail_storage_match_class(storage, storage_class, set))
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen enum mail_storage_flags flags, const char **error_r)
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen struct mail_storage *storage_class, *storage = NULL;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen const char *p;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen header MD5 sums stored even if we're not running POP3
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen right now. */
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen /* autodetect */
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen /* internal shared namespace */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_autodetection(&data, &driver);
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen if (mailbox_list_settings_parse(ns->user, data, &list_set,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, flags,
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* first storage for namespace */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (mail_storage_is_mailbox_file(storage_class))
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0)
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_NO_MAIL_FILES;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = t_strdup_printf("Mailbox list driver %s: %s",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* using an existing storage */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen storage->v.create(storage, ns, error_r) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen /* set *_storage=NULL only after calling destroy() callback.
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen for example mdbox wants to access ns->storage */
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen i_panic("Trying to deinit storage without freeing mailbox %s",
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen i_panic("Trying to deinit storage before freeing its objects");
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen DLLIST_REMOVE(&storage->user->storages, storage);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainenvoid mail_storage_obj_ref(struct mail_storage *storage)
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainenvoid mail_storage_obj_unref(struct mail_storage *storage)
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen const char *str;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen str = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen const char *fmt, ...)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* critical errors may contain sensitive data, so let user
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen see only "Internal error" with a timestamp to make it
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen easier to look from log files the actual error message. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid mail_storage_copy_error(struct mail_storage *dest,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *str;
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen str = mail_storage_get_last_error(src, &error);
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainenvoid mail_storage_copy_list_error(struct mail_storage *storage,
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen const char *str;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen str = mailbox_list_get_last_error(list, &error);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid mailbox_set_index_error(struct mailbox *box)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_set_internal_error(box->storage);
5a6343181a5183b1ae1c39d40fc5a1deb3b840d9Timo Sirainenmail_storage_get_settings(struct mail_storage *storage)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct mail_user *mail_storage_get_user(struct mail_storage *storage)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid mail_storage_set_callbacks(struct mail_storage *storage,
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainenint mail_storage_purge(struct mail_storage *storage)
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainenconst char *mail_storage_get_last_error(struct mail_storage *storage,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* We get here only in error situations, so we have to return some
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen error. If storage->error is NONE, it means we forgot to set it at
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen some point.. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return storage->error_string != NULL ? storage->error_string :
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen "BUG: Unknown internal error";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* This shouldn't happen.. */
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainenconst char *mailbox_get_last_error(struct mailbox *box,
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen return mail_storage_get_last_error(box->storage, error_r);
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainenenum mail_error mailbox_get_last_mail_error(struct mailbox *box)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_get_last_error(box->storage, &error);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool mail_storage_is_mailbox_file(struct mail_storage *storage)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE) != 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool mail_storage_set_error_from_errno(struct mail_storage *storage)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* debugging is enabled - admin may be debugging a
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (permission) problem, so return FALSE to get the caller to
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen log the full error message. */
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen mail_storage_set_error(storage, error, error_string);
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainenmailbox_settings_find(struct mail_user *user, const char *vname)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen ns = mail_namespace_find(user->namespaces, vname);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen strncmp(ns->prefix, vname, ns->prefix_len-1) == 0) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (vname[ns->prefix_len-1] == mail_namespace_get_sep(ns))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* namespace prefix itself */
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainenstruct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* make sure INBOX shows up in uppercase everywhere */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else if (vname[5] == mail_namespace_get_sep(list->ns))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen vname = t_strconcat("INBOX", vname + 5, NULL);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (mailbox_list_get_storage(&new_list, vname, &storage) < 0) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen /* just use the first storage. FIXME: does this break? */
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen box = storage->v.mailbox_alloc(storage, new_list, vname, flags);
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen box->set = mailbox_settings_find(storage->user, vname);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen DLLIST_PREPEND(&box->storage->mailboxes, box);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainenstruct mailbox *mailbox_alloc_guid(struct mailbox_list *list,
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (mailbox_guid_cache_find(list, guid, &vname) < 0) {
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID,
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen /* GUID mismatch, refresh cache and try again */
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* successfully opened the correct mailbox */
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen "Couldn't verify mailbox GUID: %s",
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen vname = t_strdup_printf("(nonexistent mailbox with GUID=%s)",
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen vname = t_strdup_printf("(error in mailbox with GUID=%s)",
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainenstatic bool mailbox_is_autocreated(struct mailbox *box)
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen strcmp(box->set->autocreate, MAILBOX_SET_AUTO_NO) != 0;
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainenstatic int mailbox_autocreate(struct mailbox *box)
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen "Failed to autocreate mailbox %s: %s",
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen "Failed to autosubscribe to mailbox %s: %s",
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen box->vname, mailbox_get_last_error(box, NULL));
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainenstatic int mailbox_autocreate_and_reopen(struct mailbox *box)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen !box->storage->user->inbox_open_error_logged) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen box->storage->user->inbox_open_error_logged = TRUE;
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen "Opening INBOX failed: %s",
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainenmailbox_name_verify_separators(const char *vname, char sep,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char **error_r)
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen unsigned int i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* Make sure the vname is correct: non-empty, doesn't begin or end
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen with separator and no adjacent separators */
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen *error_r = "Has adjacent hierarchy separators";
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen if (prev_sep && i > 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int mailbox_verify_name(struct mailbox *box)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* this is INBOX - don't bother with further checks */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen list_sep = mailbox_list_get_hierarchy_sep(box->list);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* vname is either "namespace/box" or "namespace" */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_assert(strncmp(vname, ns->prefix, ns->prefix_len-1) == 0);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_assert(vname[0] == ns->prefix[ns->prefix_len-1]);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* "namespace/" isn't a valid mailbox name. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "Invalid mailbox name");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (ns_sep != list_sep && box->list->set.escape_char == '\0' &&
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, t_strdup_printf(
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "Character not allowed in mailbox name: '%c'", list_sep));
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen !box->storage->set->mail_full_filesystem_access) {
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen "Invalid mailbox name: Begins with hierarchy separator");
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen if (!mailbox_name_verify_separators(vname, ns_sep, &error) ||
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen !mailbox_list_is_valid_name(box->list, box->name, &error)) {
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen t_strdup_printf("Invalid mailbox name: %s", error));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int mailbox_verify_existing_name(struct mailbox *box)
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen /* Make sure box->_path is set, so mailbox_get_path() works from
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen now on. Note that this may also fail with some backends if the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox doesn't exist. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX, &path) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (box->storage->error != MAIL_ERROR_NOTFOUND ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* if this is an autocreated mailbox, create it now */
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenstatic bool mailbox_name_has_control_chars(const char *name)
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen const char *p;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((unsigned char)*p < ' ')
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint mailbox_verify_create_name(struct mailbox *box)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen char sep = mail_namespace_get_sep(box->list->ns);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* mailbox_alloc() already checks that vname is valid UTF8,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen so we don't need to verify that.
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen check vname instead of storage name, because vname is what is
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen visible to users, while storage name may be a fixed length GUID. */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (mailbox_name_has_control_chars(box->vname)) {
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen "Control characters not allowed in new mailbox names");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mailbox_list_name_is_too_large(box->vname, sep)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Mailbox name too long");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool have_listable_namespace_prefix(struct mail_namespace *ns,
56ba5a9b62e3ce527e898a8fe3b1a015ab30ed54Timo Sirainen if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen /* if prefix has multiple hierarchies, match
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen any of the hierarchies */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (strncmp(ns->prefix, name, name_len) == 0 &&
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen ns->prefix[name_len] == mail_namespace_get_sep(ns))
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainenint mailbox_exists(struct mailbox *box, bool auto_boxes,
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch /* unsure if this exists or not */
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen /* the mailbox name is invalid. we don't know if it currently
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen exists or not, but since it can never be accessed in any way
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen report it as if it didn't exist. */
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (auto_boxes && box->set != NULL && mailbox_is_autocreated(box)) {
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (box->v.exists(box, auto_boxes, existence_r) < 0)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (!box->inbox_user && *existence_r == MAILBOX_EXISTENCE_NOSELECT &&
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen have_listable_namespace_prefix(box->storage->user->namespaces,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen /* listable namespace prefix always exists. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* if this is a shared namespace with only INBOX and
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_shared_explicit_inbox=no, we'll need to mark the namespace as
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen usable here since nothing else will. */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainenmailbox_open_full(struct mailbox *box, struct istream *input)
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen mail_storage_set_internal_error(box->storage);
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen "Storage doesn't support streamed mailboxes");
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (ret < 0 && box->storage->error == MAIL_ERROR_NOTFOUND &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen box->input == NULL && mailbox_is_autocreated(box)) T_BEGIN {
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainenstatic bool mailbox_try_undelete(struct mailbox *box)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (mail_index_get_modification_time(box->index, &mtime) < 0)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (mtime + MAILBOX_DELETE_RETRY_SECS > time(NULL))
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (mailbox_mark_index_deleted(box, FALSE) < 0)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* mailbox has been marked as deleted. if this deletion
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen started (and crashed) a long time ago, it can be confusing
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen to user that the mailbox can't be opened. so we'll just
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen undelete it and reopen. */
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainenstatic int mailbox_alloc_index_pvt(struct mailbox *box)
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (mailbox_create_missing_dir(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE) < 0)
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen box->index_pvt = mail_index_alloc_cache_get(NULL, index_dir,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen t_strconcat(box->index_prefix, ".pvt", NULL));
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen mail_storage_get_lock_timeout(box->storage, -1U));
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainenint mailbox_open_index_pvt(struct mailbox *box)
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen if ((ret = mailbox_alloc_index_pvt(box)) <= 0)
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen if (mail_index_open(box->index_pvt, MAIL_INDEX_OPEN_FLAG_CREATE) < 0)
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen box->view_pvt = mail_index_view_open(box->index_pvt);
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainenint mailbox_open_stream(struct mailbox *box, struct istream *input)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenint mailbox_enable(struct mailbox *box, enum mailbox_feature features)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenenum mailbox_feature mailbox_get_enabled_features(struct mailbox *box)
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainenvoid mail_storage_free_binary_cache(struct mail_storage *storage)
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen i_stream_destroy(&storage->binary_cache.input);
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen memset(&storage->binary_cache, 0, sizeof(storage->binary_cache));
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 *key)
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;
return ret;
struct mailbox_transaction_context *
int ret;
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;