mail-storage.c revision fe9459ab43300c912dc4b16b8872411337f3a25f
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "ioloop.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "llist.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "str.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "str-sanitize.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "unichar.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "istream.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "eacces-error.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mkdir-parents.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "time-util.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "var-expand.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "dsasl-client.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "imap-date.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "settings-parser.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mail-index-private.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mail-index-alloc-cache.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mailbox-tree.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mailbox-list-private.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mail-storage-private.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mail-storage-settings.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mail-namespace.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mail-search.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mail-search-register.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mailbox-search-result-private.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mailbox-guid-cache.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <ctype.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#define MAILBOX_DELETE_RETRY_SECS 30
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 255
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenextern struct mail_search_register *mail_search_register_imap;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenextern struct mail_search_register *mail_search_register_human;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct mail_module_register mail_module_register = { 0 };
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
0c17af9d3f9323136a94e66605776ed4462a172dTimo SirainenARRAY_TYPE(mail_storage) mail_storage_classes;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenvoid mail_storage_init(void)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen dsasl_clients_init();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mailbox_attributes_init();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mailbox_lists_init();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_hooks_init();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_array_init(&mail_storage_classes, 8);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenvoid mail_storage_deinit(void)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (mail_search_register_human != NULL)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_search_register_deinit(&mail_search_register_human);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (mail_search_register_imap != NULL)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_search_register_deinit(&mail_search_register_imap);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (array_is_created(&mail_storage_classes))
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen array_free(&mail_storage_classes);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_hooks_deinit();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mailbox_lists_deinit();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mailbox_attributes_deinit();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen dsasl_clients_deinit();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* append it after the list, so the autodetection order is correct */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_storage *const *classes;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int i, count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen classes = array_get(&mail_storage_classes, &count);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen for (i = 0; i < count; i++) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (classes[i] == storage_class) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen array_delete(&mail_storage_classes, i, 1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen break;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_storage *const *classes;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int i, count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(name != NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen classes = array_get(&mail_storage_classes, &count);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen for (i = 0; i < count; i++) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (strcasecmp(classes[i]->name, name) == 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return classes[i];
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct mail_storage *
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mailbox_list_settings *set)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_storage *const *classes;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int i, count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen classes = array_get(&mail_storage_classes, &count);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen for (i = 0; i < count; i++) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (classes[i]->v.autodetect != NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (classes[i]->v.autodetect(ns, set))
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return classes[i];
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *p;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen p = *data;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen while (i_isalnum(*p) || *p == '_') p++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (*p == ':' && p != *data) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* no autodetection if the storage driver is given. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *driver = t_strdup_until(*data, p);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *data = p + 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct mail_storage *
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mailbox_list_settings *list_set,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen enum mail_storage_flags flags, const char **error_r)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_storage *storage_class = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *home;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (driver == NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* no mail_location, autodetect */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else if (strcmp(driver, "auto") == 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* explicit autodetection with "auto" driver. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (list_set->root_dir != NULL &&
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *list_set->root_dir == '\0') {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* handle the same as with driver=NULL */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen list_set->root_dir = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen storage_class = mail_user_get_storage_class(ns->user, driver);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (storage_class == NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *error_r = t_strdup_printf(
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "Unknown mail storage driver %s", driver);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (list_set->root_dir == NULL || *list_set->root_dir == '\0') {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* no root directory given. is this allowed? */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const struct mailbox_list *list;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen list = list_set->layout == NULL ? NULL :
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mailbox_list_find_class(list_set->layout);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (storage_class == NULL &&
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen (flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* autodetection should take care of this */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (storage_class != NULL &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen /* root not required for this storage */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (list != NULL &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (list->props & MAILBOX_LIST_PROP_NO_ROOT) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* root not required for this layout */
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen } else {
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen *error_r = "Root mail directory not given";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen }
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (storage_class != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen storage_class->v.get_list_settings(ns, list_set);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return storage_class;
2abfef71398a61e5ed97c23a1ceb71461933ccb8Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (storage_class != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return storage_class;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)mail_user_get_home(ns->user, &home);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen *error_r = t_strdup_printf(
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen "Mail storage autodetection failed with home=%s", home);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen } else if (strncmp(ns->set->location, "auto:", 5) == 0) {
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen *error_r = t_strdup_printf(
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen "Autodetection failed for %s (home=%s)",
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen ns->set->location, home);
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen } else {
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen *error_r = t_strdup_printf(
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen "Ambiguous mail location setting, "
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen "don't know what to do with it: %s "
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen "(try prefixing it with mbox: or maildir:)",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ns->set->location);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainenstatic int
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainenmail_storage_verify_root(const char *root_dir, bool autocreate,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen const char **error_r)
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen{
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen struct stat st;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen if (stat(root_dir, &st) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* exists */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
9c7e765845357342923e16351181091028e5930fTimo Sirainen } else if (errno == EACCES) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return -1;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen } else if (errno != ENOENT && errno != ENOTDIR) {
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen return -1;
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen } else if (!autocreate) {
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen *error_r = t_strdup_printf(
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen "Root mail directory doesn't exist: %s", root_dir);
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen return -1;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen } else {
b00787191c3c31bebb939c3d00f1fcdb67356c69Timo Sirainen /* doesn't exist */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return 0;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen}
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstatic int
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainenmail_storage_create_root(struct mailbox_list *list,
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen enum mail_storage_flags flags, const char **error_r)
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen{
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen const char *root_dir, *error;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen bool autocreate;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen int ret;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_MAILBOX,
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen &root_dir)) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen /* storage doesn't use directories (e.g. shared root) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen }
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOVERIFY) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!list->mail_set->mail_debug)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* we don't need to verify, but since debugging is
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen enabled, check and log if the root doesn't exist */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (mail_storage_verify_root(root_dir, FALSE, &error) < 0) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen i_debug("Namespace %s: Creating storage despite: %s",
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen list->ns->prefix, error);
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen autocreate = (flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) == 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = mail_storage_verify_root(root_dir, autocreate, error_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret == 0) {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen ret = mailbox_list_try_mkdir_root(list, root_dir,
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX,
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen error_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret < 0 ? -1 : 0;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen}
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenmail_storage_match_class(struct mail_storage *storage,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen const struct mail_storage *storage_class,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen const struct mailbox_list_settings *set)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (strcmp(storage->name, storage_class->name) != 0)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen return FALSE;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen if ((storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0 &&
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen strcmp(storage->unique_root_dir, set->root_dir) != 0)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen return FALSE;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (strcmp(storage->name, "shared") == 0) {
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen /* allow multiple independent shared namespaces */
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen return FALSE;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen }
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen return TRUE;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen}
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainenstatic struct mail_storage *
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenmail_storage_find(struct mail_user *user,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen const struct mail_storage *storage_class,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen const struct mailbox_list_settings *set)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen{
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen struct mail_storage *storage = user->storages;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen for (; storage != NULL; storage = storage->next) {
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen if (mail_storage_match_class(storage, storage_class, set))
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen return storage;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen }
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen return NULL;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen}
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenint mail_storage_create_full(struct mail_namespace *ns, const char *driver,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen const char *data, enum mail_storage_flags flags,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct mail_storage **storage_r,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen const char **error_r)
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen{
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct mail_storage *storage_class, *storage = NULL;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct mailbox_list *list;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen struct mailbox_list_settings list_set;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen enum mailbox_list_flags list_flags = 0;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen const char *p;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen ns->mail_set->pop3_uidl_format != NULL) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen header MD5 sums stored even if we're not running POP3
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen right now. */
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen p = ns->mail_set->pop3_uidl_format;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen while ((p = strchr(p, '%')) != NULL) {
a87e5f15283e057c7dc26dd9db7b616268c95ca7Timo Sirainen if (p[1] == '%')
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen p += 2;
c93cd163f9c1d4b0ca29f49cbfdbf474caeef5bfTimo Sirainen else if (var_get_key(++p) == 'm') {
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen memset(&list_set, 0, sizeof(list_set));
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen list_set.mailbox_dir_name = "";
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen list_set.maildir_name = "";
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (data == NULL) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* autodetect */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* internal shared namespace */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen list_set.root_dir = ns->user->set->base_dir;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen } else {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (driver == NULL)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen mail_storage_set_autodetection(&data, &driver);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (mailbox_list_settings_parse(ns->user, data, &list_set,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen error_r) < 0)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return -1;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, flags,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen error_r);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen if (storage_class == NULL)
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen return -1;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen i_assert(list_set.layout != NULL);
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen if (ns->list == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* first storage for namespace */
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen if (mail_storage_is_mailbox_file(storage_class))
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_NO_MAIL_FILES;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_LIST_DELETES) != 0)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_NO_DELETES;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen list_flags, &list, error_r) < 0) {
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen *error_r = t_strdup_printf("Mailbox list driver %s: %s",
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen list_set.layout, *error_r);
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen return -1;
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) == 0) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return -1;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen if (storage != NULL) {
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen /* using an existing storage */
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen storage->refcount++;
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen mail_namespace_add_storage(ns, storage);
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen *storage_r = storage;
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen return 0;
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen }
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen storage = storage_class->v.alloc();
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen storage->refcount = 1;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen storage->storage_class = storage_class;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen storage->user = ns->user;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen storage->set = ns->mail_set;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen storage->flags = flags;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (storage->v.create != NULL &&
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen storage->v.create(storage, ns, error_r) < 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen pool_unref(&storage->pool);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return -1;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen T_BEGIN {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen hook_mail_storage_created(storage);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } T_END;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen DLLIST_PREPEND(&ns->user->storages, storage);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen mail_namespace_add_storage(ns, storage);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen *storage_r = storage;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return 0;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen enum mail_storage_flags flags, const char **error_r)
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen struct mail_storage *storage;
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return mail_storage_create_full(ns, driver, ns->set->location,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen flags, &storage, error_r);
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen}
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen{
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen struct mail_storage *storage = *_storage;
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen i_assert(storage->refcount > 0);
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen /* set *_storage=NULL only after calling destroy() callback.
7bd6001d84ecc1792ddfd54fe8efa63c509d90b1Timo Sirainen for example mdbox wants to access ns->storage */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (--storage->refcount > 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *_storage = NULL;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
9a56220167d02bbcb66a81b7553f4eb4da939945Timo Sirainen
9a56220167d02bbcb66a81b7553f4eb4da939945Timo Sirainen if (storage->mailboxes != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_panic("Trying to deinit storage without freeing mailbox %s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen storage->mailboxes->vname);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (storage->obj_refcount != 0)
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen i_panic("Trying to deinit storage before freeing its objects");
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen DLLIST_REMOVE(&storage->user->storages, storage);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen storage->v.destroy(storage);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_free(storage->error_string);
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen if (array_is_created(&storage->error_stack)) {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen i_assert(array_count(&storage->error_stack) == 0);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen array_free(&storage->error_stack);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen }
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen *_storage = NULL;
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen pool_unref(&storage->pool);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen mail_index_alloc_cache_destroy_unrefed();
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen}
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainenvoid mail_storage_obj_ref(struct mail_storage *storage)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(storage->refcount > 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (storage->obj_refcount++ == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_user_ref(storage->user);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_storage_obj_unref(struct mail_storage *storage)
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen{
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen i_assert(storage->refcount > 0);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen i_assert(storage->obj_refcount > 0);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if (--storage->obj_refcount == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_user *user = storage->user;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_user_unref(&user);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen }
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen}
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen i_free_and_null(storage->error_string);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen storage->error = MAIL_ERROR_NONE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen enum mail_error error, const char *string)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen i_free(storage->error_string);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen storage->error_string = i_strdup(string);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen storage->error = error;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen const char *str;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen str = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time);
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen i_free(storage->error_string);
eae1d6e75713d3d658908ac39b719992e2f8a456Timo Sirainen storage->error_string = i_strdup(str);
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen storage->error = MAIL_ERROR_TEMP;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen}
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen const char *fmt, ...)
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen{
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen va_list va;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen va_start(va, fmt);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("%s", t_strdup_vprintf(fmt, va));
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen va_end(va);
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* critical errors may contain sensitive data, so let user
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen see only "Internal error" with a timestamp to make it
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen easier to look from log files the actual error message. */
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen mail_storage_set_internal_error(storage);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen}
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainenvoid mail_storage_copy_error(struct mail_storage *dest,
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen struct mail_storage *src)
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen{
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen const char *str;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen enum mail_error error;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (src == dest)
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen str = mail_storage_get_last_error(src, &error);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen mail_storage_set_error(dest, error, str);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen}
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainenvoid mail_storage_copy_list_error(struct mail_storage *storage,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen struct mailbox_list *list)
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen{
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen const char *str;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen enum mail_error error;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen str = mailbox_list_get_last_error(list, &error);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen mail_storage_set_error(storage, error, str);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainenvoid mailbox_set_index_error(struct mailbox *box)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_index_is_deleted(box->index))
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen mailbox_set_deleted(box);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen else
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen mail_storage_set_internal_error(box->storage);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen mail_index_reset_error(box->index);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen}
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainenconst struct mail_storage_settings *
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenmail_storage_get_settings(struct mail_storage *storage)
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen{
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen return storage->set;
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen}
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstruct mail_user *mail_storage_get_user(struct mail_storage *storage)
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen{
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen return storage->user;
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen}
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainenvoid mail_storage_set_callbacks(struct mail_storage *storage,
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen struct mail_storage_callbacks *callbacks,
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen void *context)
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen{
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen storage->callbacks = *callbacks;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen storage->callback_context = context;
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen}
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen
7c449f545b10daa47027552f98d916a9805da662Timo Sirainenint mail_storage_purge(struct mail_storage *storage)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return storage->v.purge == NULL ? 0 :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen storage->v.purge(storage);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenconst char *mail_storage_get_last_error(struct mail_storage *storage,
7c449f545b10daa47027552f98d916a9805da662Timo Sirainen enum mail_error *error_r)
7c449f545b10daa47027552f98d916a9805da662Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* We get here only in error situations, so we have to return some
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen error. If storage->error is NONE, it means we forgot to set it at
ff4bb2dfb5714eeb0408d3bb862de1646351d097Timo Sirainen some point.. */
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainen if (storage->error == MAIL_ERROR_NONE) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (error_r != NULL)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen *error_r = MAIL_ERROR_TEMP;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return storage->error_string != NULL ? storage->error_string :
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen "BUG: Unknown internal error";
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen if (storage->error_string == NULL) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* This shouldn't happen.. */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen storage->error_string =
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_strdup_printf("BUG: Unknown 0x%x error",
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen storage->error);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (error_r != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = storage->error;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return storage->error_string;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainenconst char *mailbox_get_last_error(struct mailbox *box,
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen enum mail_error *error_r)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return mail_storage_get_last_error(box->storage, error_r);
60f9b96be55e63f0113e273dda8ba3b883c6f095Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenenum mail_error mailbox_get_last_mail_error(struct mailbox *box)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen enum mail_error error;
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen mail_storage_get_last_error(box->storage, &error);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return error;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenvoid mail_storage_last_error_push(struct mail_storage *storage)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen struct mail_storage_error *err;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
bde6382cf65fba6165dc3603f5419e194d87f404Timo Sirainen if (!array_is_created(&storage->error_stack))
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_array_init(&storage->error_stack, 2);
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen err = array_append_space(&storage->error_stack);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen err->error_string = i_strdup(storage->error_string);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen err->error = storage->error;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_storage_last_error_pop(struct mail_storage *storage)
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen unsigned int count = array_count(&storage->error_stack);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen const struct mail_storage_error *err =
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen array_idx(&storage->error_stack, count-1);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_free(storage->error_string);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen storage->error_string = err->error_string;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen storage->error = err->error;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen array_delete(&storage->error_stack, count-1, 1);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainenbool mail_storage_is_mailbox_file(struct mail_storage *storage)
60f9b96be55e63f0113e273dda8ba3b883c6f095Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return (storage->class_flags &
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE) != 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenbool mail_storage_set_error_from_errno(struct mail_storage *storage)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen const char *error_string;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen enum mail_error error;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen return FALSE;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen /* debugging is enabled - admin may be debugging a
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen (permission) problem, so return FALSE to get the caller to
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen log the full error message. */
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen return FALSE;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen }
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen mail_storage_set_error(storage, error, error_string);
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen return TRUE;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen}
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainenconst struct mailbox_settings *
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainenmailbox_settings_find(struct mail_namespace *ns, const char *vname)
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen{
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen struct mailbox_settings *const *box_set;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen if (!array_is_created(&ns->set->mailboxes))
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen return NULL;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (ns->prefix_len > 0 &&
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen strncmp(ns->prefix, vname, ns->prefix_len-1) == 0) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (vname[ns->prefix_len-1] == mail_namespace_get_sep(ns))
d22301419109ed4a38351715e6760011421dadecTimo Sirainen vname += ns->prefix_len;
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen else if (vname[ns->prefix_len-1] == '\0') {
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen /* namespace prefix itself */
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen vname = "";
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen }
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen }
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen array_foreach(&ns->set->mailboxes, box_set) {
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen if (strcmp((*box_set)->name, vname) == 0)
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen return *box_set;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen return NULL;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen}
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainenstruct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen enum mailbox_flags flags)
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen{
7c449f545b10daa47027552f98d916a9805da662Timo Sirainen struct mailbox_list *new_list = list;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen struct mail_storage *storage;
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen struct mailbox *box;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen enum mail_error open_error = 0;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen const char *errstr = NULL;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen i_assert(uni_utf8_str_is_valid(vname));
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen if (strncasecmp(vname, "INBOX", 5) == 0 &&
8d889b6d842e96ecbe7b6493920bbb6df8e0ed30Timo Sirainen strncmp(vname, "INBOX", 5) != 0) {
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen /* make sure INBOX shows up in uppercase everywhere. do this
8d889b6d842e96ecbe7b6493920bbb6df8e0ed30Timo Sirainen regardless of whether we're in inbox=yes namespace, because
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen clients expect INBOX to be case insensitive regardless of
8d889b6d842e96ecbe7b6493920bbb6df8e0ed30Timo Sirainen server's internal configuration. */
8d889b6d842e96ecbe7b6493920bbb6df8e0ed30Timo Sirainen if (vname[5] == '\0')
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen vname = "INBOX";
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen else if (vname[5] != mail_namespace_get_sep(list->ns))
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen /* not INBOX prefix */ ;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen else if (strncasecmp(list->ns->prefix, vname, 6) == 0 &&
7d7f4648f72b8c70928e04514b0d93dad0ba6fd5Timo Sirainen strncmp(list->ns->prefix, "INBOX", 5) != 0) {
7d7f4648f72b8c70928e04514b0d93dad0ba6fd5Timo Sirainen mailbox_list_set_critical(list,
7d7f4648f72b8c70928e04514b0d93dad0ba6fd5Timo Sirainen "Invalid server configuration: "
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen "Namespace prefix=%s must be uppercase INBOX",
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen list->ns->prefix);
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen open_error = MAIL_ERROR_TEMP;
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen } else {
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen vname = t_strconcat("INBOX", vname + 5, NULL);
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen }
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen }
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen T_BEGIN {
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen if (mailbox_list_get_storage(&new_list, vname, &storage) < 0) {
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen /* do a delayed failure at mailbox_open() */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen storage = mail_namespace_get_default_storage(list->ns);
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen errstr = mailbox_list_get_last_error(new_list, &open_error);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen errstr = t_strdup(errstr);
649823f9c7e42a424a8fadc427e12f3576c4f714Timo Sirainen }
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen box = storage->v.mailbox_alloc(storage, new_list, vname, flags);
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen box->set = mailbox_settings_find(new_list->ns, vname);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen box->open_error = open_error;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (open_error != 0)
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen mail_storage_set_error(storage, open_error, errstr);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hook_mailbox_allocated(box);
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen } T_END;
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen DLLIST_PREPEND(&box->storage->mailboxes, box);
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen mail_storage_obj_ref(box->storage);
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen return box;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen}
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainenstruct mailbox *mailbox_alloc_guid(struct mailbox_list *list,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen const guid_128_t guid,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen enum mailbox_flags flags)
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen{
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen struct mailbox *box = NULL;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen struct mailbox_metadata metadata;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen enum mail_error open_error = MAIL_ERROR_TEMP;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen const char *vname;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen if (mailbox_guid_cache_find(list, guid, &vname) < 0) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen vname = NULL;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen } else if (vname != NULL) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen box = mailbox_alloc(list, vname, flags);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen &metadata) < 0) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen } else if (memcmp(metadata.guid, guid,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen sizeof(metadata.guid)) != 0) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen /* GUID mismatch, refresh cache and try again */
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen mailbox_free(&box);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen mailbox_guid_cache_refresh(list);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return mailbox_alloc_guid(list, guid, flags);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen } else {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen /* successfully opened the correct mailbox */
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return box;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen }
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen i_error("mailbox_alloc_guid(%s): "
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen "Couldn't verify mailbox GUID: %s",
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen guid_128_to_string(guid),
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen mailbox_get_last_error(box, NULL));
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen vname = NULL;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen mailbox_free(&box);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen } else {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen vname = t_strdup_printf("(nonexistent mailbox with GUID=%s)",
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen guid_128_to_string(guid));
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen open_error = MAIL_ERROR_NOTFOUND;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen }
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen if (vname == NULL) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen vname = t_strdup_printf("(error in mailbox with GUID=%s)",
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen guid_128_to_string(guid));
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen }
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen box = mailbox_alloc(list, vname, flags);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen box->open_error = open_error;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return box;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen}
65d6ca3fb5450b81df0190d9e9aa62c00fed5116Timo Sirainen
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainenstatic bool mailbox_is_autocreated(struct mailbox *box)
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen{
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen if (box->inbox_user)
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen return TRUE;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen return box->set != NULL &&
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen strcmp(box->set->autocreate, MAILBOX_SET_AUTO_NO) != 0;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen}
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainenstatic int mailbox_autocreate(struct mailbox *box)
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen{
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen const char *errstr;
649823f9c7e42a424a8fadc427e12f3576c4f714Timo Sirainen enum mail_error error;
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen if (mailbox_create(box, NULL, FALSE) < 0) {
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen errstr = mailbox_get_last_error(box, &error);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (error != MAIL_ERROR_EXISTS) {
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen mail_storage_set_critical(box->storage,
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen "Failed to autocreate mailbox %s: %s",
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen box->vname, errstr);
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return -1;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen }
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen } else if (box->set != NULL &&
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen strcmp(box->set->autocreate,
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen MAILBOX_SET_AUTO_SUBSCRIBE) == 0) {
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen if (mailbox_set_subscribed(box, TRUE) < 0) {
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen mail_storage_set_critical(box->storage,
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen "Failed to autosubscribe to mailbox %s: %s",
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen box->vname, mailbox_get_last_error(box, NULL));
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return -1;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen }
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen }
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return 0;
305465bb1a4c5d90c4b4e2c2790eb05fa4ebc41eTimo Sirainen}
305465bb1a4c5d90c4b4e2c2790eb05fa4ebc41eTimo Sirainen
305465bb1a4c5d90c4b4e2c2790eb05fa4ebc41eTimo Sirainenstatic int mailbox_autocreate_and_reopen(struct mailbox *box)
305465bb1a4c5d90c4b4e2c2790eb05fa4ebc41eTimo Sirainen{
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen int ret;
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (mailbox_autocreate(box) < 0)
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return -1;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen mailbox_close(box);
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen ret = box->v.open(box);
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen if (ret < 0 && box->inbox_user &&
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen !box->storage->user->inbox_open_error_logged) {
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen box->storage->user->inbox_open_error_logged = TRUE;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen mail_storage_set_critical(box->storage,
73c76fa7340a107229c530196d026aadeae979c7Timo Sirainen "Opening INBOX failed: %s",
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen mailbox_get_last_error(box, NULL));
9c7e765845357342923e16351181091028e5930fTimo Sirainen }
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen return ret;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen}
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainenstatic bool
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenmailbox_name_verify_separators(const char *vname, char sep,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const char **error_r)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen unsigned int i;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen bool prev_sep = FALSE;
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen /* Make sure the vname is correct: non-empty, doesn't begin or end
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen with separator and no adjacent separators */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen for (i = 0; vname[i] != '\0'; i++) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (vname[i] == sep) {
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen if (prev_sep) {
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen *error_r = "Has adjacent hierarchy separators";
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen prev_sep = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen prev_sep = FALSE;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (prev_sep && i > 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *error_r = "Ends with hierarchy separator";
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen return FALSE;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int mailbox_verify_name(struct mailbox *box)
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen{
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen struct mail_namespace *ns = box->list->ns;
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen const char *error, *vname = box->vname;
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen char list_sep, ns_sep;
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen if (box->inbox_user) {
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen /* this is INBOX - don't bother with further checks */
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen return 0;
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen list_sep = mailbox_list_get_hierarchy_sep(box->list);
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen ns_sep = mail_namespace_get_sep(ns);
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen if (ns->prefix_len > 0) {
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen /* vname is either "namespace/box" or "namespace" */
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen if (strncmp(vname, ns->prefix, ns->prefix_len-1) != 0 ||
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen (vname[ns->prefix_len-1] != '\0' &&
65d6ca3fb5450b81df0190d9e9aa62c00fed5116Timo Sirainen vname[ns->prefix_len-1] != ns->prefix[ns->prefix_len-1])) {
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainen /* User input shouldn't normally be able to get us in
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen here. The main reason this isn't an assert is to
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen allow any input at all to mailbox_verify_*_name()
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen without crashing. */
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
65d6ca3fb5450b81df0190d9e9aa62c00fed5116Timo Sirainen t_strdup_printf("Invalid mailbox name '%s': "
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen "Missing namespace prefix '%s'",
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen str_sanitize(vname, 80), ns->prefix));
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen return -1;
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen }
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen vname += ns->prefix_len - 1;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen if (vname[0] != '\0') {
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen i_assert(vname[0] == ns->prefix[ns->prefix_len-1]);
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen vname++;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen if (vname[0] == '\0') {
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen /* "namespace/" isn't a valid mailbox name. */
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen mail_storage_set_error(box->storage,
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen MAIL_ERROR_PARAMS,
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen "Invalid mailbox name");
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen return -1;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen if (ns_sep != list_sep && box->list->set.escape_char == '\0' &&
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen strchr(vname, list_sep) != NULL) {
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, t_strdup_printf(
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen "Character not allowed in mailbox name: '%c'", list_sep));
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen return -1;
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen }
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen if (vname[0] == ns_sep &&
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen !box->storage->set->mail_full_filesystem_access) {
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen "Invalid mailbox name: Begins with hierarchy separator");
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen return -1;
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen }
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen if (!mailbox_name_verify_separators(vname, ns_sep, &error) ||
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen !mailbox_list_is_valid_name(box->list, box->name, &error)) {
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen t_strdup_printf("Invalid mailbox name: %s", error));
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen return -1;
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen }
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen return 0;
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen}
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainenstatic int mailbox_verify_existing_name(struct mailbox *box)
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen{
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen const char *path;
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen if (box->opened)
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen return 0;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mailbox_verify_name(box) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Make sure box->_path is set, so mailbox_get_path() works from
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen now on. Note that this may also fail with some backends if the
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen mailbox doesn't exist. */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX, &path) < 0) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (box->storage->error != MAIL_ERROR_NOTFOUND ||
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen !mailbox_is_autocreated(box))
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen return -1;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen /* if this is an autocreated mailbox, create it now */
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen if (mailbox_autocreate(box) < 0)
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen return -1;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen mailbox_close(box);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen &path) < 0)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return -1;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen return 0;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen}
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool mailbox_name_has_control_chars(const char *name)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen const char *p;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (p = name; *p != '\0'; p++) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if ((unsigned char)*p < ' ')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
82c70897a2d0e6144ecc56ca8e0eb9fff768f2c5Timo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenvoid mailbox_skip_create_name_restrictions(struct mailbox *box, bool set)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen box->skip_create_name_restrictions = set;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen}
82c70897a2d0e6144ecc56ca8e0eb9fff768f2c5Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainenint mailbox_verify_create_name(struct mailbox *box)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen{
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* mailbox_alloc() already checks that vname is valid UTF8,
82c70897a2d0e6144ecc56ca8e0eb9fff768f2c5Timo Sirainen so we don't need to verify that.
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen check vname instead of storage name, because vname is what is
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen visible to users, while storage name may be a fixed length GUID. */
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainen if (mailbox_verify_name(box) < 0)
d67ac5f76cc02c227f4997878bb4aef48ee298faTimo Sirainen return -1;
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen if (box->skip_create_name_restrictions)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return 0;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen if (mailbox_name_has_control_chars(box->vname)) {
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen "Control characters not allowed in new mailbox names");
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strlen(box->vname) > MAILBOX_LIST_NAME_MAX_LENGTH) {
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen "Mailbox name too long");
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return -1;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen /* check individual component names, too */
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen const char *old_name = box->name;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen const char *name;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen const char sep = mailbox_list_get_hierarchy_sep(box->list);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen while((name = strchr(old_name, sep)) != NULL) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (name - old_name > MAILBOX_MAX_HIERARCHY_NAME_LENGTH) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen "Mailbox name too long");
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return -1;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen name++;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen old_name = name;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (strlen(old_name) > MAILBOX_MAX_HIERARCHY_NAME_LENGTH) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen "Mailbox name too long");
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return -1;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return 0;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen}
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainenstatic bool have_listable_namespace_prefix(struct mail_namespace *ns,
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen const char *name)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int name_len = strlen(name);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen for (; ns != NULL; ns = ns->next) {
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen continue;
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (ns->prefix_len <= name_len)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen continue;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* if prefix has multiple hierarchies, match
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen any of the hierarchies */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (strncmp(ns->prefix, name, name_len) == 0 &&
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen ns->prefix[name_len] == mail_namespace_get_sep(ns))
7c449f545b10daa47027552f98d916a9805da662Timo Sirainen return TRUE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen return FALSE;
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen}
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen
int mailbox_exists(struct mailbox *box, bool auto_boxes,
enum mailbox_existence *existence_r)
{
switch (box->open_error) {
case 0:
break;
case MAIL_ERROR_NOTFOUND:
*existence_r = MAILBOX_EXISTENCE_NONE;
return 0;
default:
/* unsure if this exists or not */
return -1;
}
if (mailbox_verify_name(box) < 0) {
/* the mailbox name is invalid. we don't know if it currently
exists or not, but since it can never be accessed in any way
report it as if it didn't exist. */
*existence_r = MAILBOX_EXISTENCE_NONE;
return 0;
}
if (auto_boxes && mailbox_is_autocreated(box)) {
*existence_r = MAILBOX_EXISTENCE_SELECT;
return 0;
}
if (box->v.exists(box, auto_boxes, existence_r) < 0)
return -1;
if (!box->inbox_user && *existence_r == MAILBOX_EXISTENCE_NOSELECT &&
have_listable_namespace_prefix(box->storage->user->namespaces,
box->vname)) {
/* listable namespace prefix always exists. */
*existence_r = MAILBOX_EXISTENCE_NOSELECT;
return 0;
}
/* if this is a shared namespace with only INBOX and
mail_shared_explicit_inbox=no, we'll need to mark the namespace as
usable here since nothing else will. */
box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
return 0;
}
static int ATTR_NULL(2)
mailbox_open_full(struct mailbox *box, struct istream *input)
{
int ret;
if (box->opened)
return 0;
switch (box->open_error) {
case 0:
break;
case MAIL_ERROR_NOTFOUND:
mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
return -1;
default:
mail_storage_set_internal_error(box->storage);
box->storage->error = box->open_error;
return -1;
}
if (mailbox_verify_existing_name(box) < 0)
return -1;
if (input != NULL) {
if ((box->storage->class_flags &
MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) == 0) {
mail_storage_set_critical(box->storage,
"Storage doesn't support streamed mailboxes");
return -1;
}
box->input = input;
box->flags |= MAILBOX_FLAG_READONLY;
i_stream_ref(box->input);
}
T_BEGIN {
ret = box->v.open(box);
} T_END;
if (ret < 0 && box->storage->error == MAIL_ERROR_NOTFOUND &&
box->input == NULL && mailbox_is_autocreated(box)) T_BEGIN {
ret = mailbox_autocreate_and_reopen(box);
} T_END;
if (ret < 0) {
if (box->input != NULL)
i_stream_unref(&box->input);
return -1;
}
box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
return 0;
}
static bool mailbox_try_undelete(struct mailbox *box)
{
time_t mtime;
if ((box->flags & MAILBOX_FLAG_READONLY) != 0) {
/* most importantly we don't do this because we want to avoid
a loop: mdbox storage rebuild -> mailbox_open() ->
mailbox_mark_index_deleted() -> mailbox_sync() ->
mdbox storage rebuild. */
return FALSE;
}
if (mail_index_get_modification_time(box->index, &mtime) < 0)
return FALSE;
if (mtime + MAILBOX_DELETE_RETRY_SECS > time(NULL))
return FALSE;
if (mailbox_mark_index_deleted(box, FALSE) < 0)
return FALSE;
box->mailbox_deleted = FALSE;
return TRUE;
}
int mailbox_open(struct mailbox *box)
{
if (mailbox_open_full(box, NULL) < 0) {
if (!box->mailbox_deleted)
return -1;
/* mailbox has been marked as deleted. if this deletion
started (and crashed) a long time ago, it can be confusing
to user that the mailbox can't be opened. so we'll just
undelete it and reopen. */
if(!mailbox_try_undelete(box))
return -1;
if (mailbox_open_full(box, NULL) < 0)
return -1;
}
return 0;
}
static int mailbox_alloc_index_pvt(struct mailbox *box)
{
const char *index_dir;
int ret;
if (box->index_pvt != NULL)
return 1;
ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE,
&index_dir);
if (ret <= 0)
return ret; /* error / no private indexes */
if (mailbox_create_missing_dir(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE) < 0)
return -1;
box->index_pvt = mail_index_alloc_cache_get(NULL, index_dir,
t_strconcat(box->index_prefix, ".pvt", NULL));
mail_index_set_fsync_mode(box->index_pvt,
box->storage->set->parsed_fsync_mode, 0);
mail_index_set_lock_method(box->index_pvt,
box->storage->set->parsed_lock_method,
mail_storage_get_lock_timeout(box->storage, UINT_MAX));
return 1;
}
int mailbox_open_index_pvt(struct mailbox *box)
{
enum mail_index_open_flags index_flags;
int ret;
if (box->view_pvt != NULL)
return 1;
if (mailbox_get_private_flags_mask(box) == 0)
return 0;
if ((ret = mailbox_alloc_index_pvt(box)) <= 0)
return ret;
index_flags = MAIL_INDEX_OPEN_FLAG_CREATE |
mail_storage_settings_to_index_flags(box->storage->set);
if ((box->flags & MAILBOX_FLAG_SAVEONLY) != 0)
index_flags |= MAIL_INDEX_OPEN_FLAG_SAVEONLY;
if (mail_index_open(box->index_pvt, index_flags) < 0)
return -1;
box->view_pvt = mail_index_view_open(box->index_pvt);
return 1;
}
int mailbox_open_stream(struct mailbox *box, struct istream *input)
{
return mailbox_open_full(box, input);
}
int mailbox_enable(struct mailbox *box, enum mailbox_feature features)
{
if (mailbox_verify_name(box) < 0)
return -1;
return box->v.enable(box, features);
}
enum mailbox_feature mailbox_get_enabled_features(struct mailbox *box)
{
return box->enabled_features;
}
void mail_storage_free_binary_cache(struct mail_storage *storage)
{
if (storage->binary_cache.box == NULL)
return;
timeout_remove(&storage->binary_cache.to);
i_stream_destroy(&storage->binary_cache.input);
memset(&storage->binary_cache, 0, sizeof(storage->binary_cache));
}
void mailbox_close(struct mailbox *box)
{
if (!box->opened)
return;
if (box->transaction_count != 0) {
i_panic("Trying to close mailbox %s with open transactions",
box->name);
}
box->v.close(box);
if (box->storage->binary_cache.box == box)
mail_storage_free_binary_cache(box->storage);
box->opened = FALSE;
box->mailbox_deleted = FALSE;
array_clear(&box->search_results);
if (array_is_created(&box->recent_flags))
array_free(&box->recent_flags);
box->recent_flags_prev_uid = 0;
box->recent_flags_count = 0;
}
void mailbox_free(struct mailbox **_box)
{
struct mailbox *box = *_box;
*_box = NULL;
mailbox_close(box);
box->v.free(box);
DLLIST_REMOVE(&box->storage->mailboxes, box);
mail_storage_obj_unref(box->storage);
if (box->metadata_pool != NULL)
pool_unref(&box->metadata_pool);
pool_unref(&box->pool);
}
bool mailbox_equals(const struct mailbox *box1,
const struct mail_namespace *ns2, const char *vname2)
{
struct mail_namespace *ns1 = mailbox_get_namespace(box1);
const char *name1;
if (ns1 != ns2)
return FALSE;
name1 = mailbox_get_vname(box1);
if (strcmp(name1, vname2) == 0)
return TRUE;
return strcasecmp(name1, "INBOX") == 0 &&
strcasecmp(vname2, "INBOX") == 0;
}
bool mailbox_is_any_inbox(struct mailbox *box)
{
return box->inbox_any;
}
int mailbox_create(struct mailbox *box, const struct mailbox_update *update,
bool directory)
{
int ret;
if (mailbox_verify_create_name(box) < 0)
return -1;
box->creating = TRUE;
ret = box->v.create_box(box, update, directory);
box->creating = FALSE;
if (ret == 0)
box->list->guid_cache_updated = TRUE;
return ret;
}
int mailbox_update(struct mailbox *box, const struct mailbox_update *update)
{
int ret;
i_assert(update->min_next_uid == 0 ||
update->min_first_recent_uid == 0 ||
update->min_first_recent_uid <= update->min_next_uid);
if (mailbox_verify_existing_name(box) < 0)
return -1;
ret = box->v.update_box(box, update);
if (!guid_128_is_empty(update->mailbox_guid))
box->list->guid_cache_invalidated = TRUE;
return ret;
}
int mailbox_mark_index_deleted(struct mailbox *box, bool del)
{
struct mail_index_transaction *trans;
enum mail_index_transaction_flags trans_flags = 0;
enum mailbox_flags old_flag;
int ret;
if (box->marked_deleted && del) {
/* we already marked it deleted. this allows plugins to
"lock" the deletion earlier. */
return 0;
}
old_flag = box->flags & MAILBOX_FLAG_OPEN_DELETED;
box->flags |= MAILBOX_FLAG_OPEN_DELETED;
ret = mailbox_open(box);
box->flags = (box->flags & ~MAILBOX_FLAG_OPEN_DELETED) | old_flag;
if (ret < 0)
return -1;
trans_flags = del ? 0 : MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL;
trans = mail_index_transaction_begin(box->view, trans_flags);
if (del)
mail_index_set_deleted(trans);
else
mail_index_set_undeleted(trans);
if (mail_index_transaction_commit(&trans) < 0) {
mailbox_set_index_error(box);
return -1;
}
/* sync the mailbox. this finishes the index deletion and it can
succeed only for a single session. we do it here, so the rest of
the deletion code doesn't have to worry about race conditions. */
box->delete_sync_check = TRUE;
ret = mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ);
box->delete_sync_check = FALSE;
if (ret < 0)
return -1;
box->marked_deleted = del;
return 0;
}
static void mailbox_close_reset_path(struct mailbox *box)
{
memset(&box->_perm, 0, sizeof(box->_perm));
box->_path = NULL;
box->_index_path = NULL;
}
int mailbox_delete(struct mailbox *box)
{
int ret;
if (*box->name == '\0') {
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
"Storage root can't be deleted");
return -1;
}
box->deleting = TRUE;
if (mailbox_open(box) < 0) {
if (mailbox_get_last_mail_error(box) != MAIL_ERROR_NOTFOUND &&
!box->mailbox_deleted)
return -1;
/* \noselect mailbox */
}
ret = box->v.delete_box(box);
if (ret < 0 && box->marked_deleted) {
/* deletion failed. revert the mark so it can maybe be
tried again later. */
if (mailbox_mark_index_deleted(box, FALSE) < 0)
return -1;
}
box->deleting = FALSE;
mailbox_close(box);
/* if mailbox is reopened, its path may be different with
LAYOUT=index */
mailbox_close_reset_path(box);
return ret;
}
int mailbox_delete_empty(struct mailbox *box)
{
int ret;
/* FIXME: should be a parameter to delete(), but since it changes API
don't do it for now */
box->deleting_must_be_empty = TRUE;
ret = mailbox_delete(box);
box->deleting_must_be_empty = FALSE;
return ret;
}
static bool
mail_storages_rename_compatible(struct mail_storage *storage1,
struct mail_storage *storage2,
const char **error_r)
{
if (storage1 == storage2)
return TRUE;
if (strcmp(storage1->name, storage2->name) != 0) {
*error_r = t_strdup_printf("storage %s != %s",
storage1->name, storage2->name);
return FALSE;
}
if ((storage1->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0) {
/* e.g. mdbox where all mails are in storage/ directory and
they can't be easily moved from there. */
*error_r = t_strdup_printf("storage %s uses unique root",
storage1->name);
return FALSE;
}
return TRUE;
}
static bool nullequals(const void *p1, const void *p2)
{
return (p1 == NULL && p2 == NULL) || (p1 != NULL && p2 != NULL);
}
static bool
mailbox_lists_rename_compatible(struct mailbox_list *list1,
struct mailbox_list *list2,
const char **error_r)
{
if (!nullequals(list1->set.alt_dir, list2->set.alt_dir)) {
*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)
{
memset(status_r, 0, sizeof(*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 ((items & STATUS_HIGHESTMODSEQ) != 0)
mailbox_enable(box, MAILBOX_FEATURE_CONDSTORE);
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 ((items & STATUS_HIGHESTMODSEQ) != 0)
mailbox_enable(box, MAILBOX_FEATURE_CONDSTORE);
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)
{
memset(metadata_r, 0, sizeof(*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);
}
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)
{
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;
memset(status_r, 0, sizeof(*status_r));
ret = box->v.sync_deinit(ctx, status_r);
if (ret < 0 && box->inbox_user &&
!box->storage->user->inbox_open_error_logged) {
errormsg = mailbox_get_last_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)
{
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(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--;
}
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;
}
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;
return ctx;
}
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;
}
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)
{
ctx->dest_mail = 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 (!(*ctx)->copying_via_save)
(*ctx)->saving = TRUE;
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;
}
int mailbox_save_finish(struct mail_save_context **_ctx)
{
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;
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);
i_assert(!ctx->unfinished);
ctx->saving = FALSE;
return ret;
}
void mailbox_save_cancel(struct mail_save_context **_ctx)
{
struct mail_save_context *ctx = *_ctx;
struct mail_keywords *keywords = ctx->data.keywords;
struct mail_private *mail;
*_ctx = NULL;
T_BEGIN {
ctx->transaction->box->v.save_cancel(ctx);
} T_END;
if (keywords != NULL && !ctx->finishing)
mailbox_keywords_unref(&keywords);
if (ctx->dest_mail != NULL) {
/* 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 */
mail = (struct mail_private *)ctx->dest_mail;
mail->v.close(&mail->mail);
}
i_assert(!ctx->unfinished);
ctx->saving = FALSE;
}
struct mailbox_transaction_context *
mailbox_save_get_transaction(struct mail_save_context *ctx)
{
return ctx->transaction;
}
int mailbox_copy(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;
}
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->copying_via_save = FALSE;
ctx->saving = FALSE;
return ret;
}
int mailbox_move(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
int ret;
i_assert(!ctx->moving);
ctx->moving = TRUE;
if ((ret = mailbox_copy(_ctx, mail)) == 0)
mail_expunge(mail);
ctx->moving = FALSE;
return ret;
}
int mailbox_save_using_mail(struct mail_save_context **ctx, struct mail *mail)
{
(*ctx)->saving = TRUE;
return mailbox_copy(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;
}
int mailbox_get_path_to(struct mailbox *box, enum mailbox_list_path_type type,
const char **path_r)
{
int ret;
if (type == MAILBOX_LIST_PATH_TYPE_MAILBOX && box->_path != NULL) {
if (box->_path[0] == '\0') {
*path_r = NULL;
return 0;
}
*path_r = box->_path;
return 1;
}
if (type == MAILBOX_LIST_PATH_TYPE_INDEX && box->_index_path != NULL) {
if (box->_index_path[0] == '\0') {
*path_r = NULL;
return 0;
}
*path_r = box->_index_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 (type == MAILBOX_LIST_PATH_TYPE_MAILBOX && box->_path == NULL)
box->_path = ret == 0 ? "" : p_strdup(box->pool, *path_r);
if (type == MAILBOX_LIST_PATH_TYPE_INDEX && box->_index_path == NULL)
box->_index_path = ret == 0 ? "" : p_strdup(box->pool, *path_r);
return ret;
}
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;
}
mailbox_list_get_permissions(box->list, box->name, &box->_perm);
box->_perm.file_create_gid_origin =
p_strdup(box->pool, box->_perm.file_create_gid_origin);
}
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)
{
memset(&box->_perm, 0, sizeof(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) {
if ((box->list->props & MAILBOX_LIST_PROP_AUTOCREATE_DIRS) == 0)
return 0;
/* the directory might not have been created yet */
}
/* 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;
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)
{
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 */
memset(&tm, 0, sizeof(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);
return 0;
} else if (imap_parse_date(str, timestamp_r)) {
/* imap date */
return 0;
} else if (str_to_time(str, timestamp_r) == 0) {
/* unix timestamp */
return 0;
} else if (settings_get_time(str, &secs, &error) == 0) {
*timestamp_r = ioloop_time - secs;
return 0;
} else {
return -1;
}
}