mail-storage.c revision b12798bbbda561680191eef393c6ee7259569850
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "ioloop.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "array.h"
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen#include "llist.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen#include "str.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "str-sanitize.h"
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen#include "sha1.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "unichar.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "hex-binary.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "file-create-locked.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "istream.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "eacces-error.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "mkdir-parents.h"
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen#include "time-util.h"
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen#include "var-expand.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen#include "dsasl-client.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "imap-date.h"
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen#include "settings-parser.h"
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen#include "mail-index-private.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "mail-index-alloc-cache.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "mailbox-tree.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "mailbox-list-private.h"
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen#include "mail-storage-private.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "mail-storage-settings.h"
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen#include "mail-namespace.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "mail-search.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "mail-search-register.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "mail-search-mime-register.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "mailbox-search-result-private.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "mailbox-guid-cache.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "mail-cache.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include <ctype.h>
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen#define MAILBOX_DELETE_RETRY_SECS 30
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 255
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenextern struct mail_search_register *mail_search_register_imap;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenextern struct mail_search_register *mail_search_register_human;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenstruct mail_module_register mail_module_register = { 0 };
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo SirainenARRAY_TYPE(mail_storage) mail_storage_classes;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic int mail_storage_init_refcount = 0;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenvoid mail_storage_init(void)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen{
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (mail_storage_init_refcount++ > 0)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen return;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen dsasl_clients_init();
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen mailbox_attributes_init();
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen mailbox_lists_init();
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen mail_storage_hooks_init();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_array_init(&mail_storage_classes, 8);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_storage_register_all();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_list_register_all();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mail_storage_deinit(void)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(mail_storage_init_refcount > 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (--mail_storage_init_refcount > 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mail_search_register_human != NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_search_register_deinit(&mail_search_register_human);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mail_search_register_imap != NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_search_register_deinit(&mail_search_register_imap);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_search_mime_register_deinit();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (array_is_created(&mail_storage_classes))
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_free(&mail_storage_classes);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen mail_storage_hooks_deinit();
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen mailbox_lists_deinit();
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen mailbox_attributes_deinit();
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen dsasl_clients_deinit();
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* append it after the list, so the autodetection order is correct */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mail_storage *const *classes;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int i, count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen classes = array_get(&mail_storage_classes, &count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < count; i++) {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (classes[i] == storage_class) {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen array_delete(&mail_storage_classes, i, 1);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen break;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen}
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen{
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct mail_storage *const *classes;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen unsigned int i, count;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen i_assert(name != NULL);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen classes = array_get(&mail_storage_classes, &count);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen for (i = 0; i < count; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strcasecmp(classes[i]->name, name) == 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return classes[i];
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic struct mail_storage *
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mailbox_list_settings *set)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mail_storage *const *classes;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen unsigned int i, count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen classes = array_get(&mail_storage_classes, &count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < count; i++) {
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen if (classes[i]->v.autodetect != NULL) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (classes[i]->v.autodetect(ns, set))
6600c05e2ab38e9f662582b63c56b0c980a03748Timo Sirainen return classes[i];
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return NULL;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen}
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenstatic void
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen{
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen const char *p;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen p = *data;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen while (i_isalnum(*p) || *p == '_') p++;
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (*p == ':' && p != *data) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* no autodetection if the storage driver is given. */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen *driver = t_strdup_until(*data, p);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen *data = p + 1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainenstatic struct mail_storage *
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mailbox_list_settings *list_set,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen enum mail_storage_flags flags, const char **error_r)
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen{
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen struct mail_storage *storage_class = NULL;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen const char *home;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (driver == NULL) {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen /* no mail_location, autodetect */
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen } else if (strcmp(driver, "auto") == 0) {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen /* explicit autodetection with "auto" driver. */
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (list_set->root_dir != NULL &&
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen *list_set->root_dir == '\0') {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* handle the same as with driver=NULL */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list_set->root_dir = NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen } else {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen storage_class = mail_user_get_storage_class(ns->user, driver);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (storage_class == NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen *error_r = t_strdup_printf(
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen "Unknown mail storage driver %s", driver);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (list_set->root_dir == NULL || *list_set->root_dir == '\0') {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* no root directory given. is this allowed? */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const struct mailbox_list *list;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list = list_set->layout == NULL ? NULL :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mailbox_list_find_class(list_set->layout);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (storage_class == NULL &&
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen (flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* autodetection should take care of this */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk } else if (storage_class != NULL &&
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk (storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* root not required for this storage */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk } else if (list != NULL &&
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk (list->props & MAILBOX_LIST_PROP_NO_ROOT) != 0) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* root not required for this layout */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk } else {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen *error_r = "Root mail directory not given";
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen }
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen if (storage_class != NULL) {
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen storage_class->v.get_list_settings(ns, list_set);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen return storage_class;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (storage_class != NULL)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return storage_class;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
9abf5be0962538e1f6f5c73c838ff677341da0c9Timo Sirainen (void)mail_user_get_home(ns->user, &home);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen *error_r = t_strdup_printf(
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "Mail storage autodetection failed with home=%s", home);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen } else if (strncmp(ns->set->location, "auto:", 5) == 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen *error_r = t_strdup_printf(
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "Autodetection failed for %s (home=%s)",
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen ns->set->location, home);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen } else {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen *error_r = t_strdup_printf(
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "Ambiguous mail location setting, "
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "don't know what to do with it: %s "
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "(try prefixing it with mbox: or maildir:)",
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen ns->set->location);
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen }
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen return NULL;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen}
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenstatic int
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenmail_storage_verify_root(const char *root_dir, const char *dir_type,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen bool autocreate, const char **error_r)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen{
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen struct stat st;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (stat(root_dir, &st) == 0) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* exists */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (S_ISDIR(st.st_mode))
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainen return 1;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen *error_r = t_strdup_printf(
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen "Root mail directory is a file: %s", root_dir);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return -1;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen } else if (errno == EACCES) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return -1;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen } else if (errno != ENOENT) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return -1;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen } else if (!autocreate) {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen *error_r = t_strdup_printf(
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen "Root %s directory doesn't exist: %s", dir_type, root_dir);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return -1;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen } else {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* doesn't exist */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return 0;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen}
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic int
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenmail_storage_create_root(struct mailbox_list *list,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen enum mail_storage_flags flags, const char **error_r)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen const char *root_dir, *type_name, *error;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen enum mailbox_list_path_type type;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen bool autocreate;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen int ret;
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen if (list->set.iter_from_index_dir) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen type = MAILBOX_LIST_PATH_TYPE_INDEX;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen type_name = "index";
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen } else {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen type = MAILBOX_LIST_PATH_TYPE_MAILBOX;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen type_name = "mail";
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (!mailbox_list_get_root_path(list, type, &root_dir)) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* storage doesn't use directories (e.g. shared root) */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return 0;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOVERIFY) != 0) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (!list->mail_set->mail_debug)
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen return 0;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen /* we don't need to verify, but since debugging is
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen enabled, check and log if the root doesn't exist */
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (mail_storage_verify_root(root_dir, type_name, FALSE, &error) < 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_debug("Namespace %s: Creating storage despite: %s",
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen list->ns->prefix, error);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen return 0;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen autocreate = (flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) == 0;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (autocreate && list->set.iter_from_index_dir) {
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen /* If the directories don't exist, we'll just autocreate them
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen later. FIXME: Make this the default in v2.3 even when
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ITERINDEX isn't used. */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return 0;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen ret = mail_storage_verify_root(root_dir, type_name, autocreate, error_r);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (ret == 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen ret = mailbox_list_try_mkdir_root(list, root_dir,
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen error_r);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return ret < 0 ? -1 : 0;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen}
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstatic bool
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenmail_storage_match_class(struct mail_storage *storage,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen const struct mail_storage *storage_class,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const struct mailbox_list_settings *set)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (strcmp(storage->name, storage_class->name) != 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return FALSE;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0 &&
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen strcmp(storage->unique_root_dir,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen (set->root_dir != NULL ? set->root_dir : "")) != 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return FALSE;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen if (strcmp(storage->name, "shared") == 0) {
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen /* allow multiple independent shared namespaces */
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen return FALSE;
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen }
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen return TRUE;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic struct mail_storage *
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenmail_storage_find(struct mail_user *user,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const struct mail_storage *storage_class,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const struct mailbox_list_settings *set)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen struct mail_storage *storage = user->storages;
4a514fb20e04df397842cde11cc9ea92abfe9728Timo Sirainen
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen for (; storage != NULL; storage = storage->next) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (mail_storage_match_class(storage, storage_class, set))
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return storage;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return NULL;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenint mail_storage_create_full(struct mail_namespace *ns, const char *driver,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const char *data, enum mail_storage_flags flags,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct mail_storage **storage_r,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const char **error_r)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct mail_storage *storage_class, *storage = NULL;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct mailbox_list *list;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct mailbox_list_settings list_set;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen enum mailbox_list_flags list_flags = 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *p;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen ns->mail_set->pop3_uidl_format != NULL) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen header MD5 sums stored even if we're not running POP3
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen right now. */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen p = ns->mail_set->pop3_uidl_format;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen while ((p = strchr(p, '%')) != NULL) {
494a5de15db3b2806ab31d5ecc3e1c306ae14d06Timo Sirainen if (p[1] == '%')
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen p += 2;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen else if (var_get_key(++p) == 'm') {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen break;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mailbox_list_settings_init_defaults(&list_set);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (data == NULL) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* autodetect */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* internal shared namespace */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen list_set.root_dir = ns->user->set->base_dir;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen } else {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (driver == NULL)
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen mail_storage_set_autodetection(&data, &driver);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (mailbox_list_settings_parse(ns->user, data, &list_set,
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen error_r) < 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, flags,
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen error_r);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (storage_class == NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_assert(list_set.layout != NULL);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (ns->list == NULL) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* first storage for namespace */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (mail_storage_is_mailbox_file(storage_class))
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_NO_MAIL_FILES;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_LIST_DELETES) != 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_NO_DELETES;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen list_flags, &list, error_r) < 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen *error_r = t_strdup_printf("Mailbox list driver %s: %s",
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen list_set.layout, *error_r);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) == 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (storage != NULL) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* using an existing storage */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage->refcount++;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mail_namespace_add_storage(ns, storage);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen *storage_r = storage;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage = storage_class->v.alloc();
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen storage->refcount = 1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage->storage_class = storage_class;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage->user = ns->user;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage->set = ns->mail_set;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage->flags = flags;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (storage->v.create != NULL &&
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen storage->v.create(storage, ns, error_r) < 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen pool_unref(&storage->pool);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen return -1;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen T_BEGIN {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen hook_mail_storage_created(storage);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } T_END;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen DLLIST_PREPEND(&ns->user->storages, storage);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mail_namespace_add_storage(ns, storage);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen *storage_r = storage;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen enum mail_storage_flags flags, const char **error_r)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen struct mail_storage *storage;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return mail_storage_create_full(ns, driver, ns->set->location,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen flags, &storage, error_r);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct mail_storage *storage = *_storage;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_assert(storage->refcount > 0);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* set *_storage=NULL only after calling destroy() callback.
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen for example mdbox wants to access ns->storage */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (--storage->refcount > 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *_storage = NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (storage->mailboxes != NULL) {
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen i_panic("Trying to deinit storage without freeing mailbox %s",
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen storage->mailboxes->vname);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (storage->obj_refcount != 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_panic("Trying to deinit storage before freeing its objects");
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen DLLIST_REMOVE(&storage->user->storages, storage);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen storage->v.destroy(storage);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_free(storage->last_internal_error);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen i_free(storage->error_string);
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen if (array_is_created(&storage->error_stack)) {
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen i_assert(array_count(&storage->error_stack) == 0);
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen array_free(&storage->error_stack);
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen }
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen *_storage = NULL;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen pool_unref(&storage->pool);
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen mail_index_alloc_cache_destroy_unrefed();
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen}
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainenvoid mail_storage_obj_ref(struct mail_storage *storage)
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen{
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen i_assert(storage->refcount > 0);
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen if (storage->obj_refcount++ == 0)
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen mail_user_ref(storage->user);
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen}
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenvoid mail_storage_obj_unref(struct mail_storage *storage)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_assert(storage->refcount > 0);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_assert(storage->obj_refcount > 0);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (--storage->obj_refcount == 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct mail_user *user = storage->user;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_user_unref(&user);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_free_and_null(storage->error_string);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_free(storage->last_internal_error);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen storage->last_error_is_internal = FALSE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen storage->error = MAIL_ERROR_NONE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen enum mail_error error, const char *string)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (storage->error_string != string) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_free(storage->error_string);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage->error_string = i_strdup(string);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage->last_error_is_internal = FALSE;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen storage->error = error;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen}
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen{
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen const char *str;
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen str = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen i_free(storage->error_string);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen storage->error_string = i_strdup(str);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen storage->error = MAIL_ERROR_TEMP;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen}
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
b82d6d7f02734007c129fa25bc876049c8d9bddeTimo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen const char *fmt, ...)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen{
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen char *old_error = storage->last_internal_error;
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen va_list va;
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen va_start(va, fmt);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen storage->last_internal_error = i_strdup_vprintf(fmt, va);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk va_end(va);
c78e7a94528078728cc639b26a1c83e11b4d7e1bTimo Sirainen storage->last_error_is_internal = TRUE;
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen i_error("%s", storage->last_internal_error);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* free the old_error only after the new error is generated, because
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen the old_error may be one of the parameters. */
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen i_free(old_error);
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* critical errors may contain sensitive data, so let user
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen see only "Internal error" with a timestamp to make it
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen easier to look from log files the actual error message. */
0910ea0672c0295c442eb686cc41e98656831f37Timo Sirainen mail_storage_set_internal_error(storage);
0910ea0672c0295c442eb686cc41e98656831f37Timo Sirainen}
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
e91543761d0b7b97a1dc28e036e44d76405545c2Timo Sirainenconst char *mail_storage_get_last_internal_error(struct mail_storage *storage,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen enum mail_error *error_r)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen{
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (error_r != NULL)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen *error_r = storage->error;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (storage->last_error_is_internal) {
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen i_assert(storage->last_internal_error != NULL);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return storage->last_internal_error;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen }
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return mail_storage_get_last_error(storage, error_r);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen}
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainenconst char *mailbox_get_last_internal_error(struct mailbox *box,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen enum mail_error *error_r)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen{
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return mail_storage_get_last_internal_error(mailbox_get_storage(box),
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen error_r);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen}
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainenvoid mail_storage_copy_error(struct mail_storage *dest,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen struct mail_storage *src)
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen{
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen const char *str;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen enum mail_error error;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (src == dest)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen str = mail_storage_get_last_error(src, &error);
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen mail_storage_set_error(dest, error, str);
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen}
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volkvoid mail_storage_copy_list_error(struct mail_storage *storage,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct mailbox_list *list)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen{
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk const char *str;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk enum mail_error error;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
c78e7a94528078728cc639b26a1c83e11b4d7e1bTimo Sirainen str = mailbox_list_get_last_error(list, &error);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen mail_storage_set_error(storage, error, str);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen}
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainenvoid mailbox_set_index_error(struct mailbox *box)
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen{
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen if (mail_index_is_deleted(box->index))
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen mailbox_set_deleted(box);
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen else
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen mail_storage_set_internal_error(box->storage);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen mail_index_reset_error(box->index);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen}
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainenconst struct mail_storage_settings *
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainenmail_storage_get_settings(struct mail_storage *storage)
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen{
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return storage->set;
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen}
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstruct mail_user *mail_storage_get_user(struct mail_storage *storage)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return storage->user;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenvoid mail_storage_set_callbacks(struct mail_storage *storage,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct mail_storage_callbacks *callbacks,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen void *context)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen storage->callbacks = *callbacks;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen storage->callback_context = context;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenint mail_storage_purge(struct mail_storage *storage)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return storage->v.purge == NULL ? 0 :
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen storage->v.purge(storage);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenconst char *mail_storage_get_last_error(struct mail_storage *storage,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen enum mail_error *error_r)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* We get here only in error situations, so we have to return some
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen error. If storage->error is NONE, it means we forgot to set it at
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen some point.. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (storage->error == MAIL_ERROR_NONE) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (error_r != NULL)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen *error_r = MAIL_ERROR_TEMP;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return storage->error_string != NULL ? storage->error_string :
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen "BUG: Unknown internal error";
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (storage->error_string == NULL) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* This shouldn't happen.. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen storage->error_string =
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_strdup_printf("BUG: Unknown 0x%x error",
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen storage->error);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (error_r != NULL)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen *error_r = storage->error;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return storage->error_string;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenconst char *mailbox_get_last_error(struct mailbox *box,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen enum mail_error *error_r)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return mail_storage_get_last_error(box->storage, error_r);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenenum mail_error mailbox_get_last_mail_error(struct mailbox *box)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen enum mail_error error;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen mail_storage_get_last_error(box->storage, &error);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return error;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenvoid mail_storage_last_error_push(struct mail_storage *storage)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct mail_storage_error *err;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (!array_is_created(&storage->error_stack))
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_array_init(&storage->error_stack, 2);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen err = array_append_space(&storage->error_stack);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen err->error_string = i_strdup(storage->error_string);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen err->error = storage->error;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen err->last_error_is_internal = storage->last_error_is_internal;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (err->last_error_is_internal)
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen err->last_internal_error = i_strdup(storage->last_internal_error);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainenvoid mail_storage_last_error_pop(struct mail_storage *storage)
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen unsigned int count = array_count(&storage->error_stack);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const struct mail_storage_error *err =
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen array_idx(&storage->error_stack, count-1);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_free(storage->error_string);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_free(storage->last_internal_error);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen storage->error_string = err->error_string;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen storage->error = err->error;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen storage->last_error_is_internal = err->last_error_is_internal;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen storage->last_internal_error = err->last_internal_error;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen array_delete(&storage->error_stack, count-1, 1);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenbool mail_storage_is_mailbox_file(struct mail_storage *storage)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return (storage->class_flags &
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE) != 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenbool mail_storage_set_error_from_errno(struct mail_storage *storage)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const char *error_string;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen enum mail_error error;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (!mail_error_from_errno(&error, &error_string))
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return FALSE;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* debugging is enabled - admin may be debugging a
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen (permission) problem, so return FALSE to get the caller to
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen log the full error message. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return FALSE;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen mail_storage_set_error(storage, error, error_string);
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen return TRUE;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenconst struct mailbox_settings *
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenmailbox_settings_find(struct mail_namespace *ns, const char *vname)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct mailbox_settings *const *box_set;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen if (!array_is_created(&ns->set->mailboxes))
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return NULL;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (ns->prefix_len > 0 &&
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen strncmp(ns->prefix, vname, ns->prefix_len-1) == 0) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (vname[ns->prefix_len-1] == mail_namespace_get_sep(ns))
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen vname += ns->prefix_len;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen else if (vname[ns->prefix_len-1] == '\0') {
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen /* namespace prefix itself */
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen vname = "";
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen }
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen array_foreach(&ns->set->mailboxes, box_set) {
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen if (strcmp((*box_set)->name, vname) == 0)
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen return *box_set;
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen }
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen return NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstruct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen enum mailbox_flags flags)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen struct mailbox_list *new_list = list;
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen struct mail_storage *storage;
9f1a154d6f436e67f22f737f66bb148b502d4d2aTimo Sirainen struct mailbox *box;
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen enum mail_error open_error = 0;
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen const char *errstr = NULL;
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen i_assert(uni_utf8_str_is_valid(vname));
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen if (strncasecmp(vname, "INBOX", 5) == 0 &&
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen strncmp(vname, "INBOX", 5) != 0) {
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen /* make sure INBOX shows up in uppercase everywhere. do this
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen regardless of whether we're in inbox=yes namespace, because
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen clients expect INBOX to be case insensitive regardless of
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen server's internal configuration. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (vname[5] == '\0')
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen vname = "INBOX";
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen else if (vname[5] != mail_namespace_get_sep(list->ns))
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen /* not INBOX prefix */ ;
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen else if (strncasecmp(list->ns->prefix, vname, 6) == 0 &&
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen strncmp(list->ns->prefix, "INBOX", 5) != 0) {
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen mailbox_list_set_critical(list,
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen "Invalid server configuration: "
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen "Namespace prefix=%s must be uppercase INBOX",
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen list->ns->prefix);
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen open_error = MAIL_ERROR_TEMP;
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen } else {
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen vname = t_strconcat("INBOX", vname + 5, NULL);
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen }
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen }
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen T_BEGIN {
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen if (mailbox_list_get_storage(&new_list, vname, &storage) < 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* do a delayed failure at mailbox_open() */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen storage = mail_namespace_get_default_storage(list->ns);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen errstr = mailbox_list_get_last_error(new_list, &open_error);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen errstr = t_strdup(errstr);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen box = storage->v.mailbox_alloc(storage, new_list, vname, flags);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen box->set = mailbox_settings_find(new_list->ns, vname);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen box->open_error = open_error;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen if (open_error != 0)
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen mail_storage_set_error(storage, open_error, errstr);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen hook_mailbox_allocated(box);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen } T_END;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen DLLIST_PREPEND(&box->storage->mailboxes, box);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen mail_storage_obj_ref(box->storage);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen return box;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen}
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainenstruct mailbox *mailbox_alloc_guid(struct mailbox_list *list,
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen const guid_128_t guid,
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen enum mailbox_flags flags)
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen{
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen struct mailbox *box = NULL;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen struct mailbox_metadata metadata;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen enum mail_error open_error = MAIL_ERROR_TEMP;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen const char *vname;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen if (mailbox_guid_cache_find(list, guid, &vname) < 0) {
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen vname = NULL;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen } else if (vname != NULL) {
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen box = mailbox_alloc(list, vname, flags);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID,
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen &metadata) < 0) {
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen } else if (memcmp(metadata.guid, guid,
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen sizeof(metadata.guid)) != 0) {
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen /* GUID mismatch, refresh cache and try again */
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen mailbox_free(&box);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen mailbox_guid_cache_refresh(list);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen return mailbox_alloc_guid(list, guid, flags);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen } else {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* successfully opened the correct mailbox */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return box;
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen }
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen i_error("mailbox_alloc_guid(%s): "
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen "Couldn't verify mailbox GUID: %s",
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen guid_128_to_string(guid),
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen mailbox_get_last_internal_error(box, NULL));
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen vname = NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_free(&box);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else {
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen vname = t_strdup_printf("(nonexistent mailbox with GUID=%s)",
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen guid_128_to_string(guid));
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen open_error = MAIL_ERROR_NOTFOUND;
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen }
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen if (vname == NULL) {
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen vname = t_strdup_printf("(error in mailbox with GUID=%s)",
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen guid_128_to_string(guid));
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen }
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen box = mailbox_alloc(list, vname, flags);
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen box->open_error = open_error;
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen return box;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen}
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_set_reason(struct mailbox *box, const char *reason)
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(reason != NULL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen box->reason = p_strdup(box->pool, reason);
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen}
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainenbool mailbox_is_autocreated(struct mailbox *box)
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen{
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen if (box->inbox_user)
f97cacf16251b42f530c6a28686cc8c9aa7df3a2Timo Sirainen return TRUE;
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen return box->set != NULL &&
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen strcmp(box->set->autocreate, MAILBOX_SET_AUTO_NO) != 0;
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen}
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainenstatic int mailbox_autocreate(struct mailbox *box)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen{
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen const char *errstr;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen enum mail_error error;
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen if (mailbox_create(box, NULL, FALSE) < 0) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen errstr = mailbox_get_last_internal_error(box, &error);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (error != MAIL_ERROR_EXISTS) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen mail_storage_set_critical(box->storage,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen "Failed to autocreate mailbox %s: %s",
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen box->vname, errstr);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen return -1;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen }
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen } else if (box->set != NULL &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen strcmp(box->set->autocreate,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen MAILBOX_SET_AUTO_SUBSCRIBE) == 0) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (mailbox_set_subscribed(box, TRUE) < 0) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_storage_set_critical(box->storage,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen "Failed to autosubscribe to mailbox %s: %s",
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen box->vname,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mailbox_get_last_internal_error(box, NULL));
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return -1;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return 0;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenstatic int mailbox_autocreate_and_reopen(struct mailbox *box)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen int ret;
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen if (mailbox_autocreate(box) < 0)
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen return -1;
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen mailbox_close(box);
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen ret = box->v.open(box);
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen if (ret < 0 && box->inbox_user &&
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen !box->storage->user->inbox_open_error_logged) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen box->storage->user->inbox_open_error_logged = TRUE;
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen mail_storage_set_critical(box->storage,
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen "Opening INBOX failed: %s",
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen mailbox_get_last_internal_error(box, NULL));
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return ret;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenstatic bool
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenmailbox_name_verify_separators(const char *vname, char sep,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char **error_r)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen unsigned int i;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen bool prev_sep = FALSE;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* Make sure the vname is correct: non-empty, doesn't begin or end
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen with separator and no adjacent separators */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen for (i = 0; vname[i] != '\0'; i++) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (vname[i] == sep) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (prev_sep) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen *error_r = "Has adjacent hierarchy separators";
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return FALSE;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen prev_sep = TRUE;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen } else {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen prev_sep = FALSE;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (prev_sep && i > 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen *error_r = "Ends with hierarchy separator";
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return FALSE;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return TRUE;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenstatic int mailbox_verify_name(struct mailbox *box)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen struct mail_namespace *ns = box->list->ns;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char *error, *vname = box->vname;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen char list_sep, ns_sep;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (box->inbox_user) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* this is INBOX - don't bother with further checks */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return 0;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen list_sep = mailbox_list_get_hierarchy_sep(box->list);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen ns_sep = mail_namespace_get_sep(ns);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (ns->prefix_len > 0) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* vname is either "namespace/box" or "namespace" */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (strncmp(vname, ns->prefix, ns->prefix_len-1) != 0 ||
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen (vname[ns->prefix_len-1] != '\0' &&
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen vname[ns->prefix_len-1] != ns->prefix[ns->prefix_len-1])) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* User input shouldn't normally be able to get us in
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen here. The main reason this isn't an assert is to
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen allow any input at all to mailbox_verify_*_name()
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen without crashing. */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen t_strdup_printf("Invalid mailbox name '%s': "
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen "Missing namespace prefix '%s'",
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_sanitize(vname, 80), ns->prefix));
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return -1;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen vname += ns->prefix_len - 1;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (vname[0] != '\0') {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen i_assert(vname[0] == ns->prefix[ns->prefix_len-1]);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen vname++;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (vname[0] == '\0') {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* "namespace/" isn't a valid mailbox name. */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_storage_set_error(box->storage,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen MAIL_ERROR_PARAMS,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen "Invalid mailbox name");
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return -1;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (ns_sep != list_sep && box->list->set.escape_char == '\0' &&
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen strchr(vname, list_sep) != NULL) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, t_strdup_printf(
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen "Character not allowed in mailbox name: '%c'", list_sep));
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return -1;
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen }
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen if (vname[0] == ns_sep &&
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen !box->storage->set->mail_full_filesystem_access) {
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen "Invalid mailbox name: Begins with hierarchy separator");
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen return -1;
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen }
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen if (!mailbox_name_verify_separators(vname, ns_sep, &error) ||
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen !mailbox_list_is_valid_name(box->list, box->name, &error)) {
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen t_strdup_printf("Invalid mailbox name: %s", error));
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen return -1;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return 0;
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen}
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainenstatic int mailbox_verify_existing_name(struct mailbox *box)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char *path;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen if (box->opened)
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen return 0;
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen if (mailbox_verify_name(box) < 0)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen return -1;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen /* Make sure box->_path is set, so mailbox_get_path() works from
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen now on. Note that this may also fail with some backends if the
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen mailbox doesn't exist. */
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX, &path) < 0) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (box->storage->error != MAIL_ERROR_NOTFOUND ||
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen !mailbox_is_autocreated(box))
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return -1;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen /* if this is an autocreated mailbox, create it now */
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (mailbox_autocreate(box) < 0)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen return -1;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen mailbox_close(box);
407453d06e5622ac3bf099cc76bfcbfb5860b444Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen &path) < 0)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen return -1;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen }
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen return 0;
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen}
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenstatic bool mailbox_name_has_control_chars(const char *name)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen const char *p;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen for (p = name; *p != '\0'; p++) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if ((unsigned char)*p < ' ')
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen return TRUE;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen }
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen return FALSE;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen}
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenvoid mailbox_skip_create_name_restrictions(struct mailbox *box, bool set)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen box->skip_create_name_restrictions = set;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenint mailbox_verify_create_name(struct mailbox *box)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen /* mailbox_alloc() already checks that vname is valid UTF8,
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen so we don't need to verify that.
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen check vname instead of storage name, because vname is what is
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen visible to users, while storage name may be a fixed length GUID. */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (mailbox_verify_name(box) < 0)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return -1;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (box->skip_create_name_restrictions)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return 0;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (mailbox_name_has_control_chars(box->vname)) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen "Control characters not allowed in new mailbox names");
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return -1;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (strlen(box->vname) > MAILBOX_LIST_NAME_MAX_LENGTH) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen "Mailbox name too long");
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return -1;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* check individual component names, too */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char *old_name = box->name;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char *name;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen const char sep = mailbox_list_get_hierarchy_sep(box->list);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen while((name = strchr(old_name, sep)) != NULL) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (name - old_name > MAILBOX_MAX_HIERARCHY_NAME_LENGTH) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen "Mailbox name too long");
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen return -1;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen }
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen name++;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen old_name = name;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen }
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (strlen(old_name) > MAILBOX_MAX_HIERARCHY_NAME_LENGTH) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen "Mailbox name too long");
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen return -1;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return 0;
e7157fa0ad659fa7984f3e6c59c195221c53ac64Timo Sirainen}
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenstatic bool have_listable_namespace_prefix(struct mail_namespace *ns,
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen const char *name)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen size_t name_len = strlen(name);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen for (; ns != NULL; ns = ns->next) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen continue;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (ns->prefix_len <= name_len)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen continue;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* if prefix has multiple hierarchies, match
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen any of the hierarchies */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (strncmp(ns->prefix, name, name_len) == 0 &&
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen ns->prefix[name_len] == mail_namespace_get_sep(ns))
407453d06e5622ac3bf099cc76bfcbfb5860b444Timo Sirainen return TRUE;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return FALSE;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenint mailbox_exists(struct mailbox *box, bool auto_boxes,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen enum mailbox_existence *existence_r)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen switch (box->open_error) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen case 0:
61e84692827b6a64912343f515c984853021483aTimo Sirainen break;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen case MAIL_ERROR_NOTFOUND:
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *existence_r = MAILBOX_EXISTENCE_NONE;
b337d3b6871b878d6467d7d8ed600433af5da5a1Timo Sirainen return 0;
b337d3b6871b878d6467d7d8ed600433af5da5a1Timo Sirainen default:
b337d3b6871b878d6467d7d8ed600433af5da5a1Timo Sirainen /* unsure if this exists or not */
b337d3b6871b878d6467d7d8ed600433af5da5a1Timo Sirainen return -1;
b337d3b6871b878d6467d7d8ed600433af5da5a1Timo Sirainen }
b337d3b6871b878d6467d7d8ed600433af5da5a1Timo Sirainen if (mailbox_verify_name(box) < 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* the mailbox name is invalid. we don't know if it currently
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen exists or not, but since it can never be accessed in any way
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen report it as if it didn't exist. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *existence_r = MAILBOX_EXISTENCE_NONE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (auto_boxes && mailbox_is_autocreated(box)) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *existence_r = MAILBOX_EXISTENCE_SELECT;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen if (box->v.exists(box, auto_boxes, existence_r) < 0)
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen return -1;
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen if (!box->inbox_user && *existence_r == MAILBOX_EXISTENCE_NOSELECT &&
b6eced3d628ad0c50a3cbc9f966da0edc20108abTimo Sirainen have_listable_namespace_prefix(box->storage->user->namespaces,
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen box->vname)) {
b6eced3d628ad0c50a3cbc9f966da0edc20108abTimo Sirainen /* listable namespace prefix always exists. */
b6eced3d628ad0c50a3cbc9f966da0edc20108abTimo Sirainen *existence_r = MAILBOX_EXISTENCE_NOSELECT;
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen return 0;
81fa2cf342657ee5ed02b7b36014dc08a254b006Timo Sirainen }
af86c8415338fc2ea1819dc091b971c93cbee5d2Timo Sirainen
af86c8415338fc2ea1819dc091b971c93cbee5d2Timo Sirainen /* if this is a shared namespace with only INBOX and
af86c8415338fc2ea1819dc091b971c93cbee5d2Timo Sirainen mail_shared_explicit_inbox=no, we'll need to mark the namespace as
b6eced3d628ad0c50a3cbc9f966da0edc20108abTimo Sirainen usable here since nothing else will. */
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen return 0;
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen}
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainenstatic int ATTR_NULL(2)
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainenmailbox_open_full(struct mailbox *box, struct istream *input)
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen{
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen int ret;
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen
b6eced3d628ad0c50a3cbc9f966da0edc20108abTimo Sirainen if (box->opened)
b6eced3d628ad0c50a3cbc9f966da0edc20108abTimo Sirainen return 0;
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen if (box->storage->set->mail_debug && box->reason != NULL) {
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen i_debug("%s: Mailbox opened because: %s",
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen box->vname, box->reason);
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen }
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen switch (box->open_error) {
b6eced3d628ad0c50a3cbc9f966da0edc20108abTimo Sirainen case 0:
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen break;
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen case MAIL_ERROR_NOTFOUND:
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen return -1;
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen default:
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen mail_storage_set_internal_error(box->storage);
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen box->storage->error = box->open_error;
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen return -1;
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen }
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen if (mailbox_verify_existing_name(box) < 0)
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen return -1;
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen if (input != NULL) {
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen if ((box->storage->class_flags &
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) == 0) {
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen mail_storage_set_critical(box->storage,
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen "Storage doesn't support streamed mailboxes");
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen return -1;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen }
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen box->input = input;
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen box->flags |= MAILBOX_FLAG_READONLY;
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen i_stream_ref(box->input);
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen }
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen T_BEGIN {
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen ret = box->v.open(box);
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen } T_END;
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen if (ret < 0 && box->storage->error == MAIL_ERROR_NOTFOUND &&
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen !box->deleting &&
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen box->input == NULL && mailbox_is_autocreated(box)) T_BEGIN {
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen ret = mailbox_autocreate_and_reopen(box);
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen } T_END;
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen if (ret < 0) {
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen if (box->input != NULL)
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen i_stream_unref(&box->input);
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen return -1;
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen }
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen return 0;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen}
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenstatic bool mailbox_try_undelete(struct mailbox *box)
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen{
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen time_t mtime;
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen i_assert(!box->mailbox_undeleting);
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen if ((box->flags & MAILBOX_FLAG_READONLY) != 0) {
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen /* most importantly we don't do this because we want to avoid
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen a loop: mdbox storage rebuild -> mailbox_open() ->
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen mailbox_mark_index_deleted() -> mailbox_sync() ->
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen mdbox storage rebuild. */
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen return FALSE;
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen }
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen if (mail_index_get_modification_time(box->index, &mtime) < 0)
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen return FALSE;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen if (mtime + MAILBOX_DELETE_RETRY_SECS > time(NULL))
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen return FALSE;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen box->mailbox_undeleting = TRUE;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen int ret = mailbox_mark_index_deleted(box, FALSE);
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen box->mailbox_undeleting = FALSE;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen if (ret < 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen box->mailbox_deleted = FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return TRUE;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen}
5a0fc34c5cc525334c5a10531713017ae321c573Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenint mailbox_open(struct mailbox *box)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen{
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* check that the storage supports stubs if require them */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (((box->flags & MAILBOX_FLAG_USE_STUBS) != 0) &&
5a0fc34c5cc525334c5a10531713017ae321c573Timo Sirainen ((box->storage->storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_STUBS) == 0)) {
5a0fc34c5cc525334c5a10531713017ae321c573Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen "Mailbox does not support mail stubs");
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen return -1;
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen }
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen if (mailbox_open_full(box, NULL) < 0) {
9c66dd5c3e2ba484a5c7cdb98a139bda31fdfaa4Timo Sirainen if (!box->mailbox_deleted || box->mailbox_undeleting)
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen return -1;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen /* mailbox has been marked as deleted. if this deletion
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen started (and crashed) a long time ago, it can be confusing
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen to user that the mailbox can't be opened. so we'll just
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen undelete it and reopen. */
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen if(!mailbox_try_undelete(box))
1c1e571f549f09f6547ed142f4b3a725dd9f7245Timo Sirainen return -1;
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen /* make sure we close the mailbox in the middle. some backends
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen may not have fully opened the mailbox while it was being
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen undeleted. */
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen mailbox_close(box);
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen if (mailbox_open_full(box, NULL) < 0)
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen return -1;
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen }
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen return 0;
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen}
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainenstatic int mailbox_alloc_index_pvt(struct mailbox *box)
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen{
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen const char *index_dir;
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen int ret;
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen if (box->index_pvt != NULL)
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen return 1;
9c66dd5c3e2ba484a5c7cdb98a139bda31fdfaa4Timo Sirainen
0185427dd52fddec6fc76d6e99c7659620d4366eTimo Sirainen ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE,
9c66dd5c3e2ba484a5c7cdb98a139bda31fdfaa4Timo Sirainen &index_dir);
6bc5fed79741503437c6d46d9f282b66bd029c6bTimo Sirainen if (ret <= 0)
9c66dd5c3e2ba484a5c7cdb98a139bda31fdfaa4Timo Sirainen return ret; /* error / no private indexes */
ed704d95cc94390bba7ebf085945caf5957b0c9fTimo Sirainen
6bc5fed79741503437c6d46d9f282b66bd029c6bTimo Sirainen if (mailbox_create_missing_dir(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE) < 0)
6bc5fed79741503437c6d46d9f282b66bd029c6bTimo Sirainen return -1;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen box->index_pvt = mail_index_alloc_cache_get(NULL, index_dir,
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen t_strconcat(box->index_prefix, ".pvt", NULL));
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen mail_index_set_fsync_mode(box->index_pvt,
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen box->storage->set->parsed_fsync_mode, 0);
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen mail_index_set_lock_method(box->index_pvt,
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen box->storage->set->parsed_lock_method,
5a0b68eeaf48cd1655057f36f19357146bf08e1dTimo Sirainen mail_storage_get_lock_timeout(box->storage, UINT_MAX));
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen return 1;
5a0b68eeaf48cd1655057f36f19357146bf08e1dTimo Sirainen}
5a0b68eeaf48cd1655057f36f19357146bf08e1dTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainenint mailbox_open_index_pvt(struct mailbox *box)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen{
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen enum mail_index_open_flags index_flags;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen int ret;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen if (box->view_pvt != NULL)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen return 1;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen if (mailbox_get_private_flags_mask(box) == 0)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen return 0;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen if ((ret = mailbox_alloc_index_pvt(box)) <= 0)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return ret;
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen index_flags = MAIL_INDEX_OPEN_FLAG_CREATE |
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen mail_storage_settings_to_index_flags(box->storage->set);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen if ((box->flags & MAILBOX_FLAG_SAVEONLY) != 0)
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen index_flags |= MAIL_INDEX_OPEN_FLAG_SAVEONLY;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen if (mail_index_open(box->index_pvt, index_flags) < 0)
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen return -1;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen box->view_pvt = mail_index_view_open(box->index_pvt);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen return 1;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen}
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainenint mailbox_open_stream(struct mailbox *box, struct istream *input)
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen{
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen return mailbox_open_full(box, input);
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen}
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainenint mailbox_enable(struct mailbox *box, enum mailbox_feature features)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen{
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen if (mailbox_verify_name(box) < 0)
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen return -1;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen return box->v.enable(box, features);
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen}
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainenenum mailbox_feature mailbox_get_enabled_features(struct mailbox *box)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen{
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen return box->enabled_features;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen}
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainenvoid mail_storage_free_binary_cache(struct mail_storage *storage)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen{
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen if (storage->binary_cache.box == NULL)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen return;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen timeout_remove(&storage->binary_cache.to);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen i_stream_destroy(&storage->binary_cache.input);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen i_zero(&storage->binary_cache);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen}
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainenvoid mailbox_close(struct mailbox *box)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen{
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen if (!box->opened)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen return;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen if (box->transaction_count != 0) {
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen i_panic("Trying to close mailbox %s with open transactions",
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen box->name);
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen }
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen box->v.close(box);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen if (box->storage->binary_cache.box == box)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mail_storage_free_binary_cache(box->storage);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen box->opened = FALSE;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen box->mailbox_deleted = FALSE;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen array_clear(&box->search_results);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen if (array_is_created(&box->recent_flags))
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen array_free(&box->recent_flags);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen box->recent_flags_prev_uid = 0;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen box->recent_flags_count = 0;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainenvoid mailbox_free(struct mailbox **_box)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen struct mailbox *box = *_box;
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen *_box = NULL;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen mailbox_close(box);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen box->v.free(box);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen DLLIST_REMOVE(&box->storage->mailboxes, box);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_storage_obj_unref(box->storage);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (box->metadata_pool != NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool_unref(&box->metadata_pool);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool_unref(&box->pool);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenbool mailbox_equals(const struct mailbox *box1,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const struct mail_namespace *ns2, const char *vname2)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mail_namespace *ns1 = mailbox_get_namespace(box1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *name1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (ns1 != ns2)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen name1 = mailbox_get_vname(box1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strcmp(name1, vname2) == 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
ff4bb2dfb5714eeb0408d3bb862de1646351d097Timo Sirainen return strcasecmp(name1, "INBOX") == 0 &&
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen strcasecmp(vname2, "INBOX") == 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenbool mailbox_is_any_inbox(struct mailbox *box)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return box->inbox_any;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void mailbox_copy_cache_decisions_from_inbox(struct mailbox *box)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mail_namespace *ns =
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_namespace_find_inbox(box->storage->user->namespaces);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mailbox *inbox =
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_alloc(ns->list, "INBOX", MAILBOX_FLAG_READONLY);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen enum mailbox_existence existence;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* this should be NoSelect but since inbox can never be
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen NoSelect we use EXISTENCE_NONE to avoid creating inbox by accident */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_set_reason(inbox, "copy caching decisions");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mailbox_exists(inbox, FALSE, &existence) == 0 &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen existence != MAILBOX_EXISTENCE_NONE &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_open(inbox) == 0 &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_open(box) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mail_index_transaction *dit =
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_index_transaction_begin(box->view,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_cache_decisions_copy(dit, inbox->cache, box->cache);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* we can't do much about errors here */
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen (void)mail_index_transaction_commit(&dit);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen }
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen mailbox_free(&inbox);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen}
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainenint mailbox_create(struct mailbox *box, const struct mailbox_update *update,
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen bool directory)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen{
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen int ret;
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (mailbox_verify_create_name(box) < 0)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen return -1;
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen box->creating = TRUE;
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen ret = box->v.create_box(box, update, directory);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen box->creating = FALSE;
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (ret == 0) {
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen box->list->guid_cache_updated = TRUE;
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (!box->inbox_any)
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen mailbox_copy_cache_decisions_from_inbox(box);
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen } else if (box->opened) {
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* Creation failed after (partially) opening the mailbox.
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen It may not be in a valid state, so close it. */
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen mail_storage_last_error_push(box->storage);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen mailbox_close(box);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen mail_storage_last_error_pop(box->storage);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen }
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen return ret;
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen}
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainenint mailbox_update(struct mailbox *box, const struct mailbox_update *update)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen{
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen int ret;
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen i_assert(update->min_next_uid == 0 ||
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen update->min_first_recent_uid == 0 ||
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen update->min_first_recent_uid <= update->min_next_uid);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (mailbox_verify_existing_name(box) < 0)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen return -1;
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen ret = box->v.update_box(box, update);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (!guid_128_is_empty(update->mailbox_guid))
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen box->list->guid_cache_invalidated = TRUE;
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen return ret;
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen}
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainenint mailbox_mark_index_deleted(struct mailbox *box, bool del)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen{
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen struct mail_index_transaction *trans;
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen enum mail_index_transaction_flags trans_flags = 0;
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen enum mailbox_flags old_flag;
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen int ret;
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen if (box->marked_deleted && del) {
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen /* we already marked it deleted. this allows plugins to
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen "lock" the deletion earlier. */
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen return 0;
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen }
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen old_flag = box->flags & MAILBOX_FLAG_OPEN_DELETED;
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen box->flags |= MAILBOX_FLAG_OPEN_DELETED;
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen ret = mailbox_open(box);
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen box->flags = (box->flags & ~MAILBOX_FLAG_OPEN_DELETED) | old_flag;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen if (ret < 0)
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen return -1;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen trans_flags = del ? 0 : MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL;
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen trans = mail_index_transaction_begin(box->view, trans_flags);
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen if (del)
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen mail_index_set_deleted(trans);
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen else
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen mail_index_set_undeleted(trans);
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen if (mail_index_transaction_commit(&trans) < 0) {
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen mailbox_set_index_error(box);
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen return -1;
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen }
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen if (del) {
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen /* sync the mailbox. this finishes the index deletion and it
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen can succeed only for a single session. we do it here, so the
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen rest of the deletion code doesn't have to worry about race
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen conditions. */
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen box->delete_sync_check = TRUE;
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen ret = mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ);
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen box->delete_sync_check = FALSE;
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen if (ret < 0)
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen return -1;
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen }
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen box->marked_deleted = del;
b30f98f260924a50343c4d0493a7c4fe5e714d0fTimo Sirainen return 0;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen}
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen
b30f98f260924a50343c4d0493a7c4fe5e714d0fTimo Sirainenstatic void mailbox_close_reset_path(struct mailbox *box)
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen{
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen i_zero(&box->_perm);
b30f98f260924a50343c4d0493a7c4fe5e714d0fTimo Sirainen box->_path = NULL;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen box->_index_path = NULL;
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen}
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainenint mailbox_delete(struct mailbox *box)
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen{
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen int ret;
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen if (*box->name == '\0') {
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen "Storage root can't be deleted");
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen return -1;
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen }
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen box->deleting = TRUE;
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen if (mailbox_open(box) < 0) {
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen if (mailbox_get_last_mail_error(box) != MAIL_ERROR_NOTFOUND &&
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen !box->mailbox_deleted)
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen return -1;
4d84348ffcbb60de566108562c95ad64629e7a53Timo Sirainen /* might be a \noselect mailbox, so continue deletion */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ret = box->v.delete_box(box);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen if (ret < 0 && box->marked_deleted) {
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen /* deletion failed. revert the mark so it can maybe be
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tried again later. */
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen if (mailbox_mark_index_deleted(box, FALSE) < 0)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen return -1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen box->deleting = FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_close(box);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* if mailbox is reopened, its path may be different with
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen LAYOUT=index */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_close_reset_path(box);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return ret;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen}
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenint mailbox_delete_empty(struct mailbox *box)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen{
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen int ret;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen /* FIXME: should be a parameter to delete(), but since it changes API
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen don't do it for now */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen box->deleting_must_be_empty = TRUE;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen ret = mailbox_delete(box);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen box->deleting_must_be_empty = FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return ret;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic bool
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenmail_storages_rename_compatible(struct mail_storage *storage1,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen struct mail_storage *storage2,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen const char **error_r)
ac4e6609cbdca594db1b1c02afb1e372ab22e060Timo Sirainen{
ac4e6609cbdca594db1b1c02afb1e372ab22e060Timo Sirainen if (storage1 == storage2)
ac4e6609cbdca594db1b1c02afb1e372ab22e060Timo Sirainen return TRUE;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strcmp(storage1->name, storage2->name) != 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *error_r = t_strdup_printf("storage %s != %s",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen storage1->name, storage2->name);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if ((storage1->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* e.g. mdbox where all mails are in storage/ directory and
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen they can't be easily moved from there. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *error_r = t_strdup_printf("storage %s uses unique root",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen storage1->name);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenstatic bool nullequals(const void *p1, const void *p2)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen{
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen return (p1 == NULL && p2 == NULL) || (p1 != NULL && p2 != NULL);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen}
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenstatic bool
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenmailbox_lists_rename_compatible(struct mailbox_list *list1,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen struct mailbox_list *list2,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen const char **error_r)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen{
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen if (!nullequals(list1->set.alt_dir, list2->set.alt_dir)) {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen *error_r = "one namespace has alt dir and another doesn't";
return FALSE;
}
if (!nullequals(list1->set.index_dir, list2->set.index_dir)) {
*error_r = "one namespace has index dir and another doesn't";
return FALSE;
}
if (!nullequals(list1->set.control_dir, list2->set.control_dir)) {
*error_r = "one namespace has control dir and another doesn't";
return FALSE;
}
return TRUE;
}
static
int mailbox_rename_check_children(struct mailbox *src, struct mailbox *dest)
{
int ret = 0;
size_t src_prefix_len = strlen(src->vname)+1; /* include separator */
size_t dest_prefix_len = strlen(dest->vname)+1;
/* this can return folders with * in their name, that are not
actually our children */
const char *pattern = t_strdup_printf("%s%c*", src->vname,
mail_namespace_get_sep(src->list->ns));
struct mailbox_list_iterate_context *iter = mailbox_list_iter_init(src->list, pattern,
MAILBOX_LIST_ITER_RETURN_NO_FLAGS);
const struct mailbox_info *child;
while((child = mailbox_list_iter_next(iter)) != NULL) {
if (strncmp(child->vname, src->vname, src_prefix_len) != 0)
continue; /* not our child */
/* if total length of new name exceeds the limit, fail */
if (strlen(child->vname + src_prefix_len)+dest_prefix_len > MAILBOX_LIST_NAME_MAX_LENGTH) {
mail_storage_set_error(dest->storage, MAIL_ERROR_PARAMS,
"Mailbox or child name too long");
ret = -1;
break;
}
}
/* something went bad */
if (mailbox_list_iter_deinit(&iter) < 0) {
mail_storage_copy_list_error(dest->storage, src->list);
ret = -1;
}
return ret;
}
int mailbox_rename(struct mailbox *src, struct mailbox *dest)
{
const char *error = NULL;
/* Check only name validity, \Noselect don't necessarily exist. */
if (mailbox_verify_name(src) < 0)
return -1;
if (*src->name == '\0') {
mail_storage_set_error(src->storage, MAIL_ERROR_PARAMS,
"Can't rename mailbox root");
return -1;
}
if (mailbox_verify_create_name(dest) < 0) {
mail_storage_copy_error(dest->storage, src->storage);
return -1;
}
if (mailbox_rename_check_children(src, dest) != 0) {
return -1;
}
if (!mail_storages_rename_compatible(src->storage,
dest->storage, &error) ||
!mailbox_lists_rename_compatible(src->list,
dest->list, &error)) {
if (src->storage->set->mail_debug) {
i_debug("Can't rename '%s' to '%s': %s",
src->vname, dest->vname, error);
}
mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
"Can't rename mailboxes across specified storages.");
return -1;
}
if (src->list != dest->list &&
(src->list->ns->type != MAIL_NAMESPACE_TYPE_PRIVATE ||
dest->list->ns->type != MAIL_NAMESPACE_TYPE_PRIVATE)) {
mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
"Renaming not supported across non-private namespaces.");
return -1;
}
if (src->list == dest->list && strcmp(src->name, dest->name) == 0) {
mail_storage_set_error(src->storage, MAIL_ERROR_EXISTS,
"Can't rename mailbox to itself.");
return -1;
}
if (src->v.rename_box(src, dest) < 0)
return -1;
src->list->guid_cache_invalidated = TRUE;
dest->list->guid_cache_invalidated = TRUE;
return 0;
}
int mailbox_set_subscribed(struct mailbox *box, bool set)
{
if (mailbox_verify_name(box) < 0)
return -1;
if (mailbox_list_iter_subscriptions_refresh(box->list) < 0) {
mail_storage_copy_list_error(box->storage, box->list);
return -1;
}
if (mailbox_is_subscribed(box) == set)
return 0;
return box->v.set_subscribed(box, set);
}
bool mailbox_is_subscribed(struct mailbox *box)
{
struct mailbox_node *node;
i_assert(box->list->subscriptions != NULL);
node = mailbox_tree_lookup(box->list->subscriptions, box->vname);
return node != NULL && (node->flags & MAILBOX_SUBSCRIBED) != 0;
}
struct mail_storage *mailbox_get_storage(const struct mailbox *box)
{
return box->storage;
}
struct mail_namespace *
mailbox_get_namespace(const struct mailbox *box)
{
return box->list->ns;
}
const struct mail_storage_settings *mailbox_get_settings(struct mailbox *box)
{
return box->storage->set;
}
const char *mailbox_get_name(const struct mailbox *box)
{
return box->name;
}
const char *mailbox_get_vname(const struct mailbox *box)
{
return box->vname;
}
bool mailbox_is_readonly(struct mailbox *box)
{
i_assert(box->opened);
return box->v.is_readonly(box);
}
bool mailbox_backends_equal(const struct mailbox *box1,
const struct mailbox *box2)
{
struct mail_namespace *ns1 = box1->list->ns, *ns2 = box2->list->ns;
if (strcmp(box1->name, box2->name) != 0)
return FALSE;
while (ns1->alias_for != NULL)
ns1 = ns1->alias_for;
while (ns2->alias_for != NULL)
ns2 = ns2->alias_for;
return ns1 == ns2;
}
static void
mailbox_get_status_set_defaults(struct mailbox *box,
struct mailbox_status *status_r)
{
i_zero(status_r);
if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUIDS) != 0)
status_r->have_guids = TRUE;
if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_SAVE_GUIDS) != 0)
status_r->have_save_guids = TRUE;
if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUID128) != 0)
status_r->have_only_guid128 = TRUE;
}
int mailbox_get_status(struct mailbox *box,
enum mailbox_status_items items,
struct mailbox_status *status_r)
{
mailbox_get_status_set_defaults(box, status_r);
if (mailbox_verify_existing_name(box) < 0)
return -1;
if (box->v.get_status(box, items, status_r) < 0)
return -1;
i_assert(status_r->have_guids || !status_r->have_save_guids);
return 0;
}
void mailbox_get_open_status(struct mailbox *box,
enum mailbox_status_items items,
struct mailbox_status *status_r)
{
i_assert(box->opened);
i_assert((items & MAILBOX_STATUS_FAILING_ITEMS) == 0);
mailbox_get_status_set_defaults(box, status_r);
if (box->v.get_status(box, items, status_r) < 0)
i_unreached();
}
int mailbox_get_metadata(struct mailbox *box, enum mailbox_metadata_items items,
struct mailbox_metadata *metadata_r)
{
i_zero(metadata_r);
if (mailbox_verify_existing_name(box) < 0)
return -1;
if (box->metadata_pool != NULL)
p_clear(box->metadata_pool);
if (box->v.get_metadata(box, items, metadata_r) < 0)
return -1;
i_assert((items & MAILBOX_METADATA_GUID) == 0 ||
!guid_128_is_empty(metadata_r->guid));
return 0;
}
enum mail_flags mailbox_get_private_flags_mask(struct mailbox *box)
{
if (box->v.get_private_flags_mask != NULL)
return box->v.get_private_flags_mask(box);
else if (box->list->set.index_pvt_dir != NULL)
return MAIL_SEEN; /* FIXME */
else
return 0;
}
struct mailbox_sync_context *
mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct mailbox_sync_context *ctx;
if (box->transaction_count != 0) {
i_panic("Trying to sync mailbox %s with open transactions",
box->name);
}
if (!box->opened) {
if (mailbox_open(box) < 0) {
ctx = i_new(struct mailbox_sync_context, 1);
ctx->box = box;
ctx->flags = flags;
ctx->open_failed = TRUE;
return ctx;
}
}
T_BEGIN {
ctx = box->v.sync_init(box, flags);
} T_END;
return ctx;
}
bool mailbox_sync_next(struct mailbox_sync_context *ctx,
struct mailbox_sync_rec *sync_rec_r)
{
if (ctx->open_failed)
return FALSE;
return ctx->box->v.sync_next(ctx, sync_rec_r);
}
int mailbox_sync_deinit(struct mailbox_sync_context **_ctx,
struct mailbox_sync_status *status_r)
{
struct mailbox_sync_context *ctx = *_ctx;
struct mailbox *box = ctx->box;
const char *errormsg;
enum mail_error error;
int ret;
*_ctx = NULL;
i_zero(status_r);
if (!ctx->open_failed)
ret = box->v.sync_deinit(ctx, status_r);
else {
i_free(ctx);
ret = -1;
}
if (ret < 0 && box->inbox_user &&
!box->storage->user->inbox_open_error_logged) {
errormsg = mailbox_get_last_internal_error(box, &error);
if (error == MAIL_ERROR_NOTPOSSIBLE) {
box->storage->user->inbox_open_error_logged = TRUE;
i_error("Syncing INBOX failed: %s", errormsg);
}
}
if (ret == 0)
box->synced = TRUE;
return ret;
}
int mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct mailbox_sync_context *ctx;
struct mailbox_sync_status status;
if (array_count(&box->search_results) == 0) {
/* we don't care about mailbox's current state, so we might
as well fix inconsistency state */
flags |= MAILBOX_SYNC_FLAG_FIX_INCONSISTENT;
}
ctx = mailbox_sync_init(box, flags);
return mailbox_sync_deinit(&ctx, &status);
}
#undef mailbox_notify_changes
void mailbox_notify_changes(struct mailbox *box,
mailbox_notify_callback_t *callback, void *context)
{
i_assert(box->opened);
box->notify_callback = callback;
box->notify_context = context;
box->v.notify_changes(box);
}
void mailbox_notify_changes_stop(struct mailbox *box)
{
i_assert(box->opened);
box->notify_callback = NULL;
box->notify_context = NULL;
box->v.notify_changes(box);
}
struct mail_search_context *
mailbox_search_init(struct mailbox_transaction_context *t,
struct mail_search_args *args,
const enum mail_sort_type *sort_program,
enum mail_fetch_field wanted_fields,
struct mailbox_header_lookup_ctx *wanted_headers)
{
i_assert(wanted_headers == NULL || wanted_headers->box == t->box);
mail_search_args_ref(args);
if (!args->simplified)
mail_search_args_simplify(args);
return t->box->v.search_init(t, args, sort_program,
wanted_fields, wanted_headers);
}
int mailbox_search_deinit(struct mail_search_context **_ctx)
{
struct mail_search_context *ctx = *_ctx;
struct mail_search_args *args = ctx->args;
int ret;
*_ctx = NULL;
mailbox_search_results_initial_done(ctx);
ret = ctx->transaction->box->v.search_deinit(ctx);
mail_search_args_unref(&args);
return ret;
}
bool mailbox_search_next(struct mail_search_context *ctx, struct mail **mail_r)
{
bool tryagain;
while (!mailbox_search_next_nonblock(ctx, mail_r, &tryagain)) {
if (!tryagain)
return FALSE;
}
return TRUE;
}
bool mailbox_search_next_nonblock(struct mail_search_context *ctx,
struct mail **mail_r, bool *tryagain_r)
{
struct mailbox *box = ctx->transaction->box;
*mail_r = NULL;
*tryagain_r = FALSE;
if (!box->v.search_next_nonblock(ctx, mail_r, tryagain_r))
return FALSE;
else {
mailbox_search_results_add(ctx, (*mail_r)->uid);
return TRUE;
}
}
bool mailbox_search_seen_lost_data(struct mail_search_context *ctx)
{
return ctx->seen_lost_data;
}
int mailbox_search_result_build(struct mailbox_transaction_context *t,
struct mail_search_args *args,
enum mailbox_search_result_flags flags,
struct mail_search_result **result_r)
{
struct mail_search_context *ctx;
struct mail *mail;
int ret;
ctx = mailbox_search_init(t, args, NULL, 0, NULL);
*result_r = mailbox_search_result_save(ctx, flags);
while (mailbox_search_next(ctx, &mail)) ;
ret = mailbox_search_deinit(&ctx);
if (ret < 0)
mailbox_search_result_free(result_r);
return ret;
}
struct mailbox_transaction_context *
mailbox_transaction_begin(struct mailbox *box,
enum mailbox_transaction_flags flags)
{
struct mailbox_transaction_context *trans;
i_assert((flags & MAILBOX_TRANSACTION_FLAG_FILL_IN_STUB) == 0 ||
(box->flags & MAILBOX_FLAG_USE_STUBS) != 0);
i_assert(box->opened);
box->transaction_count++;
trans = box->v.transaction_begin(box, flags);
trans->flags = flags;
return trans;
}
int mailbox_transaction_commit(struct mailbox_transaction_context **t)
{
struct mail_transaction_commit_changes changes;
int ret;
/* Store changes temporarily so that plugins overriding
transaction_commit() can look at them. */
ret = mailbox_transaction_commit_get_changes(t, &changes);
if (changes.pool != NULL)
pool_unref(&changes.pool);
return ret;
}
int mailbox_transaction_commit_get_changes(
struct mailbox_transaction_context **_t,
struct mail_transaction_commit_changes *changes_r)
{
struct mailbox_transaction_context *t = *_t;
struct mailbox *box = t->box;
unsigned int save_count = t->save_count;
int ret;
changes_r->pool = NULL;
*_t = NULL;
T_BEGIN {
ret = box->v.transaction_commit(t, changes_r);
} T_END;
/* either all the saved messages get UIDs or none, because a) we
failed, b) MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS not set,
c) backend doesn't support it (e.g. virtual plugin) */
i_assert(ret < 0 ||
seq_range_count(&changes_r->saved_uids) == save_count ||
array_count(&changes_r->saved_uids) == 0);
/* decrease the transaction count only after transaction_commit().
that way if it creates and destroys transactions internally, we
don't see transaction_count=0 until the parent transaction is fully
finished */
box->transaction_count--;
if (ret < 0 && changes_r->pool != NULL)
pool_unref(&changes_r->pool);
return ret;
}
void mailbox_transaction_rollback(struct mailbox_transaction_context **_t)
{
struct mailbox_transaction_context *t = *_t;
struct mailbox *box = t->box;
*_t = NULL;
box->v.transaction_rollback(t);
box->transaction_count--;
}
void mailbox_transaction_set_reason(struct mailbox_transaction_context *t,
const char *reason)
{
i_assert(reason != NULL);
i_free(t->reason);
t->reason = i_strdup(reason);
}
unsigned int mailbox_transaction_get_count(const struct mailbox *box)
{
return box->transaction_count;
}
void mailbox_transaction_set_max_modseq(struct mailbox_transaction_context *t,
uint64_t max_modseq,
ARRAY_TYPE(seq_range) *seqs)
{
mail_index_transaction_set_max_modseq(t->itrans, max_modseq, seqs);
}
struct mailbox *
mailbox_transaction_get_mailbox(const struct mailbox_transaction_context *t)
{
return t->box;
}
static void mailbox_save_dest_mail_close(struct mail_save_context *ctx)
{
struct mail_private *mail = (struct mail_private *)ctx->dest_mail;
mail->v.close(&mail->mail);
}
struct mail_save_context *
mailbox_save_alloc(struct mailbox_transaction_context *t)
{
struct mail_save_context *ctx;
T_BEGIN {
ctx = t->box->v.save_alloc(t);
} T_END;
i_assert(!ctx->unfinished);
ctx->unfinished = TRUE;
ctx->data.received_date = (time_t)-1;
ctx->data.save_date = (time_t)-1;
/* Always have a dest_mail available. A lot of plugins make use
of this. */
if (ctx->dest_mail == NULL)
ctx->dest_mail = mail_alloc(t, 0, NULL);
else {
/* make sure the mail isn't used before mail_set_seq_saving() */
mailbox_save_dest_mail_close(ctx);
}
return ctx;
}
void mailbox_save_context_deinit(struct mail_save_context *ctx)
{
i_assert(ctx->dest_mail != NULL);
if (!ctx->dest_mail_external)
mail_free(&ctx->dest_mail);
else
ctx->dest_mail = NULL;
}
void mailbox_save_set_flags(struct mail_save_context *ctx,
enum mail_flags flags,
struct mail_keywords *keywords)
{
struct mailbox *box = ctx->transaction->box;
if (ctx->data.keywords != NULL)
mailbox_keywords_unref(&ctx->data.keywords);
ctx->data.flags = flags & ~mailbox_get_private_flags_mask(box);
ctx->data.pvt_flags = flags & mailbox_get_private_flags_mask(box);
ctx->data.keywords = keywords;
if (keywords != NULL)
mailbox_keywords_ref(keywords);
}
void mailbox_save_copy_flags(struct mail_save_context *ctx, struct mail *mail)
{
const char *const *keywords_list;
struct mail_keywords *keywords;
keywords_list = mail_get_keywords(mail);
keywords = str_array_length(keywords_list) == 0 ? NULL :
mailbox_keywords_create_valid(ctx->transaction->box,
keywords_list);
mailbox_save_set_flags(ctx, mail_get_flags(mail), keywords);
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
}
void mailbox_save_set_min_modseq(struct mail_save_context *ctx,
uint64_t min_modseq)
{
ctx->data.min_modseq = min_modseq;
}
void mailbox_save_set_received_date(struct mail_save_context *ctx,
time_t received_date, int timezone_offset)
{
ctx->data.received_date = received_date;
ctx->data.received_tz_offset = timezone_offset;
}
void mailbox_save_set_save_date(struct mail_save_context *ctx,
time_t save_date)
{
ctx->data.save_date = save_date;
}
void mailbox_save_set_from_envelope(struct mail_save_context *ctx,
const char *envelope)
{
i_free(ctx->data.from_envelope);
ctx->data.from_envelope = i_strdup(envelope);
}
void mailbox_save_set_uid(struct mail_save_context *ctx, uint32_t uid)
{
ctx->data.uid = uid;
if ((ctx->transaction->flags & MAILBOX_TRANSACTION_FLAG_FILL_IN_STUB) != 0) {
if (!mail_index_lookup_seq(ctx->transaction->view, uid,
&ctx->data.stub_seq))
i_panic("Trying to fill in stub for nonexistent UID %u", uid);
}
}
void mailbox_save_set_guid(struct mail_save_context *ctx, const char *guid)
{
i_assert(guid == NULL || *guid != '\0');
i_free(ctx->data.guid);
ctx->data.guid = i_strdup(guid);
}
void mailbox_save_set_pop3_uidl(struct mail_save_context *ctx, const char *uidl)
{
i_assert(*uidl != '\0');
i_assert(strchr(uidl, '\n') == NULL);
i_free(ctx->data.pop3_uidl);
ctx->data.pop3_uidl = i_strdup(uidl);
}
void mailbox_save_set_pop3_order(struct mail_save_context *ctx,
unsigned int order)
{
i_assert(order > 0);
ctx->data.pop3_order = order;
}
void mailbox_save_set_dest_mail(struct mail_save_context *ctx,
struct mail *mail)
{
i_assert(mail != NULL);
if (!ctx->dest_mail_external)
mail_free(&ctx->dest_mail);
ctx->dest_mail = mail;
ctx->dest_mail_external = TRUE;
}
struct mail *mailbox_save_get_dest_mail(struct mail_save_context *ctx)
{
return ctx->dest_mail;
}
int mailbox_save_begin(struct mail_save_context **ctx, struct istream *input)
{
struct mailbox *box = (*ctx)->transaction->box;
int ret;
if (mail_index_is_deleted(box->index)) {
mailbox_set_deleted(box);
mailbox_save_cancel(ctx);
return -1;
}
/* if we're filling in a stub, we must have set UID already
(which in turn sets stub_seq) */
i_assert(((*ctx)->transaction->flags & MAILBOX_TRANSACTION_FLAG_FILL_IN_STUB) == 0 ||
(*ctx)->data.stub_seq != 0);
if (!(*ctx)->copying_or_moving) {
/* We're actually saving the mail. We're not being called by
mail_storage_copy() because backend didn't support fast
copying. */
i_assert(!(*ctx)->copying_via_save);
(*ctx)->saving = TRUE;
} else {
i_assert((*ctx)->copying_via_save);
}
if (box->v.save_begin == NULL) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Saving messages not supported");
ret = -1;
} else T_BEGIN {
ret = box->v.save_begin(*ctx, input);
} T_END;
if (ret < 0) {
mailbox_save_cancel(ctx);
return -1;
}
return 0;
}
int mailbox_save_continue(struct mail_save_context *ctx)
{
int ret;
T_BEGIN {
ret = ctx->transaction->box->v.save_continue(ctx);
} T_END;
return ret;
}
static void
mailbox_save_add_pvt_flags(struct mailbox_transaction_context *t,
enum mail_flags pvt_flags)
{
struct mail_save_private_changes *save;
if (!array_is_created(&t->pvt_saves))
i_array_init(&t->pvt_saves, 8);
save = array_append_space(&t->pvt_saves);
save->mailnum = t->save_count;
save->flags = pvt_flags;
}
static void
mailbox_save_context_reset(struct mail_save_context *ctx, bool success)
{
i_assert(!ctx->unfinished);
if (!ctx->copying_or_moving) {
/* we're finishing a save (not copy/move). Note that we could
have come here also from mailbox_save_cancel(), in which
case ctx->saving may be FALSE. */
i_assert(!ctx->copying_via_save);
i_assert(ctx->saving || !success);
ctx->saving = FALSE;
} else {
i_assert(ctx->copying_via_save || !success);
/* We came from mailbox_copy(). saving==TRUE is possible here
if we also came from mailbox_save_using_mail(). Don't set
saving=FALSE yet in that case, because copy() is still
running. */
}
}
int mailbox_save_finish(struct mail_save_context **_ctx)
{
struct mail_save_context *ctx = *_ctx;
struct mailbox_transaction_context *t = ctx->transaction;
/* we need to keep a copy of this because save_finish implementations
will likely zero the data structure during cleanup */
struct mail_keywords *keywords = ctx->data.keywords;
enum mail_flags pvt_flags = ctx->data.pvt_flags;
bool copying_via_save = ctx->copying_via_save;
int ret;
/* Do one final continue. The caller may not have done it if the
input stream's offset already matched the number of bytes that
were wanted to be saved. But due to nested istreams some of the
underlying ones may not have seen the EOF yet, and haven't flushed
out the pending data. */
if (mailbox_save_continue(ctx) < 0) {
mailbox_save_cancel(_ctx);
return -1;
}
*_ctx = NULL;
ctx->finishing = TRUE;
T_BEGIN {
ret = t->box->v.save_finish(ctx);
} T_END;
ctx->finishing = FALSE;
if (ret == 0 && !copying_via_save) {
if (pvt_flags != 0)
mailbox_save_add_pvt_flags(t, pvt_flags);
t->save_count++;
}
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
mailbox_save_context_reset(ctx, TRUE);
return ret;
}
void mailbox_save_cancel(struct mail_save_context **_ctx)
{
struct mail_save_context *ctx = *_ctx;
struct mail_keywords *keywords = ctx->data.keywords;
*_ctx = NULL;
T_BEGIN {
ctx->transaction->box->v.save_cancel(ctx);
} T_END;
if (keywords != NULL && !ctx->finishing)
mailbox_keywords_unref(&keywords);
/* the dest_mail is no longer valid. if we're still saving
more mails, the mail sequence may get reused. make sure
the mail gets reset in between */
mailbox_save_dest_mail_close(ctx);
mailbox_save_context_reset(ctx, FALSE);
}
struct mailbox_transaction_context *
mailbox_save_get_transaction(struct mail_save_context *ctx)
{
return ctx->transaction;
}
static int mailbox_copy_int(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
struct mailbox_transaction_context *t = ctx->transaction;
struct mail_keywords *keywords = ctx->data.keywords;
enum mail_flags pvt_flags = ctx->data.pvt_flags;
struct mail *backend_mail;
int ret;
*_ctx = NULL;
if (mail_index_is_deleted(t->box->index)) {
mailbox_set_deleted(t->box);
mailbox_save_cancel(&ctx);
return -1;
}
/* bypass virtual storage, so hard linking can be used whenever
possible */
if (mail_get_backend_mail(mail, &backend_mail) < 0) {
mailbox_save_cancel(&ctx);
return -1;
}
i_assert(!ctx->copying_or_moving);
i_assert(ctx->copy_src_mail == NULL);
ctx->copying_or_moving = TRUE;
ctx->copy_src_mail = mail;
ctx->finishing = TRUE;
T_BEGIN {
ret = t->box->v.copy(ctx, backend_mail);
} T_END;
ctx->finishing = FALSE;
if (ret == 0) {
if (pvt_flags != 0)
mailbox_save_add_pvt_flags(t, pvt_flags);
t->save_count++;
}
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
i_assert(!ctx->unfinished);
ctx->copy_src_mail = NULL;
ctx->copying_via_save = FALSE;
ctx->copying_or_moving = FALSE;
ctx->saving = FALSE; /* if we came from mailbox_save_using_mail() */
return ret;
}
int mailbox_copy(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
i_assert(!ctx->saving);
i_assert(!ctx->moving);
return mailbox_copy_int(_ctx, mail);
}
int mailbox_move(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
int ret;
i_assert(!ctx->saving);
i_assert(!ctx->moving);
ctx->moving = TRUE;
if ((ret = mailbox_copy_int(_ctx, mail)) == 0)
mail_expunge(mail);
ctx->moving = FALSE;
return ret;
}
int mailbox_save_using_mail(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
i_assert(!ctx->saving);
i_assert(!ctx->moving);
ctx->saving = TRUE;
return mailbox_copy_int(_ctx, mail);
}
bool mailbox_is_inconsistent(struct mailbox *box)
{
return box->mailbox_deleted || box->v.is_inconsistent(box);
}
void mailbox_set_deleted(struct mailbox *box)
{
mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
"Mailbox was deleted under us");
box->mailbox_deleted = TRUE;
}
static int get_path_to(struct mailbox *box, enum mailbox_list_path_type type,
const char **internal_path, const char **path_r)
{
int ret;
if (internal_path != NULL && *internal_path != NULL) {
if ((*internal_path)[0] == '\0') {
*path_r = NULL;
return 0;
}
*path_r = *internal_path;
return 1;
}
ret = mailbox_list_get_path(box->list, box->name, type, path_r);
if (ret < 0) {
mail_storage_copy_list_error(box->storage, box->list);
return -1;
}
if (internal_path != NULL && *internal_path == NULL)
*internal_path = ret == 0 ? "" : p_strdup(box->pool, *path_r);
return ret;
}
int mailbox_get_path_to(struct mailbox *box, enum mailbox_list_path_type type,
const char **path_r)
{
if (type == MAILBOX_LIST_PATH_TYPE_MAILBOX)
return get_path_to(box, type, &box->_path, path_r);
if (type == MAILBOX_LIST_PATH_TYPE_INDEX)
return get_path_to(box, type, &box->_index_path, path_r);
return get_path_to(box, type, NULL, path_r);
}
const char *mailbox_get_path(struct mailbox *box)
{
i_assert(box->_path != NULL);
i_assert(box->_path[0] != '\0');
return box->_path;
}
const char *mailbox_get_index_path(struct mailbox *box)
{
i_assert(box->_index_path != NULL);
i_assert(box->_index_path[0] != '\0');
return box->_index_path;
}
static void mailbox_get_permissions_if_not_set(struct mailbox *box)
{
if (box->_perm.file_create_mode != 0)
return;
if (box->input != NULL) {
box->_perm.file_uid = geteuid();
box->_perm.file_create_mode = 0600;
box->_perm.dir_create_mode = 0700;
box->_perm.file_create_gid = (gid_t)-1;
box->_perm.file_create_gid_origin = "defaults";
return;
}
struct mailbox_permissions perm;
mailbox_list_get_permissions(box->list, box->name, &perm);
mailbox_permissions_copy(&box->_perm, &perm, box->pool);
}
const struct mailbox_permissions *mailbox_get_permissions(struct mailbox *box)
{
mailbox_get_permissions_if_not_set(box);
if (!box->_perm.mail_index_permissions_set && box->index != NULL) {
box->_perm.mail_index_permissions_set = TRUE;
mail_index_set_permissions(box->index,
box->_perm.file_create_mode,
box->_perm.file_create_gid,
box->_perm.file_create_gid_origin);
}
return &box->_perm;
}
void mailbox_refresh_permissions(struct mailbox *box)
{
i_zero(&box->_perm);
(void)mailbox_get_permissions(box);
}
int mailbox_create_fd(struct mailbox *box, const char *path, int flags,
int *fd_r)
{
const struct mailbox_permissions *perm = mailbox_get_permissions(box);
mode_t old_mask;
int fd;
i_assert((flags & O_CREAT) != 0);
*fd_r = -1;
old_mask = umask(0);
fd = open(path, flags, perm->file_create_mode);
umask(old_mask);
if (fd != -1) {
/* ok */
} else if (errno == EEXIST) {
/* O_EXCL used, caller will handle this error */
return 0;
} else if (errno == ENOENT) {
mailbox_set_deleted(box);
return -1;
} else if (errno == ENOTDIR) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox doesn't allow inferior mailboxes");
return -1;
} else if (mail_storage_set_error_from_errno(box->storage)) {
return -1;
} else {
mail_storage_set_critical(box->storage,
"open(%s, O_CREAT) failed: %m", path);
return -1;
}
if (perm->file_create_gid != (gid_t)-1) {
if (fchown(fd, (uid_t)-1, perm->file_create_gid) == 0) {
/* ok */
} else if (errno == EPERM) {
mail_storage_set_critical(box->storage, "%s",
eperm_error_get_chgrp("fchown", path,
perm->file_create_gid,
perm->file_create_gid_origin));
} else {
mail_storage_set_critical(box->storage,
"fchown(%s) failed: %m", path);
}
}
*fd_r = fd;
return 1;
}
int mailbox_mkdir(struct mailbox *box, const char *path,
enum mailbox_list_path_type type)
{
const struct mailbox_permissions *perm = mailbox_get_permissions(box);
const char *root_dir;
if (!perm->gid_origin_is_mailbox_path) {
/* mailbox root directory doesn't exist, create it */
root_dir = mailbox_list_get_root_forced(box->list, type);
if (mailbox_list_mkdir_root(box->list, root_dir, type) < 0) {
mail_storage_copy_list_error(box->storage, box->list);
return -1;
}
}
if (mkdir_parents_chgrp(path, perm->dir_create_mode,
perm->file_create_gid,
perm->file_create_gid_origin) == 0)
return 1;
else if (errno == EEXIST)
return 0;
else if (errno == ENOTDIR) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox doesn't allow inferior mailboxes");
return -1;
} else if (mail_storage_set_error_from_errno(box->storage)) {
return -1;
} else {
mail_storage_set_critical(box->storage,
"mkdir_parents(%s) failed: %m", path);
return -1;
}
}
int mailbox_create_missing_dir(struct mailbox *box,
enum mailbox_list_path_type type)
{
const char *mail_dir, *dir;
struct stat st;
int ret;
if ((ret = mailbox_get_path_to(box, type, &dir)) <= 0)
return ret;
if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
&mail_dir) < 0)
return -1;
if (null_strcmp(dir, mail_dir) != 0) {
/* Mailbox directory is different - create a missing dir */
} else if ((box->list->props & MAILBOX_LIST_PROP_AUTOCREATE_DIRS) != 0) {
/* This layout (e.g. imapc) wants to autocreate missing mailbox
directories as well. */
} else {
/* If the mailbox directory doesn't exist, the mailbox
shouldn't exist at all. So just assume that it's already
created and if there's a race condition just fail later. */
return 0;
}
/* we call this function even when the directory exists, so first do a
quick check to see if we need to mkdir anything */
if (stat(dir, &st) == 0)
return 0;
if (null_strcmp(dir, mail_dir) != 0 && mail_dir != NULL &&
stat(mail_dir, &st) < 0 && (errno == ENOENT || errno == ENOTDIR)) {
/* Race condition - mail root directory doesn't exist
anymore either. We shouldn't create this directory
anymore. */
mailbox_set_deleted(box);
return -1;
}
return mailbox_mkdir(box, dir, type);
}
unsigned int mail_storage_get_lock_timeout(struct mail_storage *storage,
unsigned int secs)
{
return storage->set->mail_max_lock_timeout == 0 ? secs :
I_MIN(secs, storage->set->mail_max_lock_timeout);
}
enum mail_index_open_flags
mail_storage_settings_to_index_flags(const struct mail_storage_settings *set)
{
enum mail_index_open_flags index_flags = 0;
#ifndef MMAP_CONFLICTS_WRITE
if (set->mmap_disable)
#endif
index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
if (set->dotlock_use_excl)
index_flags |= MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL;
if (set->mail_nfs_index)
index_flags |= MAIL_INDEX_OPEN_FLAG_NFS_FLUSH;
return index_flags;
}
int mail_parse_human_timestamp(const char *str, time_t *timestamp_r,
bool *utc_r)
{
struct tm tm;
unsigned int secs;
const char *error;
if (i_isdigit(str[0]) && i_isdigit(str[1]) &&
i_isdigit(str[2]) && i_isdigit(str[3]) && str[4] == '-' &&
i_isdigit(str[5]) && i_isdigit(str[6]) && str[7] == '-' &&
i_isdigit(str[8]) && i_isdigit(str[9]) && str[10] == '\0') {
/* yyyy-mm-dd */
i_zero(&tm);
tm.tm_year = (str[0]-'0') * 1000 + (str[1]-'0') * 100 +
(str[2]-'0') * 10 + (str[3]-'0') - 1900;
tm.tm_mon = (str[5]-'0') * 10 + (str[6]-'0') - 1;
tm.tm_mday = (str[8]-'0') * 10 + (str[9]-'0');
*timestamp_r = mktime(&tm);
*utc_r = FALSE;
return 0;
} else if (imap_parse_date(str, timestamp_r)) {
/* imap date */
*utc_r = FALSE;
return 0;
} else if (str_to_time(str, timestamp_r) == 0) {
/* unix timestamp */
*utc_r = TRUE;
return 0;
} else if (settings_get_time(str, &secs, &error) == 0) {
*timestamp_r = ioloop_time - secs;
*utc_r = TRUE;
return 0;
} else {
return -1;
}
}
void mail_set_mail_cache_corrupted(struct mail *mail, const char *fmt, ...)
{
struct mail_cache_view *cache_view =
mail->transaction->cache_view;
i_assert(cache_view != NULL);
va_list va;
va_start(va, fmt);
T_BEGIN {
mail_cache_set_seq_corrupted_reason(cache_view, mail->seq,
t_strdup_printf("UID %u: %s",
mail->uid,
t_strdup_vprintf(fmt, va)));
} T_END;
va_end(va);
}
int mailbox_lock_file_create(struct mailbox *box, const char *lock_fname,
unsigned int lock_secs, struct file_lock **lock_r,
const char **error_r)
{
const struct mailbox_permissions *perm;
struct file_create_settings set;
const char *lock_path;
bool created;
perm = mailbox_get_permissions(box);
i_zero(&set);
set.lock_timeout_secs =
mail_storage_get_lock_timeout(box->storage, lock_secs);
set.lock_method = box->storage->set->parsed_lock_method;
set.mode = perm->file_create_mode;
set.gid = perm->file_create_gid;
set.gid_origin = perm->file_create_gid_origin;
if (box->list->set.volatile_dir == NULL)
lock_path = t_strdup_printf("%s/%s", box->index->dir, lock_fname);
else {
unsigned char box_name_sha1[SHA1_RESULTLEN];
string_t *str = t_str_new(128);
/* Keep this simple: Use the lock_fname with a SHA1 of the
mailbox name as the suffix. The mailbox name itself could
be too large as a filename and creating the full directory
structure would be pretty troublesome. It would also make
it more difficult to perform the automated deletion of empty
lock directories. */
str_printfa(str, "%s/%s.", box->list->set.volatile_dir,
lock_fname);
sha1_get_digest(box->name, strlen(box->name), box_name_sha1);
binary_to_hex_append(str, box_name_sha1, sizeof(box_name_sha1));
lock_path = str_c(str);
set.mkdir_mode = 0700;
}
if (file_create_locked(lock_path, &set, lock_r, &created, error_r) == -1) {
*error_r = t_strdup_printf("file_create_locked(%s) failed: %s",
lock_path, *error_r);
return errno == EAGAIN ? 0 : -1;
}
file_lock_set_close_on_free(*lock_r, TRUE);
file_lock_set_unlink_on_free(*lock_r, TRUE);
return 1;
}