mail-storage.c revision a62e12ba4afefb302ef87faf6173aef012c3b5d6
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "lib.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "ioloop.h"
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include "array.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "llist.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "str.h"
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#include "str-sanitize.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "sha1.h"
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#include "unichar.h"
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen#include "hex-binary.h"
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#include "file-create-locked.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "istream.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "eacces-error.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mkdir-parents.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "time-util.h"
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include "var-expand.h"
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include "dsasl-client.h"
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include "imap-date.h"
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include "settings-parser.h"
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include "mail-index-private.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mail-index-alloc-cache.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mailbox-tree.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mailbox-list-private.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mail-storage-private.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mail-storage-settings.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mail-namespace.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mail-search.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mail-search-register.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mail-search-mime-register.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mailbox-search-result-private.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mailbox-guid-cache.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mail-cache.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include <ctype.h>
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#define MAILBOX_DELETE_RETRY_SECS 30
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 255
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenextern struct mail_search_register *mail_search_register_imap;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenextern struct mail_search_register *mail_search_register_human;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct mail_module_register mail_module_register = { 0 };
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo SirainenARRAY_TYPE(mail_storage) mail_storage_classes;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int mail_storage_init_refcount = 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mail_storage_init(void)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mail_storage_init_refcount++ > 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dsasl_clients_init();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_attributes_init();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_lists_init();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_storage_hooks_init();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_array_init(&mail_storage_classes, 8);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_storage_register_all();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_list_register_all();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mail_storage_deinit(void)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen{
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen i_assert(mail_storage_init_refcount > 0);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (--mail_storage_init_refcount > 0)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mail_search_register_human != NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_search_register_deinit(&mail_search_register_human);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mail_search_register_imap != NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_search_register_deinit(&mail_search_register_imap);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_search_mime_register_deinit();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (array_is_created(&mail_storage_classes))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_free(&mail_storage_classes);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_hooks_deinit();
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mailbox_lists_deinit();
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen mailbox_attributes_deinit();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dsasl_clients_deinit();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* append it after the list, so the autodetection order is correct */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_storage *const *classes;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int i, count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen classes = array_get(&mail_storage_classes, &count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (i = 0; i < count; i++) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (classes[i] == storage_class) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen array_delete(&mail_storage_classes, i, 1);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen break;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_storage *const *classes;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unsigned int i, count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(name != NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen classes = array_get(&mail_storage_classes, &count);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen for (i = 0; i < count; i++) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (strcasecmp(classes[i]->name, name) == 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return classes[i];
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return NULL;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic struct mail_storage *
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen struct mailbox_list_settings *set)
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct mail_storage *const *classes;
7a24bdc1a5e2d5368c2569b4852192f2bdb5a31fTimo Sirainen unsigned int i, count;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
7a24bdc1a5e2d5368c2569b4852192f2bdb5a31fTimo Sirainen classes = array_get(&mail_storage_classes, &count);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen for (i = 0; i < count; i++) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (classes[i]->v.autodetect != NULL) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (classes[i]->v.autodetect(ns, set))
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return classes[i];
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen }
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen }
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return NULL;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen}
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenstatic void
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen{
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen const char *p;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen p = *data;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen while (i_isalnum(*p) || *p == '_') p++;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (*p == ':' && p != *data) {
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen /* no autodetection if the storage driver is given. */
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen *driver = t_strdup_until(*data, p);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen *data = p + 1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic struct mail_storage *
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct mailbox_list_settings *list_set,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen enum mail_storage_flags flags, const char **error_r)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct mail_storage *storage_class = NULL;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const char *home;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (driver == NULL) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* no mail_location, autodetect */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else if (strcmp(driver, "auto") == 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* explicit autodetection with "auto" driver. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (list_set->root_dir != NULL &&
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *list_set->root_dir == '\0') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* handle the same as with driver=NULL */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen list_set->root_dir = NULL;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else {
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen storage_class = mail_user_get_storage_class(ns->user, driver);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (storage_class == NULL) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = t_strdup_printf(
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen "Unknown mail storage driver %s", driver);
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen return NULL;
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (list_set->root_dir == NULL || *list_set->root_dir == '\0') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* no root directory given. is this allowed? */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct mailbox_list *list;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen list = list_set->layout == NULL ? NULL :
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen mailbox_list_find_class(list_set->layout);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (storage_class == NULL &&
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen (flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0) {
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen /* autodetection should take care of this */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen } else if (storage_class != NULL &&
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen (storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* root not required for this storage */
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen } else if (list != NULL &&
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen (list->props & MAILBOX_LIST_PROP_NO_ROOT) != 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* root not required for this layout */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = "Root mail directory not given";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return NULL;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (storage_class != NULL) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen storage_class->v.get_list_settings(ns, list_set);
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen return storage_class;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (storage_class != NULL)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return storage_class;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen (void)mail_user_get_home(ns->user, &home);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen *error_r = t_strdup_printf(
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen "Mail storage autodetection failed with home=%s", home);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else if (strncmp(ns->set->location, "auto:", 5) == 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = t_strdup_printf(
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen "Autodetection failed for %s (home=%s)",
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ns->set->location, home);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = t_strdup_printf(
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen "Ambiguous mail location setting, "
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen "don't know what to do with it: %s "
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen "(try prefixing it with mbox: or maildir:)",
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen ns->set->location);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return NULL;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenstatic int
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenmail_storage_verify_root(const char *root_dir, const char *dir_type,
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen bool autocreate, const char **error_r)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct stat st;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen if (stat(root_dir, &st) == 0) {
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen /* exists */
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen if (S_ISDIR(st.st_mode))
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = t_strdup_printf(
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen "Root mail directory is a file: %s", root_dir);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else if (errno == EACCES) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen return -1;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen } else if (errno != ENOENT) {
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen } else if (!autocreate) {
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen *error_r = t_strdup_printf(
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen "Root %s directory doesn't exist: %s", dir_type, root_dir);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* doesn't exist */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenmail_storage_create_root(struct mailbox_list *list,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen enum mail_storage_flags flags, const char **error_r)
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const char *root_dir, *type_name, *error;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen enum mailbox_list_path_type type;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen bool autocreate;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen int ret;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (list->set.iter_from_index_dir) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen type = MAILBOX_LIST_PATH_TYPE_INDEX;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen type_name = "index";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen type = MAILBOX_LIST_PATH_TYPE_MAILBOX;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen type_name = "mail";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (!mailbox_list_get_root_path(list, type, &root_dir)) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* storage doesn't use directories (e.g. shared root) */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOVERIFY) != 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (!list->mail_set->mail_debug)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* we don't need to verify, but since debugging is
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen enabled, check and log if the root doesn't exist */
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen if (mail_storage_verify_root(root_dir, type_name, FALSE, &error) < 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_debug("Namespace %s: Creating storage despite: %s",
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen list->ns->prefix, error);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen autocreate = (flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) == 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ret = mail_storage_verify_root(root_dir, type_name, autocreate, error_r);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ret == 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const char *mail_root_dir;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (!list->set.iter_from_index_dir)
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen mail_root_dir = root_dir;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen else if (!mailbox_list_get_root_path(list,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX, &mail_root_dir))
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_unreached();
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ret = mailbox_list_try_mkdir_root(list, mail_root_dir,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen error_r);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ret == 0 && list->set.iter_from_index_dir) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ret = mailbox_list_try_mkdir_root(list, root_dir,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen MAILBOX_LIST_PATH_TYPE_INDEX,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen error_r);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return ret < 0 ? -1 : 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic bool
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenmail_storage_match_class(struct mail_storage *storage,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct mail_storage *storage_class,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct mailbox_list_settings *set)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (strcmp(storage->name, storage_class->name) != 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return FALSE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if ((storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0 &&
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen strcmp(storage->unique_root_dir,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen (set->root_dir != NULL ? set->root_dir : "")) != 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return FALSE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (strcmp(storage->name, "shared") == 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* allow multiple independent shared namespaces */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return FALSE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return TRUE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainenstatic struct mail_storage *
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainenmail_storage_find(struct mail_user *user,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct mail_storage *storage_class,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct mailbox_list_settings *set)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_storage *storage = user->storages;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (; storage != NULL; storage = storage->next) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mail_storage_match_class(storage, storage_class, set))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return storage;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mail_storage_create_full(struct mail_namespace *ns, const char *driver,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *data, enum mail_storage_flags flags,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_storage **storage_r,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char **error_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_storage *storage_class, *storage = NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_list *list;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_list_settings list_set;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen enum mailbox_list_flags list_flags = 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *p;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ns->mail_set->pop3_uidl_format != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen header MD5 sums stored even if we're not running POP3
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen right now. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p = ns->mail_set->pop3_uidl_format;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen while ((p = strchr(p, '%')) != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (p[1] == '%')
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p += 2;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (var_get_key(++p) == 'm') {
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen break;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen }
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen }
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen }
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen mailbox_list_settings_init_defaults(&list_set);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (data == NULL) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* autodetect */
42270b2d8d9bb0d04b16e0ead727154b32399a3fTimo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
42270b2d8d9bb0d04b16e0ead727154b32399a3fTimo Sirainen /* internal shared namespace */
42270b2d8d9bb0d04b16e0ead727154b32399a3fTimo Sirainen list_set.root_dir = ns->user->set->base_dir;
42270b2d8d9bb0d04b16e0ead727154b32399a3fTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (driver == NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_storage_set_autodetection(&data, &driver);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mailbox_list_settings_parse(ns->user, data, &list_set,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen error_r) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, flags,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen error_r);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (storage_class == NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(list_set.layout != NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ns->list == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* first storage for namespace */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mail_storage_is_mailbox_file(storage_class))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list_flags |= MAILBOX_LIST_FLAG_NO_MAIL_FILES;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_LIST_DELETES) != 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list_flags |= MAILBOX_LIST_FLAG_NO_DELETES;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list_flags, &list, error_r) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = t_strdup_printf("Mailbox list driver %s: %s",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list_set.layout, *error_r);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
4182d8cd818e76856a5a1e25b343fe5ddf69fd8eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (storage != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* using an existing storage */
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen storage->refcount++;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_namespace_add_storage(ns, storage);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *storage_r = storage;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen storage = storage_class->v.alloc();
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen storage->refcount = 1;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen storage->storage_class = storage_class;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen storage->user = ns->user;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen storage->set = ns->mail_set;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen storage->flags = flags;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (storage->v.create != NULL &&
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen storage->v.create(storage, ns, error_r) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen pool_unref(&storage->pool);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen T_BEGIN {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen hook_mail_storage_created(storage);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } T_END;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen DLLIST_PREPEND(&ns->user->storages, storage);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_namespace_add_storage(ns, storage);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *storage_r = storage;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen enum mail_storage_flags flags, const char **error_r)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct mail_storage *storage;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return mail_storage_create_full(ns, driver, ns->set->location,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen flags, &storage, error_r);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_storage *storage = *_storage;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(storage->refcount > 0);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* set *_storage=NULL only after calling destroy() callback.
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for example mdbox wants to access ns->storage */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (--storage->refcount > 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *_storage = NULL;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (storage->mailboxes != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_panic("Trying to deinit storage without freeing mailbox %s",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen storage->mailboxes->vname);
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen }
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen if (storage->obj_refcount != 0)
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen i_panic("Trying to deinit storage before freeing its objects");
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen DLLIST_REMOVE(&storage->user->storages, storage);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen storage->v.destroy(storage);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_free(storage->last_internal_error);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_free(storage->error_string);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (array_is_created(&storage->error_stack)) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(array_count(&storage->error_stack) == 0);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen array_free(&storage->error_stack);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *_storage = NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen pool_unref(&storage->pool);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_index_alloc_cache_destroy_unrefed();
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mail_storage_obj_ref(struct mail_storage *storage)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(storage->refcount > 0);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (storage->obj_refcount++ == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_user_ref(storage->user);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen}
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenvoid mail_storage_obj_unref(struct mail_storage *storage)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(storage->refcount > 0);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(storage->obj_refcount > 0);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (--storage->obj_refcount == 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct mail_user *user = storage->user;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_user_unref(&user);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen i_free_and_null(storage->error_string);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_free(storage->last_internal_error);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen storage->last_error_is_internal = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen storage->error = MAIL_ERROR_NONE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen enum mail_error error, const char *string)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (storage->error_string != string) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_free(storage->error_string);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen storage->error_string = i_strdup(string);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen storage->last_error_is_internal = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen storage->error = error;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *str;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_free(storage->error_string);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen storage->error_string = i_strdup(str);
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen storage->error = MAIL_ERROR_TEMP;
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen const char *fmt, ...)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen char *old_error = storage->last_internal_error;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen va_list va;
fb7dd075cf883e5e7defbc0c8fb8326e30bdccdeTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen va_start(va, fmt);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen storage->last_internal_error = i_strdup_vprintf(fmt, va);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen va_end(va);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen storage->last_error_is_internal = TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_error("%s", storage->last_internal_error);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* free the old_error only after the new error is generated, because
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen the old_error may be one of the parameters. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_free(old_error);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* critical errors may contain sensitive data, so let user
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen see only "Internal error" with a timestamp to make it
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen easier to look from log files the actual error message. */
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen mail_storage_set_internal_error(storage);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainenconst char *mail_storage_get_last_internal_error(struct mail_storage *storage,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen enum mail_error *error_r)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (error_r != NULL)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *error_r = storage->error;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen if (storage->last_error_is_internal) {
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen i_assert(storage->last_internal_error != NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return storage->last_internal_error;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen return mail_storage_get_last_error(storage, error_r);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen}
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenconst char *mailbox_get_last_internal_error(struct mailbox *box,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen enum mail_error *error_r)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return mail_storage_get_last_internal_error(mailbox_get_storage(box),
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen error_r);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen}
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainenvoid mail_storage_copy_error(struct mail_storage *dest,
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen struct mail_storage *src)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *str;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen enum mail_error error;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (src == dest)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen str = mail_storage_get_last_error(src, &error);
41955c400476941fa274f18b106a5922866fd780Timo Sirainen mail_storage_set_error(dest, error, str);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainenvoid mail_storage_copy_list_error(struct mail_storage *storage,
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen struct mailbox_list *list)
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen{
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen const char *str;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen enum mail_error error;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
d516e6848ecfbc7381abe9414fd8011fdf9d8c95Timo Sirainen str = mailbox_list_get_last_error(list, &error);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen mail_storage_set_error(storage, error, str);
d516e6848ecfbc7381abe9414fd8011fdf9d8c95Timo Sirainen}
d516e6848ecfbc7381abe9414fd8011fdf9d8c95Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid mailbox_set_index_error(struct mailbox *box)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (mail_index_is_deleted(box->index))
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mailbox_set_deleted(box);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen else
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen mail_storage_set_internal_error(box->storage);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen mail_index_reset_error(box->index);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen}
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenconst struct mail_storage_settings *
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenmail_storage_get_settings(struct mail_storage *storage)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen{
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return storage->set;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenstruct mail_user *mail_storage_get_user(struct mail_storage *storage)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen return storage->user;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenvoid mail_storage_set_callbacks(struct mail_storage *storage,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct mail_storage_callbacks *callbacks,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen void *context)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen storage->callbacks = *callbacks;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen storage->callback_context = context;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenint mail_storage_purge(struct mail_storage *storage)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return storage->v.purge == NULL ? 0 :
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen storage->v.purge(storage);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenconst char *mail_storage_get_last_error(struct mail_storage *storage,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen enum mail_error *error_r)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen{
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* We get here only in error situations, so we have to return some
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen error. If storage->error is NONE, it means we forgot to set it at
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen some point.. */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (storage->error == MAIL_ERROR_NONE) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (error_r != NULL)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen *error_r = MAIL_ERROR_TEMP;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return storage->error_string != NULL ? storage->error_string :
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen "BUG: Unknown internal error";
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen }
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (storage->error_string == NULL) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* This shouldn't happen.. */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen storage->error_string =
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen i_strdup_printf("BUG: Unknown 0x%x error",
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen storage->error);
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen }
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (error_r != NULL)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen *error_r = storage->error;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return storage->error_string;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen}
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainenconst char *mailbox_get_last_error(struct mailbox *box,
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen enum mail_error *error_r)
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen{
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen return mail_storage_get_last_error(box->storage, error_r);
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen}
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenenum mail_error mailbox_get_last_mail_error(struct mailbox *box)
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen{
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen enum mail_error error;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen mail_storage_get_last_error(box->storage, &error);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return error;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenvoid mail_storage_last_error_push(struct mail_storage *storage)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen{
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen struct mail_storage_error *err;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (!array_is_created(&storage->error_stack))
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen i_array_init(&storage->error_stack, 2);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen err = array_append_space(&storage->error_stack);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen err->error_string = i_strdup(storage->error_string);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen err->error = storage->error;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen err->last_error_is_internal = storage->last_error_is_internal;
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainen if (err->last_error_is_internal)
3b1dd975d0c543d76679593f86e136d43bf40635Timo Sirainen err->last_internal_error = i_strdup(storage->last_internal_error);
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainen}
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenvoid mail_storage_last_error_pop(struct mail_storage *storage)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen{
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen unsigned int count = array_count(&storage->error_stack);
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen const struct mail_storage_error *err =
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen array_idx(&storage->error_stack, count-1);
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen i_free(storage->error_string);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen i_free(storage->last_internal_error);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen storage->error_string = err->error_string;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen storage->error = err->error;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen storage->last_error_is_internal = err->last_error_is_internal;
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainen storage->last_internal_error = err->last_internal_error;
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainen array_delete(&storage->error_stack, count-1, 1);
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainen}
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainenbool mail_storage_is_mailbox_file(struct mail_storage *storage)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen{
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return (storage->class_flags &
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE) != 0;
3b1dd975d0c543d76679593f86e136d43bf40635Timo Sirainen}
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainen
3b1dd975d0c543d76679593f86e136d43bf40635Timo Sirainenbool mail_storage_set_error_from_errno(struct mail_storage *storage)
3b1dd975d0c543d76679593f86e136d43bf40635Timo Sirainen{
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen const char *error_string;
3b1dd975d0c543d76679593f86e136d43bf40635Timo Sirainen enum mail_error error;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
3b1dd975d0c543d76679593f86e136d43bf40635Timo Sirainen return FALSE;
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainen if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* debugging is enabled - admin may be debugging a
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen (permission) problem, so return FALSE to get the caller to
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen log the full error message. */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return FALSE;
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainen }
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen mail_storage_set_error(storage, error, error_string);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return TRUE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen}
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenconst struct mailbox_settings *
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenmailbox_settings_find(struct mail_namespace *ns, const char *vname)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen{
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen struct mailbox_settings *const *box_set;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen if (!array_is_created(&ns->set->mailboxes))
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen return NULL;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen if (ns->prefix_len > 0 &&
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen strncmp(ns->prefix, vname, ns->prefix_len-1) == 0) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (vname[ns->prefix_len-1] == mail_namespace_get_sep(ns))
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen vname += ns->prefix_len;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen else if (vname[ns->prefix_len-1] == '\0') {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* namespace prefix itself */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen vname = "";
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen array_foreach(&ns->set->mailboxes, box_set) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (strcmp((*box_set)->name, vname) == 0)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return *box_set;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return NULL;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenstruct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen enum mailbox_flags flags)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct mailbox_list *new_list = list;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct mail_storage *storage;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen struct mailbox *box;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen enum mail_error open_error = 0;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen const char *errstr = NULL;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen i_assert(uni_utf8_str_is_valid(vname));
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (strncasecmp(vname, "INBOX", 5) == 0 &&
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen strncmp(vname, "INBOX", 5) != 0) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* make sure INBOX shows up in uppercase everywhere. do this
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen regardless of whether we're in inbox=yes namespace, because
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen clients expect INBOX to be case insensitive regardless of
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen server's internal configuration. */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (vname[5] == '\0')
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen vname = "INBOX";
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen else if (vname[5] != mail_namespace_get_sep(list->ns))
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* not INBOX prefix */ ;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen else if (strncasecmp(list->ns->prefix, vname, 6) == 0 &&
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen strncmp(list->ns->prefix, "INBOX", 5) != 0) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mailbox_list_set_critical(list,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Invalid server configuration: "
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Namespace prefix=%s must be uppercase INBOX",
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen list->ns->prefix);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen open_error = MAIL_ERROR_TEMP;
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen } else {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen vname = t_strconcat("INBOX", vname + 5, NULL);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen T_BEGIN {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (mailbox_list_get_storage(&new_list, vname, &storage) < 0) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* do a delayed failure at mailbox_open() */
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen storage = mail_namespace_get_default_storage(list->ns);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen errstr = mailbox_list_get_last_error(new_list, &open_error);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen errstr = t_strdup(errstr);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen box = storage->v.mailbox_alloc(storage, new_list, vname, flags);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen box->set = mailbox_settings_find(new_list->ns, vname);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen box->open_error = open_error;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (open_error != 0)
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen mail_storage_set_error(storage, open_error, errstr);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen hook_mailbox_allocated(box);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen } T_END;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen DLLIST_PREPEND(&box->storage->mailboxes, box);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mail_storage_obj_ref(box->storage);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return box;
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen}
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainenstruct mailbox *mailbox_alloc_guid(struct mailbox_list *list,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen const guid_128_t guid,
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen enum mailbox_flags flags)
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct mailbox *box = NULL;
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen struct mailbox_metadata metadata;
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen enum mail_error open_error = MAIL_ERROR_TEMP;
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen const char *vname;
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen if (mailbox_guid_cache_find(list, guid, &vname) < 0) {
280b771b7ec7e49caa399540dfe8faf42999a1adTimo Sirainen vname = NULL;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen } else if (vname != NULL) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen box = mailbox_alloc(list, vname, flags);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen &metadata) < 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen } else if (memcmp(metadata.guid, guid,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen sizeof(metadata.guid)) != 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* GUID mismatch, refresh cache and try again */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mailbox_free(&box);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mailbox_guid_cache_refresh(list);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return mailbox_alloc_guid(list, guid, flags);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen } else {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* successfully opened the correct mailbox */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return box;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_error("mailbox_alloc_guid(%s): "
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Couldn't verify mailbox GUID: %s",
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen guid_128_to_string(guid),
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mailbox_get_last_internal_error(box, NULL));
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen vname = NULL;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mailbox_free(&box);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen } else {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen vname = t_strdup_printf("(nonexistent mailbox with GUID=%s)",
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen guid_128_to_string(guid));
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen open_error = MAIL_ERROR_NOTFOUND;
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (vname == NULL) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen vname = t_strdup_printf("(error in mailbox with GUID=%s)",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen guid_128_to_string(guid));
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box = mailbox_alloc(list, vname, flags);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->open_error = open_error;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return box;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid mailbox_set_reason(struct mailbox *box, const char *reason)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(reason != NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->reason = p_strdup(box->pool, reason);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenbool mailbox_is_autocreated(struct mailbox *box)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (box->inbox_user)
41955c400476941fa274f18b106a5922866fd780Timo Sirainen return TRUE;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen return box->set != NULL &&
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen strcmp(box->set->autocreate, MAILBOX_SET_AUTO_NO) != 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int mailbox_autocreate(struct mailbox *box)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *errstr;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen enum mail_error error;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (mailbox_create(box, NULL, FALSE) < 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen errstr = mailbox_get_last_internal_error(box, &error);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (error != MAIL_ERROR_EXISTS) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_set_critical(box->storage,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Failed to autocreate mailbox %s: %s",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->vname, errstr);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen } else if (box->set != NULL &&
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen strcmp(box->set->autocreate,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen MAILBOX_SET_AUTO_SUBSCRIBE) == 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (mailbox_set_subscribed(box, TRUE) < 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_set_critical(box->storage,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Failed to autosubscribe to mailbox %s: %s",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->vname,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mailbox_get_last_internal_error(box, NULL));
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainenstatic int mailbox_autocreate_and_reopen(struct mailbox *box)
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen{
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen int ret;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen if (mailbox_autocreate(box) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mailbox_close(box);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ret = box->v.open(box);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ret < 0 && box->inbox_user &&
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen !box->storage->user->inbox_open_error_logged) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->storage->user->inbox_open_error_logged = TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_set_critical(box->storage,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Opening INBOX failed: %s",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mailbox_get_last_internal_error(box, NULL));
41955c400476941fa274f18b106a5922866fd780Timo Sirainen }
41955c400476941fa274f18b106a5922866fd780Timo Sirainen return ret;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen}
41955c400476941fa274f18b106a5922866fd780Timo Sirainen
41955c400476941fa274f18b106a5922866fd780Timo Sirainenstatic bool
41955c400476941fa274f18b106a5922866fd780Timo Sirainenmailbox_name_verify_separators(const char *vname, char sep,
41955c400476941fa274f18b106a5922866fd780Timo Sirainen const char **error_r)
41955c400476941fa274f18b106a5922866fd780Timo Sirainen{
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen unsigned int i;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen bool prev_sep = FALSE;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen
41955c400476941fa274f18b106a5922866fd780Timo Sirainen /* Make sure the vname is correct: non-empty, doesn't begin or end
41955c400476941fa274f18b106a5922866fd780Timo Sirainen with separator and no adjacent separators */
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen for (i = 0; vname[i] != '\0'; i++) {
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen if (vname[i] == sep) {
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen if (prev_sep) {
41955c400476941fa274f18b106a5922866fd780Timo Sirainen *error_r = "Has adjacent hierarchy separators";
41955c400476941fa274f18b106a5922866fd780Timo Sirainen return FALSE;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen }
41955c400476941fa274f18b106a5922866fd780Timo Sirainen prev_sep = TRUE;
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen } else {
41955c400476941fa274f18b106a5922866fd780Timo Sirainen prev_sep = FALSE;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen }
41955c400476941fa274f18b106a5922866fd780Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (prev_sep && i > 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *error_r = "Ends with hierarchy separator";
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
2584e86cc2d8c31ba30a4109cf4ba09d1e37e28aTimo Sirainenstatic int mailbox_verify_name(struct mailbox *box)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
41955c400476941fa274f18b106a5922866fd780Timo Sirainen struct mail_namespace *ns = box->list->ns;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *error, *vname = box->vname;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen char list_sep, ns_sep;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (box->inbox_user) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* this is INBOX - don't bother with further checks */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen list_sep = mailbox_list_get_hierarchy_sep(box->list);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ns_sep = mail_namespace_get_sep(ns);
41955c400476941fa274f18b106a5922866fd780Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ns->prefix_len > 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* vname is either "namespace/box" or "namespace" */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (strncmp(vname, ns->prefix, ns->prefix_len-1) != 0 ||
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen (vname[ns->prefix_len-1] != '\0' &&
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen vname[ns->prefix_len-1] != ns->prefix[ns->prefix_len-1])) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* User input shouldn't normally be able to get us in
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen here. The main reason this isn't an assert is to
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen allow any input at all to mailbox_verify_*_name()
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen without crashing. */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen t_strdup_printf("Invalid mailbox name '%s': "
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Missing namespace prefix '%s'",
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen str_sanitize(vname, 80), ns->prefix));
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return -1;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen vname += ns->prefix_len - 1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (vname[0] != '\0') {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(vname[0] == ns->prefix[ns->prefix_len-1]);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen vname++;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (vname[0] == '\0') {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* "namespace/" isn't a valid mailbox name. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_set_error(box->storage,
2584e86cc2d8c31ba30a4109cf4ba09d1e37e28aTimo Sirainen MAIL_ERROR_PARAMS,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Invalid mailbox name");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ns_sep != list_sep && box->list->set.escape_char == '\0' &&
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen strchr(vname, list_sep) != NULL) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, t_strdup_printf(
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen "Character not allowed in mailbox name: '%c'", list_sep));
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (vname[0] == ns_sep &&
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen !box->storage->set->mail_full_filesystem_access) {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen "Invalid mailbox name: Begins with hierarchy separator");
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen return -1;
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen }
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (!mailbox_name_verify_separators(vname, ns_sep, &error) ||
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen !mailbox_list_is_valid_name(box->list, box->name, &error)) {
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen t_strdup_printf("Invalid mailbox name: %s", error));
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainenstatic int mailbox_verify_existing_name(struct mailbox *box)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const char *path;
5b486fdbf2077a994337dc8bd4477ec51d5daf4eTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (box->opened)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (mailbox_verify_name(box) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen /* Make sure box->_path is set, so mailbox_get_path() works from
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen now on. Note that this may also fail with some backends if the
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen mailbox doesn't exist. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX, &path) < 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (box->storage->error != MAIL_ERROR_NOTFOUND ||
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen !mailbox_is_autocreated(box))
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* if this is an autocreated mailbox, create it now */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (mailbox_autocreate(box) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen mailbox_close(box);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen &path) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic bool mailbox_name_has_control_chars(const char *name)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *p;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen for (p = name; *p != '\0'; p++) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if ((unsigned char)*p < ' ')
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainenvoid mailbox_skip_create_name_restrictions(struct mailbox *box, bool set)
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen{
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen box->skip_create_name_restrictions = set;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen}
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainenint mailbox_verify_create_name(struct mailbox *box)
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen{
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen /* mailbox_alloc() already checks that vname is valid UTF8,
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen so we don't need to verify that.
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen check vname instead of storage name, because vname is what is
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen visible to users, while storage name may be a fixed length GUID. */
a385399497bdb50d4dfce729ffc852b75ed46a36Timo Sirainen if (mailbox_verify_name(box) < 0)
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (box->skip_create_name_restrictions)
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen return 0;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen if (mailbox_name_has_control_chars(box->vname)) {
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Control characters not allowed in new mailbox names");
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen return -1;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen }
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen if (strlen(box->vname) > MAILBOX_LIST_NAME_MAX_LENGTH) {
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen "Mailbox name too long");
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen return -1;
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen }
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen /* check individual component names, too */
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen const char *old_name = box->name;
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen const char *name;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen const char sep = mailbox_list_get_hierarchy_sep(box->list);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen while((name = strchr(old_name, sep)) != NULL) {
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen if (name - old_name > MAILBOX_MAX_HIERARCHY_NAME_LENGTH) {
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen "Mailbox name too long");
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen return -1;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen }
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen name++;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen old_name = name;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (strlen(old_name) > MAILBOX_MAX_HIERARCHY_NAME_LENGTH) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen "Mailbox name too long");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenstatic bool have_listable_namespace_prefix(struct mail_namespace *ns,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const char *name)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen size_t name_len = strlen(name);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen for (; ns != NULL; ns = ns->next) {
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen continue;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ns->prefix_len <= name_len)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen continue;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* if prefix has multiple hierarchies, match
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen any of the hierarchies */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (strncmp(ns->prefix, name, name_len) == 0 &&
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ns->prefix[name_len] == mail_namespace_get_sep(ns))
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenint mailbox_exists(struct mailbox *box, bool auto_boxes,
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen enum mailbox_existence *existence_r)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen switch (box->open_error) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen case 0:
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen break;
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen case MAIL_ERROR_NOTFOUND:
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *existence_r = MAILBOX_EXISTENCE_NONE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen default:
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen /* unsure if this exists or not */
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (mailbox_verify_name(box) < 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* the mailbox name is invalid. we don't know if it currently
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen exists or not, but since it can never be accessed in any way
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen report it as if it didn't exist. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *existence_r = MAILBOX_EXISTENCE_NONE;
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (auto_boxes && mailbox_is_autocreated(box)) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *existence_r = MAILBOX_EXISTENCE_SELECT;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (box->v.exists(box, auto_boxes, existence_r) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (!box->inbox_user && *existence_r == MAILBOX_EXISTENCE_NOSELECT &&
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen have_listable_namespace_prefix(box->storage->user->namespaces,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->vname)) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* listable namespace prefix always exists. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *existence_r = MAILBOX_EXISTENCE_NOSELECT;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen }
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* if this is a shared namespace with only INBOX and
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_shared_explicit_inbox=no, we'll need to mark the namespace as
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen usable here since nothing else will. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int ATTR_NULL(2)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenmailbox_open_full(struct mailbox *box, struct istream *input)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen int ret;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (box->opened)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (box->storage->set->mail_debug && box->reason != NULL) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_debug("%s: Mailbox opened because: %s",
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen box->vname, box->reason);
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen }
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen switch (box->open_error) {
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen case 0:
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen break;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen case MAIL_ERROR_NOTFOUND:
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen default:
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_set_internal_error(box->storage);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->storage->error = box->open_error;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (mailbox_verify_existing_name(box) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (input != NULL) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if ((box->storage->class_flags &
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) == 0) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen mail_storage_set_critical(box->storage,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Storage doesn't support streamed mailboxes");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->input = input;
2b9fd042e701cfe7d79c4294a5ab401d6ec9ce18Timo Sirainen box->flags |= MAILBOX_FLAG_READONLY;
2b9fd042e701cfe7d79c4294a5ab401d6ec9ce18Timo Sirainen i_stream_ref(box->input);
2b9fd042e701cfe7d79c4294a5ab401d6ec9ce18Timo Sirainen }
2b9fd042e701cfe7d79c4294a5ab401d6ec9ce18Timo Sirainen
2b9fd042e701cfe7d79c4294a5ab401d6ec9ce18Timo Sirainen T_BEGIN {
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen ret = box->v.open(box);
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen } T_END;
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen if (ret < 0 && box->storage->error == MAIL_ERROR_NOTFOUND &&
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen !box->deleting &&
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen box->input == NULL && mailbox_is_autocreated(box)) T_BEGIN {
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen ret = mailbox_autocreate_and_reopen(box);
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen } T_END;
2b9fd042e701cfe7d79c4294a5ab401d6ec9ce18Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ret < 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (box->input != NULL)
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen i_stream_unref(&box->input);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic bool mailbox_try_undelete(struct mailbox *box)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen time_t mtime;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(!box->mailbox_undeleting);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if ((box->flags & MAILBOX_FLAG_READONLY) != 0) {
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen /* most importantly we don't do this because we want to avoid
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen a loop: mdbox storage rebuild -> mailbox_open() ->
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mailbox_mark_index_deleted() -> mailbox_sync() ->
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mdbox storage rebuild. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (mail_index_get_modification_time(box->index, &mtime) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (mtime + MAILBOX_DELETE_RETRY_SECS > time(NULL))
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->mailbox_undeleting = TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen int ret = mailbox_mark_index_deleted(box, FALSE);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->mailbox_undeleting = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ret < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->mailbox_deleted = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenint mailbox_open(struct mailbox *box)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* check that the storage supports stubs if require them */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (((box->flags & MAILBOX_FLAG_USE_STUBS) != 0) &&
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ((box->storage->storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_STUBS) == 0)) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Mailbox does not support mail stubs");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (mailbox_open_full(box, NULL) < 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (!box->mailbox_deleted || box->mailbox_undeleting)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* mailbox has been marked as deleted. if this deletion
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen started (and crashed) a long time ago, it can be confusing
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen to user that the mailbox can't be opened. so we'll just
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen undelete it and reopen. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if(!mailbox_try_undelete(box))
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* make sure we close the mailbox in the middle. some backends
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen may not have fully opened the mailbox while it was being
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen undeleted. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mailbox_close(box);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (mailbox_open_full(box, NULL) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int mailbox_alloc_index_pvt(struct mailbox *box)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *index_dir;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen int ret;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (box->index_pvt != NULL)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 1;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen
e5601cd11edce275b4c423523bd00ee3e4eeae42Timo Sirainen ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE,
e5601cd11edce275b4c423523bd00ee3e4eeae42Timo Sirainen &index_dir);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ret <= 0)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return ret; /* error / no private indexes */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (mailbox_create_missing_dir(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE) < 0)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen box->index_pvt = mail_index_alloc_cache_get(NULL, index_dir,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen t_strconcat(box->index_prefix, ".pvt", NULL));
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_index_set_fsync_mode(box->index_pvt,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->storage->set->parsed_fsync_mode, 0);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_index_set_lock_method(box->index_pvt,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->storage->set->parsed_lock_method,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_get_lock_timeout(box->storage, UINT_MAX));
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenint mailbox_open_index_pvt(struct mailbox *box)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen enum mail_index_open_flags index_flags;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen int ret;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
7ab62198bfb9ac210b11ea7a147234e0f72f6448Timo Sirainen if (box->view_pvt != NULL)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (mailbox_get_private_flags_mask(box) == 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if ((ret = mailbox_alloc_index_pvt(box)) <= 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return ret;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen index_flags = MAIL_INDEX_OPEN_FLAG_CREATE |
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mail_storage_settings_to_index_flags(box->storage->set);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if ((box->flags & MAILBOX_FLAG_SAVEONLY) != 0)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen index_flags |= MAIL_INDEX_OPEN_FLAG_SAVEONLY;
e5601cd11edce275b4c423523bd00ee3e4eeae42Timo Sirainen if (mail_index_open(box->index_pvt, index_flags) < 0)
e5601cd11edce275b4c423523bd00ee3e4eeae42Timo Sirainen return -1;
e5601cd11edce275b4c423523bd00ee3e4eeae42Timo Sirainen box->view_pvt = mail_index_view_open(box->index_pvt);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenint mailbox_open_stream(struct mailbox *box, struct istream *input)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return mailbox_open_full(box, input);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenint mailbox_enable(struct mailbox *box, enum mailbox_feature features)
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen{
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen if (mailbox_verify_name(box) < 0)
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return box->v.enable(box, features);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen}
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenenum mailbox_feature mailbox_get_enabled_features(struct mailbox *box)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return box->enabled_features;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenvoid mail_storage_free_binary_cache(struct mail_storage *storage)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (storage->binary_cache.box == NULL)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen timeout_remove(&storage->binary_cache.to);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen i_stream_destroy(&storage->binary_cache.input);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen i_zero(&storage->binary_cache);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenvoid mailbox_close(struct mailbox *box)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (!box->opened)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (box->transaction_count != 0) {
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen i_panic("Trying to close mailbox %s with open transactions",
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen box->name);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen box->v.close(box);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (box->storage->binary_cache.box == box)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mail_storage_free_binary_cache(box->storage);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen box->opened = FALSE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen box->mailbox_deleted = FALSE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen array_clear(&box->search_results);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (array_is_created(&box->recent_flags))
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen array_free(&box->recent_flags);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen box->recent_flags_prev_uid = 0;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen box->recent_flags_count = 0;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenvoid mailbox_free(struct mailbox **_box)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct mailbox *box = *_box;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen *_box = NULL;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen mailbox_close(box);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen box->v.free(box);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen DLLIST_REMOVE(&box->storage->mailboxes, box);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mail_storage_obj_unref(box->storage);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (box->metadata_pool != NULL)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen pool_unref(&box->metadata_pool);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen pool_unref(&box->pool);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenbool mailbox_equals(const struct mailbox *box1,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen const struct mail_namespace *ns2, const char *vname2)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct mail_namespace *ns1 = mailbox_get_namespace(box1);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen const char *name1;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (ns1 != ns2)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return FALSE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen name1 = mailbox_get_vname(box1);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (strcmp(name1, vname2) == 0)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return TRUE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return strcasecmp(name1, "INBOX") == 0 &&
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen strcasecmp(vname2, "INBOX") == 0;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenbool mailbox_is_any_inbox(struct mailbox *box)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return box->inbox_any;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainenstatic void mailbox_copy_cache_decisions_from_inbox(struct mailbox *box)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct mail_namespace *ns =
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mail_namespace_find_inbox(box->storage->user->namespaces);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct mailbox *inbox =
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mailbox_alloc(ns->list, "INBOX", MAILBOX_FLAG_READONLY);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen enum mailbox_existence existence;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* this should be NoSelect but since inbox can never be
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen NoSelect we use EXISTENCE_NONE to avoid creating inbox by accident */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mailbox_set_reason(inbox, "copy caching decisions");
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (mailbox_exists(inbox, FALSE, &existence) == 0 &&
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen existence != MAILBOX_EXISTENCE_NONE &&
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen mailbox_open(inbox) == 0 &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_open(box) == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_index_transaction *dit =
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_index_transaction_begin(box->view,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen mail_cache_decisions_copy(dit, inbox->cache, box->cache);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* we can't do much about errors here */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen (void)mail_index_transaction_commit(&dit);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen mailbox_free(&inbox);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen}
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
942302b0247403645394d848b3c620ead262a2a5Timo Sirainenint mailbox_create(struct mailbox *box, const struct mailbox_update *update,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen bool directory)
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen int ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (mailbox_verify_create_name(box) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->creating = TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ret = box->v.create_box(box, update, directory);
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen box->creating = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ret == 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen box->list->guid_cache_updated = TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (!box->inbox_any)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_copy_cache_decisions_from_inbox(box);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else if (box->opened) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* Creation failed after (partially) opening the mailbox.
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen It may not be in a valid state, so close it. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_storage_last_error_push(box->storage);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_close(box);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_storage_last_error_pop(box->storage);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return ret;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mailbox_update(struct mailbox *box, const struct mailbox_update *update)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(update->min_next_uid == 0 ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen update->min_first_recent_uid == 0 ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen update->min_first_recent_uid <= update->min_next_uid);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mailbox_verify_existing_name(box) < 0)
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ret = box->v.update_box(box, update);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!guid_128_is_empty(update->mailbox_guid))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen box->list->guid_cache_invalidated = TRUE;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen return ret;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen}
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainenint mailbox_mark_index_deleted(struct mailbox *box, bool del)
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen{
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen struct mail_index_transaction *trans;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen enum mail_index_transaction_flags trans_flags = 0;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen enum mailbox_flags old_flag;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen int ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (box->marked_deleted && del) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* we already marked it deleted. this allows plugins to
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen "lock" the deletion earlier. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen old_flag = box->flags & MAILBOX_FLAG_OPEN_DELETED;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen box->flags |= MAILBOX_FLAG_OPEN_DELETED;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ret = mailbox_open(box);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen box->flags = (box->flags & ~MAILBOX_FLAG_OPEN_DELETED) | old_flag;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ret < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen trans_flags = del ? 0 : MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen trans = mail_index_transaction_begin(box->view, trans_flags);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (del)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_index_set_deleted(trans);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_index_set_undeleted(trans);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mail_index_transaction_commit(&trans) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_set_index_error(box);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (del) {
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen /* sync the mailbox. this finishes the index deletion and it
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen can succeed only for a single session. we do it here, so the
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen rest of the deletion code doesn't have to worry about race
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen conditions. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen box->delete_sync_check = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ret = mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen box->delete_sync_check = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ret < 0)
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen box->marked_deleted = del;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen}
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenstatic void mailbox_close_reset_path(struct mailbox *box)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_zero(&box->_perm);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen box->_path = NULL;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen box->_index_path = NULL;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenint mailbox_delete(struct mailbox *box)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int ret;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (*box->name == '\0') {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "Storage root can't be deleted");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen box->deleting = TRUE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (mailbox_open(box) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mailbox_get_last_mail_error(box) != MAIL_ERROR_NOTFOUND &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen !box->mailbox_deleted)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return -1;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* might be a \noselect mailbox, so continue deletion */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ret = box->v.delete_box(box);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (ret < 0 && box->marked_deleted) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* deletion failed. revert the mark so it can maybe be
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen tried again later. */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (mailbox_mark_index_deleted(box, FALSE) < 0)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return -1;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
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)
{
i_zero(status_r);
if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUIDS) != 0)
status_r->have_guids = TRUE;
if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_SAVE_GUIDS) != 0)
status_r->have_save_guids = TRUE;
if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUID128) != 0)
status_r->have_only_guid128 = TRUE;
}
int mailbox_get_status(struct mailbox *box,
enum mailbox_status_items items,
struct mailbox_status *status_r)
{
mailbox_get_status_set_defaults(box, status_r);
if (mailbox_verify_existing_name(box) < 0)
return -1;
if (box->v.get_status(box, items, status_r) < 0)
return -1;
i_assert(status_r->have_guids || !status_r->have_save_guids);
return 0;
}
void mailbox_get_open_status(struct mailbox *box,
enum mailbox_status_items items,
struct mailbox_status *status_r)
{
i_assert(box->opened);
i_assert((items & MAILBOX_STATUS_FAILING_ITEMS) == 0);
mailbox_get_status_set_defaults(box, status_r);
if (box->v.get_status(box, items, status_r) < 0)
i_unreached();
}
int mailbox_get_metadata(struct mailbox *box, enum mailbox_metadata_items items,
struct mailbox_metadata *metadata_r)
{
i_zero(metadata_r);
if (mailbox_verify_existing_name(box) < 0)
return -1;
if (box->metadata_pool != NULL)
p_clear(box->metadata_pool);
if (box->v.get_metadata(box, items, metadata_r) < 0)
return -1;
i_assert((items & MAILBOX_METADATA_GUID) == 0 ||
!guid_128_is_empty(metadata_r->guid));
return 0;
}
enum mail_flags mailbox_get_private_flags_mask(struct mailbox *box)
{
if (box->v.get_private_flags_mask != NULL)
return box->v.get_private_flags_mask(box);
else if (box->list->set.index_pvt_dir != NULL)
return MAIL_SEEN; /* FIXME */
else
return 0;
}
struct mailbox_sync_context *
mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct mailbox_sync_context *ctx;
if (box->transaction_count != 0) {
i_panic("Trying to sync mailbox %s with open transactions",
box->name);
}
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;
i_zero(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_internal_error(box, &error);
if (error == MAIL_ERROR_NOTPOSSIBLE) {
box->storage->user->inbox_open_error_logged = TRUE;
i_error("Syncing INBOX failed: %s", errormsg);
}
}
if (ret == 0)
box->synced = TRUE;
return ret;
}
int mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct mailbox_sync_context *ctx;
struct mailbox_sync_status status;
if (array_count(&box->search_results) == 0) {
/* we don't care about mailbox's current state, so we might
as well fix inconsistency state */
flags |= MAILBOX_SYNC_FLAG_FIX_INCONSISTENT;
}
ctx = mailbox_sync_init(box, flags);
return mailbox_sync_deinit(&ctx, &status);
}
#undef mailbox_notify_changes
void mailbox_notify_changes(struct mailbox *box,
mailbox_notify_callback_t *callback, void *context)
{
i_assert(box->opened);
box->notify_callback = callback;
box->notify_context = context;
box->v.notify_changes(box);
}
void mailbox_notify_changes_stop(struct mailbox *box)
{
i_assert(box->opened);
box->notify_callback = NULL;
box->notify_context = NULL;
box->v.notify_changes(box);
}
struct mail_search_context *
mailbox_search_init(struct mailbox_transaction_context *t,
struct mail_search_args *args,
const enum mail_sort_type *sort_program,
enum mail_fetch_field wanted_fields,
struct mailbox_header_lookup_ctx *wanted_headers)
{
i_assert(wanted_headers == NULL || wanted_headers->box == t->box);
mail_search_args_ref(args);
if (!args->simplified)
mail_search_args_simplify(args);
return t->box->v.search_init(t, args, sort_program,
wanted_fields, wanted_headers);
}
int mailbox_search_deinit(struct mail_search_context **_ctx)
{
struct mail_search_context *ctx = *_ctx;
struct mail_search_args *args = ctx->args;
int ret;
*_ctx = NULL;
mailbox_search_results_initial_done(ctx);
ret = ctx->transaction->box->v.search_deinit(ctx);
mail_search_args_unref(&args);
return ret;
}
bool mailbox_search_next(struct mail_search_context *ctx, struct mail **mail_r)
{
bool tryagain;
while (!mailbox_search_next_nonblock(ctx, mail_r, &tryagain)) {
if (!tryagain)
return FALSE;
}
return TRUE;
}
bool mailbox_search_next_nonblock(struct mail_search_context *ctx,
struct mail **mail_r, bool *tryagain_r)
{
struct mailbox *box = ctx->transaction->box;
*mail_r = NULL;
*tryagain_r = FALSE;
if (!box->v.search_next_nonblock(ctx, mail_r, tryagain_r))
return FALSE;
else {
mailbox_search_results_add(ctx, (*mail_r)->uid);
return TRUE;
}
}
bool mailbox_search_seen_lost_data(struct mail_search_context *ctx)
{
return ctx->seen_lost_data;
}
int mailbox_search_result_build(struct mailbox_transaction_context *t,
struct mail_search_args *args,
enum mailbox_search_result_flags flags,
struct mail_search_result **result_r)
{
struct mail_search_context *ctx;
struct mail *mail;
int ret;
ctx = mailbox_search_init(t, args, NULL, 0, NULL);
*result_r = mailbox_search_result_save(ctx, flags);
while (mailbox_search_next(ctx, &mail)) ;
ret = mailbox_search_deinit(&ctx);
if (ret < 0)
mailbox_search_result_free(result_r);
return ret;
}
struct mailbox_transaction_context *
mailbox_transaction_begin(struct mailbox *box,
enum mailbox_transaction_flags flags)
{
struct mailbox_transaction_context *trans;
i_assert((flags & MAILBOX_TRANSACTION_FLAG_FILL_IN_STUB) == 0 ||
(box->flags & MAILBOX_FLAG_USE_STUBS) != 0);
i_assert(box->opened);
box->transaction_count++;
trans = box->v.transaction_begin(box, flags);
trans->flags = flags;
return trans;
}
int mailbox_transaction_commit(struct mailbox_transaction_context **t)
{
struct mail_transaction_commit_changes changes;
int ret;
/* Store changes temporarily so that plugins overriding
transaction_commit() can look at them. */
ret = mailbox_transaction_commit_get_changes(t, &changes);
if (changes.pool != NULL)
pool_unref(&changes.pool);
return ret;
}
int mailbox_transaction_commit_get_changes(
struct mailbox_transaction_context **_t,
struct mail_transaction_commit_changes *changes_r)
{
struct mailbox_transaction_context *t = *_t;
struct mailbox *box = t->box;
unsigned int save_count = t->save_count;
int ret;
changes_r->pool = NULL;
*_t = NULL;
T_BEGIN {
ret = box->v.transaction_commit(t, changes_r);
} T_END;
/* either all the saved messages get UIDs or none, because a) we
failed, b) MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS not set,
c) backend doesn't support it (e.g. virtual plugin) */
i_assert(ret < 0 ||
seq_range_count(&changes_r->saved_uids) == save_count ||
array_count(&changes_r->saved_uids) == 0);
/* decrease the transaction count only after transaction_commit().
that way if it creates and destroys transactions internally, we
don't see transaction_count=0 until the parent transaction is fully
finished */
box->transaction_count--;
if (ret < 0 && changes_r->pool != NULL)
pool_unref(&changes_r->pool);
return ret;
}
void mailbox_transaction_rollback(struct mailbox_transaction_context **_t)
{
struct mailbox_transaction_context *t = *_t;
struct mailbox *box = t->box;
*_t = NULL;
box->v.transaction_rollback(t);
box->transaction_count--;
}
void mailbox_transaction_set_reason(struct mailbox_transaction_context *t,
const char *reason)
{
i_assert(reason != NULL);
i_free(t->reason);
t->reason = i_strdup(reason);
}
unsigned int mailbox_transaction_get_count(const struct mailbox *box)
{
return box->transaction_count;
}
void mailbox_transaction_set_max_modseq(struct mailbox_transaction_context *t,
uint64_t max_modseq,
ARRAY_TYPE(seq_range) *seqs)
{
mail_index_transaction_set_max_modseq(t->itrans, max_modseq, seqs);
}
struct mailbox *
mailbox_transaction_get_mailbox(const struct mailbox_transaction_context *t)
{
return t->box;
}
static void mailbox_save_dest_mail_close(struct mail_save_context *ctx)
{
struct mail_private *mail = (struct mail_private *)ctx->dest_mail;
mail->v.close(&mail->mail);
}
struct mail_save_context *
mailbox_save_alloc(struct mailbox_transaction_context *t)
{
struct mail_save_context *ctx;
T_BEGIN {
ctx = t->box->v.save_alloc(t);
} T_END;
i_assert(!ctx->unfinished);
ctx->unfinished = TRUE;
ctx->data.received_date = (time_t)-1;
ctx->data.save_date = (time_t)-1;
/* Always have a dest_mail available. A lot of plugins make use
of this. */
if (ctx->dest_mail == NULL)
ctx->dest_mail = mail_alloc(t, 0, NULL);
else {
/* make sure the mail isn't used before mail_set_seq_saving() */
mailbox_save_dest_mail_close(ctx);
}
return ctx;
}
void mailbox_save_context_deinit(struct mail_save_context *ctx)
{
i_assert(ctx->dest_mail != NULL);
if (!ctx->dest_mail_external)
mail_free(&ctx->dest_mail);
else
ctx->dest_mail = NULL;
}
void mailbox_save_set_flags(struct mail_save_context *ctx,
enum mail_flags flags,
struct mail_keywords *keywords)
{
struct mailbox *box = ctx->transaction->box;
if (ctx->data.keywords != NULL)
mailbox_keywords_unref(&ctx->data.keywords);
ctx->data.flags = flags & ~mailbox_get_private_flags_mask(box);
ctx->data.pvt_flags = flags & mailbox_get_private_flags_mask(box);
ctx->data.keywords = keywords;
if (keywords != NULL)
mailbox_keywords_ref(keywords);
}
void mailbox_save_copy_flags(struct mail_save_context *ctx, struct mail *mail)
{
const char *const *keywords_list;
struct mail_keywords *keywords;
keywords_list = mail_get_keywords(mail);
keywords = str_array_length(keywords_list) == 0 ? NULL :
mailbox_keywords_create_valid(ctx->transaction->box,
keywords_list);
mailbox_save_set_flags(ctx, mail_get_flags(mail), keywords);
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
}
void mailbox_save_set_min_modseq(struct mail_save_context *ctx,
uint64_t min_modseq)
{
ctx->data.min_modseq = min_modseq;
}
void mailbox_save_set_received_date(struct mail_save_context *ctx,
time_t received_date, int timezone_offset)
{
ctx->data.received_date = received_date;
ctx->data.received_tz_offset = timezone_offset;
}
void mailbox_save_set_save_date(struct mail_save_context *ctx,
time_t save_date)
{
ctx->data.save_date = save_date;
}
void mailbox_save_set_from_envelope(struct mail_save_context *ctx,
const char *envelope)
{
i_free(ctx->data.from_envelope);
ctx->data.from_envelope = i_strdup(envelope);
}
void mailbox_save_set_uid(struct mail_save_context *ctx, uint32_t uid)
{
ctx->data.uid = uid;
if ((ctx->transaction->flags & MAILBOX_TRANSACTION_FLAG_FILL_IN_STUB) != 0) {
if (!mail_index_lookup_seq(ctx->transaction->view, uid,
&ctx->data.stub_seq))
i_panic("Trying to fill in stub for nonexistent UID %u", uid);
}
}
void mailbox_save_set_guid(struct mail_save_context *ctx, const char *guid)
{
i_assert(guid == NULL || *guid != '\0');
i_free(ctx->data.guid);
ctx->data.guid = i_strdup(guid);
}
void mailbox_save_set_pop3_uidl(struct mail_save_context *ctx, const char *uidl)
{
i_assert(*uidl != '\0');
i_assert(strchr(uidl, '\n') == NULL);
i_free(ctx->data.pop3_uidl);
ctx->data.pop3_uidl = i_strdup(uidl);
}
void mailbox_save_set_pop3_order(struct mail_save_context *ctx,
unsigned int order)
{
i_assert(order > 0);
ctx->data.pop3_order = order;
}
void mailbox_save_set_dest_mail(struct mail_save_context *ctx,
struct mail *mail)
{
i_assert(mail != NULL);
if (!ctx->dest_mail_external)
mail_free(&ctx->dest_mail);
ctx->dest_mail = mail;
ctx->dest_mail_external = TRUE;
}
struct mail *mailbox_save_get_dest_mail(struct mail_save_context *ctx)
{
return ctx->dest_mail;
}
int mailbox_save_begin(struct mail_save_context **ctx, struct istream *input)
{
struct mailbox *box = (*ctx)->transaction->box;
int ret;
if (mail_index_is_deleted(box->index)) {
mailbox_set_deleted(box);
mailbox_save_cancel(ctx);
return -1;
}
/* if we're filling in a stub, we must have set UID already
(which in turn sets stub_seq) */
i_assert(((*ctx)->transaction->flags & MAILBOX_TRANSACTION_FLAG_FILL_IN_STUB) == 0 ||
(*ctx)->data.stub_seq != 0);
if (!(*ctx)->copying_or_moving) {
/* We're actually saving the mail. We're not being called by
mail_storage_copy() because backend didn't support fast
copying. */
i_assert(!(*ctx)->copying_via_save);
(*ctx)->saving = TRUE;
} else {
i_assert((*ctx)->copying_via_save);
}
if (box->v.save_begin == NULL) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Saving messages not supported");
ret = -1;
} else T_BEGIN {
ret = box->v.save_begin(*ctx, input);
} T_END;
if (ret < 0) {
mailbox_save_cancel(ctx);
return -1;
}
return 0;
}
int mailbox_save_continue(struct mail_save_context *ctx)
{
int ret;
T_BEGIN {
ret = ctx->transaction->box->v.save_continue(ctx);
} T_END;
return ret;
}
static void
mailbox_save_add_pvt_flags(struct mailbox_transaction_context *t,
enum mail_flags pvt_flags)
{
struct mail_save_private_changes *save;
if (!array_is_created(&t->pvt_saves))
i_array_init(&t->pvt_saves, 8);
save = array_append_space(&t->pvt_saves);
save->mailnum = t->save_count;
save->flags = pvt_flags;
}
static void
mailbox_save_context_reset(struct mail_save_context *ctx, bool success)
{
i_assert(!ctx->unfinished);
if (!ctx->copying_or_moving) {
/* we're finishing a save (not copy/move). Note that we could
have come here also from mailbox_save_cancel(), in which
case ctx->saving may be FALSE. */
i_assert(!ctx->copying_via_save);
i_assert(ctx->saving || !success);
ctx->saving = FALSE;
} else {
i_assert(ctx->copying_via_save || !success);
/* We came from mailbox_copy(). saving==TRUE is possible here
if we also came from mailbox_save_using_mail(). Don't set
saving=FALSE yet in that case, because copy() is still
running. */
}
}
int mailbox_save_finish(struct mail_save_context **_ctx)
{
struct mail_save_context *ctx = *_ctx;
struct mailbox_transaction_context *t = ctx->transaction;
struct mail_keywords *keywords = ctx->data.keywords;
enum mail_flags pvt_flags = ctx->data.pvt_flags;
bool copying_via_save = ctx->copying_via_save;
int ret;
/* Do one final continue. The caller may not have done it if the
input stream's offset already matched the number of bytes that
were wanted to be saved. But due to nested istreams some of the
underlying ones may not have seen the EOF yet, and haven't flushed
out the pending data. */
if (mailbox_save_continue(ctx) < 0) {
mailbox_save_cancel(_ctx);
return -1;
}
*_ctx = NULL;
ctx->finishing = TRUE;
T_BEGIN {
ret = t->box->v.save_finish(ctx);
} T_END;
ctx->finishing = FALSE;
if (ret == 0 && !copying_via_save) {
if (pvt_flags != 0)
mailbox_save_add_pvt_flags(t, pvt_flags);
t->save_count++;
}
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
mailbox_save_context_reset(ctx, TRUE);
return ret;
}
void mailbox_save_cancel(struct mail_save_context **_ctx)
{
struct mail_save_context *ctx = *_ctx;
struct mail_keywords *keywords = ctx->data.keywords;
*_ctx = NULL;
T_BEGIN {
ctx->transaction->box->v.save_cancel(ctx);
} T_END;
if (keywords != NULL && !ctx->finishing)
mailbox_keywords_unref(&keywords);
/* the dest_mail is no longer valid. if we're still saving
more mails, the mail sequence may get reused. make sure
the mail gets reset in between */
mailbox_save_dest_mail_close(ctx);
mailbox_save_context_reset(ctx, FALSE);
}
struct mailbox_transaction_context *
mailbox_save_get_transaction(struct mail_save_context *ctx)
{
return ctx->transaction;
}
static int mailbox_copy_int(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
struct mailbox_transaction_context *t = ctx->transaction;
struct mail_keywords *keywords = ctx->data.keywords;
enum mail_flags pvt_flags = ctx->data.pvt_flags;
struct mail *backend_mail;
int ret;
*_ctx = NULL;
if (mail_index_is_deleted(t->box->index)) {
mailbox_set_deleted(t->box);
mailbox_save_cancel(&ctx);
return -1;
}
/* bypass virtual storage, so hard linking can be used whenever
possible */
if (mail_get_backend_mail(mail, &backend_mail) < 0) {
mailbox_save_cancel(&ctx);
return -1;
}
i_assert(!ctx->copying_or_moving);
i_assert(ctx->copy_src_mail == NULL);
ctx->copying_or_moving = TRUE;
ctx->copy_src_mail = mail;
ctx->finishing = TRUE;
T_BEGIN {
ret = t->box->v.copy(ctx, backend_mail);
} T_END;
ctx->finishing = FALSE;
if (ret == 0) {
if (pvt_flags != 0)
mailbox_save_add_pvt_flags(t, pvt_flags);
t->save_count++;
}
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
i_assert(!ctx->unfinished);
ctx->copy_src_mail = NULL;
ctx->copying_via_save = FALSE;
ctx->copying_or_moving = FALSE;
ctx->saving = FALSE; /* if we came from mailbox_save_using_mail() */
return ret;
}
int mailbox_copy(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
i_assert(!ctx->saving);
i_assert(!ctx->moving);
return mailbox_copy_int(_ctx, mail);
}
int mailbox_move(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
int ret;
i_assert(!ctx->saving);
i_assert(!ctx->moving);
ctx->moving = TRUE;
if ((ret = mailbox_copy_int(_ctx, mail)) == 0)
mail_expunge(mail);
ctx->moving = FALSE;
return ret;
}
int mailbox_save_using_mail(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
i_assert(!ctx->saving);
i_assert(!ctx->moving);
ctx->saving = TRUE;
return mailbox_copy_int(_ctx, mail);
}
bool mailbox_is_inconsistent(struct mailbox *box)
{
return box->mailbox_deleted || box->v.is_inconsistent(box);
}
void mailbox_set_deleted(struct mailbox *box)
{
mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
"Mailbox was deleted under us");
box->mailbox_deleted = TRUE;
}
static int get_path_to(struct mailbox *box, enum mailbox_list_path_type type,
const char **internal_path, const char **path_r)
{
int ret;
if (internal_path != NULL && *internal_path != NULL) {
if ((*internal_path)[0] == '\0') {
*path_r = NULL;
return 0;
}
*path_r = *internal_path;
return 1;
}
ret = mailbox_list_get_path(box->list, box->name, type, path_r);
if (ret < 0) {
mail_storage_copy_list_error(box->storage, box->list);
return -1;
}
if (internal_path != NULL && *internal_path == NULL)
*internal_path = ret == 0 ? "" : p_strdup(box->pool, *path_r);
return ret;
}
int mailbox_get_path_to(struct mailbox *box, enum mailbox_list_path_type type,
const char **path_r)
{
if (type == MAILBOX_LIST_PATH_TYPE_MAILBOX)
return get_path_to(box, type, &box->_path, path_r);
if (type == MAILBOX_LIST_PATH_TYPE_INDEX)
return get_path_to(box, type, &box->_index_path, path_r);
return get_path_to(box, type, NULL, path_r);
}
const char *mailbox_get_path(struct mailbox *box)
{
i_assert(box->_path != NULL);
i_assert(box->_path[0] != '\0');
return box->_path;
}
const char *mailbox_get_index_path(struct mailbox *box)
{
i_assert(box->_index_path != NULL);
i_assert(box->_index_path[0] != '\0');
return box->_index_path;
}
static void mailbox_get_permissions_if_not_set(struct mailbox *box)
{
if (box->_perm.file_create_mode != 0)
return;
if (box->input != NULL) {
box->_perm.file_uid = geteuid();
box->_perm.file_create_mode = 0600;
box->_perm.dir_create_mode = 0700;
box->_perm.file_create_gid = (gid_t)-1;
box->_perm.file_create_gid_origin = "defaults";
return;
}
struct mailbox_permissions perm;
mailbox_list_get_permissions(box->list, box->name, &perm);
mailbox_permissions_copy(&box->_perm, &perm, box->pool);
}
const struct mailbox_permissions *mailbox_get_permissions(struct mailbox *box)
{
mailbox_get_permissions_if_not_set(box);
if (!box->_perm.mail_index_permissions_set && box->index != NULL) {
box->_perm.mail_index_permissions_set = TRUE;
mail_index_set_permissions(box->index,
box->_perm.file_create_mode,
box->_perm.file_create_gid,
box->_perm.file_create_gid_origin);
}
return &box->_perm;
}
void mailbox_refresh_permissions(struct mailbox *box)
{
i_zero(&box->_perm);
(void)mailbox_get_permissions(box);
}
int mailbox_create_fd(struct mailbox *box, const char *path, int flags,
int *fd_r)
{
const struct mailbox_permissions *perm = mailbox_get_permissions(box);
mode_t old_mask;
int fd;
i_assert((flags & O_CREAT) != 0);
*fd_r = -1;
old_mask = umask(0);
fd = open(path, flags, perm->file_create_mode);
umask(old_mask);
if (fd != -1) {
/* ok */
} else if (errno == EEXIST) {
/* O_EXCL used, caller will handle this error */
return 0;
} else if (errno == ENOENT) {
mailbox_set_deleted(box);
return -1;
} else if (errno == ENOTDIR) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox doesn't allow inferior mailboxes");
return -1;
} else if (mail_storage_set_error_from_errno(box->storage)) {
return -1;
} else {
mail_storage_set_critical(box->storage,
"open(%s, O_CREAT) failed: %m", path);
return -1;
}
if (perm->file_create_gid != (gid_t)-1) {
if (fchown(fd, (uid_t)-1, perm->file_create_gid) == 0) {
/* ok */
} else if (errno == EPERM) {
mail_storage_set_critical(box->storage, "%s",
eperm_error_get_chgrp("fchown", path,
perm->file_create_gid,
perm->file_create_gid_origin));
} else {
mail_storage_set_critical(box->storage,
"fchown(%s) failed: %m", path);
}
}
*fd_r = fd;
return 1;
}
int mailbox_mkdir(struct mailbox *box, const char *path,
enum mailbox_list_path_type type)
{
const struct mailbox_permissions *perm = mailbox_get_permissions(box);
const char *root_dir;
if (!perm->gid_origin_is_mailbox_path) {
/* mailbox root directory doesn't exist, create it */
root_dir = mailbox_list_get_root_forced(box->list, type);
if (mailbox_list_mkdir_root(box->list, root_dir, type) < 0) {
mail_storage_copy_list_error(box->storage, box->list);
return -1;
}
}
if (mkdir_parents_chgrp(path, perm->dir_create_mode,
perm->file_create_gid,
perm->file_create_gid_origin) == 0)
return 1;
else if (errno == EEXIST)
return 0;
else if (errno == ENOTDIR) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox doesn't allow inferior mailboxes");
return -1;
} else if (mail_storage_set_error_from_errno(box->storage)) {
return -1;
} else {
mail_storage_set_critical(box->storage,
"mkdir_parents(%s) failed: %m", path);
return -1;
}
}
int mailbox_create_missing_dir(struct mailbox *box,
enum mailbox_list_path_type type)
{
const char *mail_dir, *dir;
struct stat st;
int ret;
if ((ret = mailbox_get_path_to(box, type, &dir)) <= 0)
return ret;
if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
&mail_dir) < 0)
return -1;
if (null_strcmp(dir, mail_dir) == 0) {
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,
bool *utc_r)
{
struct tm tm;
unsigned int secs;
const char *error;
if (i_isdigit(str[0]) && i_isdigit(str[1]) &&
i_isdigit(str[2]) && i_isdigit(str[3]) && str[4] == '-' &&
i_isdigit(str[5]) && i_isdigit(str[6]) && str[7] == '-' &&
i_isdigit(str[8]) && i_isdigit(str[9]) && str[10] == '\0') {
/* yyyy-mm-dd */
i_zero(&tm);
tm.tm_year = (str[0]-'0') * 1000 + (str[1]-'0') * 100 +
(str[2]-'0') * 10 + (str[3]-'0') - 1900;
tm.tm_mon = (str[5]-'0') * 10 + (str[6]-'0') - 1;
tm.tm_mday = (str[8]-'0') * 10 + (str[9]-'0');
*timestamp_r = mktime(&tm);
*utc_r = FALSE;
return 0;
} else if (imap_parse_date(str, timestamp_r)) {
/* imap date */
*utc_r = FALSE;
return 0;
} else if (str_to_time(str, timestamp_r) == 0) {
/* unix timestamp */
*utc_r = TRUE;
return 0;
} else if (settings_get_time(str, &secs, &error) == 0) {
*timestamp_r = ioloop_time - secs;
*utc_r = TRUE;
return 0;
} else {
return -1;
}
}
void mail_set_mail_cache_corrupted(struct mail *mail, const char *fmt, ...)
{
struct mail_cache_view *cache_view =
mail->transaction->cache_view;
i_assert(cache_view != NULL);
va_list va;
va_start(va, fmt);
T_BEGIN {
mail_cache_set_seq_corrupted_reason(cache_view, mail->seq,
t_strdup_printf("UID %u: %s",
mail->uid,
t_strdup_vprintf(fmt, va)));
} T_END;
va_end(va);
}
int mailbox_lock_file_create(struct mailbox *box, const char *lock_fname,
unsigned int lock_secs, struct file_lock **lock_r,
const char **error_r)
{
const struct mailbox_permissions *perm;
struct file_create_settings set;
const char *lock_path;
bool created;
perm = mailbox_get_permissions(box);
i_zero(&set);
set.lock_timeout_secs =
mail_storage_get_lock_timeout(box->storage, lock_secs);
set.lock_method = box->storage->set->parsed_lock_method;
set.mode = perm->file_create_mode;
set.gid = perm->file_create_gid;
set.gid_origin = perm->file_create_gid_origin;
if (box->list->set.volatile_dir == NULL)
lock_path = t_strdup_printf("%s/%s", box->index->dir, lock_fname);
else {
unsigned char box_name_sha1[SHA1_RESULTLEN];
string_t *str = t_str_new(128);
/* Keep this simple: Use the lock_fname with a SHA1 of the
mailbox name as the suffix. The mailbox name itself could
be too large as a filename and creating the full directory
structure would be pretty troublesome. It would also make
it more difficult to perform the automated deletion of empty
lock directories. */
str_printfa(str, "%s/%s.", box->list->set.volatile_dir,
lock_fname);
sha1_get_digest(box->name, strlen(box->name), box_name_sha1);
binary_to_hex_append(str, box_name_sha1, sizeof(box_name_sha1));
lock_path = str_c(str);
set.mkdir_mode = 0700;
}
if (file_create_locked(lock_path, &set, lock_r, &created, error_r) == -1) {
*error_r = t_strdup_printf("file_create_locked(%s) failed: %s",
lock_path, *error_r);
return errno == EAGAIN ? 0 : -1;
}
file_lock_set_close_on_free(*lock_r, TRUE);
file_lock_set_unlink_on_free(*lock_r, TRUE);
return 1;
}