mail-storage.c revision 13e130c3af3032982de6b1d13c6dcddda9164848
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ioloop.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "array.h"
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen#include "llist.h"
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen#include "unichar.h"
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen#include "istream.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "eacces-error.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mkdir-parents.h"
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen#include "time-util.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "var-expand.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-index-private.h"
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen#include "mail-index-alloc-cache.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mailbox-tree.h"
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen#include "mailbox-list-private.h"
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen#include "mail-storage-private.h"
5a6343181a5183b1ae1c39d40fc5a1deb3b840d9Timo Sirainen#include "mail-storage-settings.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-namespace.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-search.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-search-register.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mailbox-search-result-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mailbox-guid-cache.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <ctype.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MAILBOX_DELETE_RETRY_SECS (60*5)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct mail_search_register *mail_search_register_imap;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct mail_search_register *mail_search_register_human;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct mail_module_register mail_module_register = { 0 };
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo SirainenARRAY_TYPE(mail_storage) mail_storage_classes;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenvoid mail_storage_init(void)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen{
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen mailbox_lists_init();
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen mail_storage_hooks_init();
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen i_array_init(&mail_storage_classes, 8);
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen}
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenvoid mail_storage_deinit(void)
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen{
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen if (mail_search_register_human != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_search_register_deinit(&mail_search_register_human);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_search_register_imap != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_search_register_deinit(&mail_search_register_imap);
104318260228780a5c6b3181b3401e8e504e2776Timo Sirainen if (array_is_created(&mail_storage_classes))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_free(&mail_storage_classes);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_hooks_deinit();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mailbox_lists_deinit();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen{
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* append it after the list, so the autodetection order is correct */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen{
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen struct mail_storage *const *classes;
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen unsigned int i, count;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen classes = array_get(&mail_storage_classes, &count);
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen for (i = 0; i < count; i++) {
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen if (classes[i] == storage_class) {
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen array_delete(&mail_storage_classes, i, 1);
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen break;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen }
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen }
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen}
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen{
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen struct mail_storage *const *classes;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i, count;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen i_assert(name != NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen classes = array_get(&mail_storage_classes, &count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < count; i++) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (strcasecmp(classes[i]->name, name) == 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return classes[i];
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return NULL;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic struct mail_storage *
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen struct mailbox_list_settings *set)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_storage *const *classes;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i, count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen classes = array_get(&mail_storage_classes, &count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < count; i++) {
7fe37c2b0e4cd2a39896ab16e47eb418a59e3934Timo Sirainen if (classes[i]->v.autodetect != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (classes[i]->v.autodetect(ns, set))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return classes[i];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen }
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen return NULL;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen}
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenstatic void
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen{
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen const char *p;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen p = *data;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen while (i_isalnum(*p)) p++;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (*p == ':' && p != *data) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* no autodetection if the storage driver is given. */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen *driver = t_strdup_until(*data, p);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen *data = p + 1;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen }
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen}
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenstatic struct mail_storage *
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen struct mailbox_list_settings *list_set,
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen enum mail_storage_flags flags, const char **error_r)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen{
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen struct mail_storage *storage_class = NULL;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen const char *home;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (driver == NULL) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* no mail_location, autodetect */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen } else if (strcmp(driver, "auto") == 0) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* explicit autodetection with "auto" driver. */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (list_set->root_dir != NULL &&
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen *list_set->root_dir == '\0') {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* handle the same as with driver=NULL */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen list_set->root_dir = NULL;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen }
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen } else {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen storage_class = mail_user_get_storage_class(ns->user, driver);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (storage_class == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = t_strdup_printf(
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Unknown mail storage driver %s", driver);
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen return NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (list_set->root_dir == NULL || *list_set->root_dir == '\0') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* no root directory given. is this allowed? */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mailbox_list *list;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen list = list_set->layout == NULL ? NULL :
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen mailbox_list_find_class(list_set->layout);
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen if (storage_class == NULL &&
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen (flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* autodetection should take care of this */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen } else if (storage_class != NULL &&
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen (storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* root not required for this storage */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen } else if (list != NULL &&
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen (list->props & MAILBOX_LIST_PROP_NO_ROOT) != 0) {
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen /* root not required for this layout */
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen } else {
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen *error_r = "Root mail directory not given";
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen return NULL;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen }
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen }
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen if (storage_class != NULL) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen storage_class->v.get_list_settings(ns, list_set);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return storage_class;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (storage_class != NULL)
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen return storage_class;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen (void)mail_user_get_home(ns->user, &home);
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen *error_r = t_strdup_printf(
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Mail storage autodetection failed with home=%s", home);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else if (strncmp(ns->set->location, "auto:", 5) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = t_strdup_printf(
cd2ed64888b42b481cde6bb9548c8520516fa3e9Timo Sirainen "Autodetection failed for %s (home=%s)",
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen ns->set->location, home);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen *error_r = t_strdup_printf(
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen "Ambiguous mail location setting, "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "don't know what to do with it: %s "
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen "(try prefixing it with mbox: or maildir:)",
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen ns->set->location);
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen }
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen return NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainenstatic int
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainenmail_storage_verify_root(const char *root_dir, bool autocreate,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char **error_r)
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen{
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen struct stat st;
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen if (stat(root_dir, &st) == 0) {
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen /* exists */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (errno == EACCES) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (errno != ENOENT && errno != ENOTDIR) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen } else if (!autocreate) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen *error_r = t_strdup_printf(
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen "Root mail directory doesn't exist: %s", root_dir);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return -1;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen } else {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* doesn't exist */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen return 0;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmail_storage_create_root(struct mailbox_list *list,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mail_storage_flags flags, const char **error_r)
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen{
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen const char *root_dir, *error;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen bool autocreate;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen int ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_MAILBOX,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen &root_dir)) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* storage doesn't use directories (e.g. shared root) */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOVERIFY) != 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (!list->mail_set->mail_debug)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* we don't need to verify, but since debugging is
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen enabled, check and log if the root doesn't exist */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (mail_storage_verify_root(root_dir, FALSE, &error) < 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen i_debug("Namespace %s: Creating storage despite: %s",
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen list->ns->prefix, error);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen autocreate = (flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) == 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen ret = mail_storage_verify_root(root_dir, autocreate, error_r);
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen if (ret == 0) {
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen ret = mailbox_list_try_mkdir_root(list, root_dir,
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX,
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen error_r);
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return ret < 0 ? -1 : 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen}
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenstatic bool
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmail_storage_match_class(struct mail_storage *storage,
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen const struct mail_storage *storage_class,
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen const struct mailbox_list_settings *set)
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen{
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen if (strcmp(storage->name, storage_class->name) != 0)
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen return FALSE;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if ((storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0 &&
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen strcmp(storage->unique_root_dir, set->root_dir) != 0)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return FALSE;
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen if (strcmp(storage->name, "shared") == 0) {
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen /* allow multiple independent shared namespaces */
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen return FALSE;
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen }
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen return TRUE;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen}
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic struct mail_storage *
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_storage_find(struct mail_user *user,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_storage *storage_class,
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen const struct mailbox_list_settings *set)
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen{
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen struct mail_storage *storage = user->storages;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen for (; storage != NULL; storage = storage->next) {
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen if (mail_storage_match_class(storage, storage_class, set))
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen return storage;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen }
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen return NULL;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen}
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen enum mail_storage_flags flags, const char **error_r)
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen{
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen struct mail_storage *storage_class, *storage = NULL;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen struct mailbox_list *list;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen struct mailbox_list_settings list_set;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen enum mailbox_list_flags list_flags = 0;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen const char *data = ns->set->location;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen const char *p;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen ns->mail_set->pop3_uidl_format != NULL) {
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen header MD5 sums stored even if we're not running POP3
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen right now. */
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen p = ns->mail_set->pop3_uidl_format;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen while ((p = strchr(p, '%')) != NULL) {
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen if (p[1] == '%')
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen p += 2;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen else if (var_get_key(++p) == 'm') {
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
e52f55c08f6f1b4fbc5765bf6aa9c7daee0785c3Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen memset(&list_set, 0, sizeof(list_set));
e52f55c08f6f1b4fbc5765bf6aa9c7daee0785c3Timo Sirainen list_set.mailbox_dir_name = "";
e52f55c08f6f1b4fbc5765bf6aa9c7daee0785c3Timo Sirainen list_set.maildir_name = "";
e52f55c08f6f1b4fbc5765bf6aa9c7daee0785c3Timo Sirainen if (data == NULL) {
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen /* autodetect */
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen /* internal shared namespace */
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen list_set.root_dir = ns->user->set->base_dir;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (driver == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_autodetection(&data, &driver);
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen if (mailbox_list_settings_parse(ns->user, data, &list_set,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen error_r) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, flags,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen error_r);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (storage_class == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen i_assert(list_set.layout != NULL);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (ns->list == NULL) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* first storage for namespace */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (mail_storage_is_mailbox_file(storage_class))
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0)
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_NO_MAIL_FILES;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen list_flags, &list, error_r) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = t_strdup_printf("Mailbox list driver %s: %s",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen list_set.layout, *error_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen return -1;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (storage != NULL) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* using an existing storage */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage->refcount++;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_namespace_add_storage(ns, storage);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen return 0;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen storage = storage_class->v.alloc();
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen storage->refcount = 1;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen storage->storage_class = storage_class;
f5e1d3d6b34ec152aa1ff15c7bd3d3552e9227eaTimo Sirainen storage->user = ns->user;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen storage->set = ns->mail_set;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen storage->flags = flags;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (storage->v.create != NULL &&
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen storage->v.create(storage, ns, error_r) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen pool_unref(&storage->pool);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen }
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen T_BEGIN {
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen hook_mail_storage_created(storage);
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen } T_END;
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen DLLIST_PREPEND(&ns->user->storages, storage);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen mail_namespace_add_storage(ns, storage);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen return 0;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen}
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen{
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen struct mail_storage *storage = *_storage;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen i_assert(storage->refcount > 0);
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen /* set *_storage=NULL only after calling destroy() callback.
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen for example mdbox wants to access ns->storage */
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen if (--storage->refcount > 0) {
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen *_storage = NULL;
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen return;
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen }
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen if (storage->mailboxes != NULL) {
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen i_panic("Trying to deinit storage without freeing mailbox %s",
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen storage->mailboxes->vname);
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen }
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen if (storage->obj_refcount != 0)
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen i_panic("Trying to deinit storage before freeing its objects");
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen DLLIST_REMOVE(&storage->user->storages, storage);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen storage->v.destroy(storage);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen i_free(storage->error_string);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen *_storage = NULL;
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen pool_unref(&storage->pool);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_alloc_cache_destroy_unrefed();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainenvoid mail_storage_obj_ref(struct mail_storage *storage)
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(storage->refcount > 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen if (storage->obj_refcount++ == 0)
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen mail_user_ref(storage->user);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainenvoid mail_storage_obj_unref(struct mail_storage *storage)
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen{
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen i_assert(storage->refcount > 0);
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen i_assert(storage->obj_refcount > 0);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (--storage->obj_refcount == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_user *user = storage->user;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_user_unref(&user);
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen }
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen}
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen{
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen i_free_and_null(storage->error_string);
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen storage->error = MAIL_ERROR_NONE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mail_error error, const char *string)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_free(storage->error_string);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage->error_string = i_strdup(string);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage->error = error;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen{
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen const char *str;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen str = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen i_free(storage->error_string);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen storage->error_string = i_strdup(str);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen storage->error = MAIL_ERROR_TEMP;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen}
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen const char *fmt, ...)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen{
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen va_list va;
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen va_start(va, fmt);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("%s", t_strdup_vprintf(fmt, va));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen va_end(va);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* critical errors may contain sensitive data, so let user
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen see only "Internal error" with a timestamp to make it
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen easier to look from log files the actual error message. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_set_internal_error(storage);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid mail_storage_copy_error(struct mail_storage *dest,
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen struct mail_storage *src)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *str;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen enum mail_error error;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen str = mail_storage_get_last_error(src, &error);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_set_error(dest, error, str);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainenvoid mail_storage_copy_list_error(struct mail_storage *storage,
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen struct mailbox_list *list)
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen{
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen const char *str;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen enum mail_error error;
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen str = mailbox_list_get_last_error(list, &error);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mail_storage_set_error(storage, error, str);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid mailbox_set_index_error(struct mailbox *box)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_index_is_deleted(box->index))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_set_deleted(box);
cbcba924a745c938260fd39cb284175b75f8eaf2Timo Sirainen else
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_set_internal_error(box->storage);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_reset_error(box->index);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen}
8b5c520883aa37bb55646286d375fdbae294d710Timo Sirainen
8b5c520883aa37bb55646286d375fdbae294d710Timo Sirainenconst struct mail_storage_settings *
5a6343181a5183b1ae1c39d40fc5a1deb3b840d9Timo Sirainenmail_storage_get_settings(struct mail_storage *storage)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return storage->set;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct mail_user *mail_storage_get_user(struct mail_storage *storage)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return storage->user;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid mail_storage_set_callbacks(struct mail_storage *storage,
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen struct mail_storage_callbacks *callbacks,
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen void *context)
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen{
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen storage->callbacks = *callbacks;
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen storage->callback_context = context;
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen}
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainenint mail_storage_purge(struct mail_storage *storage)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return storage->v.purge == NULL ? 0 :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen storage->v.purge(storage);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainenconst char *mail_storage_get_last_error(struct mail_storage *storage,
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen enum mail_error *error_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* We get here only in error situations, so we have to return some
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen error. If storage->error is NONE, it means we forgot to set it at
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen some point.. */
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen if (storage->error == MAIL_ERROR_NONE) {
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen if (error_r != NULL)
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen *error_r = MAIL_ERROR_TEMP;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return storage->error_string != NULL ? storage->error_string :
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen "BUG: Unknown internal error";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (storage->error_string == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* This shouldn't happen.. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen storage->error_string =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_strdup_printf("BUG: Unknown 0x%x error",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen storage->error);
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen }
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen if (error_r != NULL)
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen *error_r = storage->error;
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen return storage->error_string;
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen}
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainenconst char *mailbox_get_last_error(struct mailbox *box,
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen enum mail_error *error_r)
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen{
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen return mail_storage_get_last_error(box->storage, error_r);
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen}
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainenenum mail_error mailbox_get_last_mail_error(struct mailbox *box)
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen enum mail_error error;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_get_last_error(box->storage, &error);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return error;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool mail_storage_is_mailbox_file(struct mail_storage *storage)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return (storage->class_flags &
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE) != 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool mail_storage_set_error_from_errno(struct mail_storage *storage)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *error_string;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen enum mail_error error;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* debugging is enabled - admin may be debugging a
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (permission) problem, so return FALSE to get the caller to
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen log the full error message. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen mail_storage_set_error(storage, error, error_string);
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen return TRUE;
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen}
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainenconst struct mailbox_settings *
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainenmailbox_settings_find(struct mail_user *user, const char *vname)
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen{
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen struct mailbox_settings *const *box_set;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen struct mail_namespace *ns;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen ns = mail_namespace_find(user->namespaces, vname);
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen if (!array_is_created(&ns->set->mailboxes))
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen return NULL;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (ns->prefix_len > 0 &&
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen strncmp(ns->prefix, vname, ns->prefix_len-1) == 0) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (vname[ns->prefix_len-1] == mail_namespace_get_sep(ns))
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen vname += ns->prefix_len;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen else if (vname[ns->prefix_len-1] == '\0') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* namespace prefix itself */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen vname = "";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_foreach(&ns->set->mailboxes, box_set) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcmp((*box_set)->name, vname) == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return *box_set;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainenstruct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen enum mailbox_flags flags)
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen{
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen struct mailbox_list *new_list = list;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_storage *storage;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mailbox *box;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(uni_utf8_str_is_valid(vname));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen strncasecmp(vname, "INBOX", 5) == 0 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen strncmp(vname, "INBOX", 5) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* make sure INBOX shows up in uppercase everywhere */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (vname[5] == '\0')
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen vname = "INBOX";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else if (vname[5] == mail_namespace_get_sep(list->ns))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen vname = t_strconcat("INBOX", vname + 5, NULL);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen }
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (mailbox_list_get_storage(&new_list, vname, &storage) < 0) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen /* just use the first storage. FIXME: does this break? */
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen storage = list->ns->storage;
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen }
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen T_BEGIN {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen box = storage->v.mailbox_alloc(storage, new_list, vname, flags);
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen box->set = mailbox_settings_find(storage->user, vname);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen hook_mailbox_allocated(box);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen } T_END;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen DLLIST_PREPEND(&box->storage->mailboxes, box);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen mail_storage_obj_ref(box->storage);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen return box;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen}
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainenstruct mailbox *mailbox_alloc_guid(struct mailbox_list *list,
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen const guid_128_t guid,
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen enum mailbox_flags flags)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen{
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen struct mailbox *box = NULL;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen struct mailbox_metadata metadata;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen enum mail_error open_error = MAIL_ERROR_TEMP;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen const char *vname;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (mailbox_guid_cache_find(list, guid, &vname) < 0) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen vname = NULL;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen } else if (vname != NULL) {
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen box = mailbox_alloc(list, vname, flags);
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID,
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen &metadata) < 0) {
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen } else if (memcmp(metadata.guid, guid,
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen sizeof(metadata.guid)) != 0) {
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen /* GUID mismatch, refresh cache and try again */
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen mailbox_free(&box);
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen mailbox_guid_cache_refresh(list);
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen return mailbox_alloc_guid(list, guid, flags);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen } else {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* successfully opened the correct mailbox */
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return box;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen i_error("mailbox_alloc_guid(%s): "
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen "Couldn't verify mailbox GUID: %s",
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen guid_128_to_string(guid),
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen mailbox_get_last_error(box, NULL));
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen vname = NULL;
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen mailbox_free(&box);
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen } else {
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen vname = t_strdup_printf("(nonexistent mailbox with GUID=%s)",
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen guid_128_to_string(guid));
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen open_error = MAIL_ERROR_NOTFOUND;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (vname == NULL) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen vname = t_strdup_printf("(error in mailbox with GUID=%s)",
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen guid_128_to_string(guid));
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen box = mailbox_alloc(list, vname, flags);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen box->open_error = open_error;
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen return box;
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen}
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainenstatic bool mailbox_is_autocreated(struct mailbox *box)
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen{
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen if (box->inbox_user)
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen return TRUE;
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen return box->set != NULL &&
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen strcmp(box->set->autocreate, MAILBOX_SET_AUTO_NO) != 0;
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen}
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainenstatic int mailbox_autocreate(struct mailbox *box)
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen{
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen const char *errstr;
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen enum mail_error error;
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen if (mailbox_create(box, NULL, FALSE) < 0) {
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen errstr = mailbox_get_last_error(box, &error);
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen if (error != MAIL_ERROR_NOTFOUND) {
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen mail_storage_set_critical(box->storage,
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen "Failed to autocreate mailbox %s: %s",
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen box->vname, errstr);
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen return -1;
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen }
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen } else if (box->set != NULL &&
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen strcmp(box->set->autocreate,
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen MAILBOX_SET_AUTO_SUBSCRIBE) == 0) {
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen if (mailbox_set_subscribed(box, TRUE) < 0) {
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen mail_storage_set_critical(box->storage,
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen "Failed to autosubscribe to mailbox %s: %s",
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen box->vname, mailbox_get_last_error(box, NULL));
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen return -1;
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen }
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen }
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen return 0;
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen}
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainenstatic int mailbox_autocreate_and_reopen(struct mailbox *box)
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen{
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen int ret;
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen if (mailbox_autocreate(box) < 0)
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen return -1;
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen mailbox_close(box);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = box->v.open(box);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (ret < 0 && box->inbox_user &&
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen !box->storage->user->inbox_open_error_logged) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen box->storage->user->inbox_open_error_logged = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_set_critical(box->storage,
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen "Opening INBOX failed: %s",
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen mailbox_get_last_error(box, NULL));
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen }
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen return ret;
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen}
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainenstatic bool
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainenmailbox_name_verify_separators(const char *vname, char sep,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char **error_r)
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen{
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen unsigned int i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool prev_sep = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* Make sure the vname is correct: non-empty, doesn't begin or end
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen with separator and no adjacent separators */
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen for (i = 0; vname[i] != '\0'; i++) {
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen if (vname[i] == sep) {
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen if (prev_sep) {
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen *error_r = "Has adjacent hierarchy separators";
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen return FALSE;
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen }
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen prev_sep = TRUE;
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen } else {
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen prev_sep = FALSE;
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen if (prev_sep && i > 0) {
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen *error_r = "Ends with hierarchy separator";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int mailbox_verify_name(struct mailbox *box)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct mail_namespace *ns = box->list->ns;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const char *error, *vname = box->vname;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen char list_sep, ns_sep;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (box->inbox_user) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* this is INBOX - don't bother with further checks */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen list_sep = mailbox_list_get_hierarchy_sep(box->list);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ns_sep = mail_namespace_get_sep(ns);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (ns->prefix_len > 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* vname is either "namespace/box" or "namespace" */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_assert(strncmp(vname, ns->prefix, ns->prefix_len-1) == 0);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen vname += ns->prefix_len - 1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (vname[0] != '\0') {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_assert(vname[0] == ns->prefix[ns->prefix_len-1]);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen vname++;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (vname[0] == '\0') {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* "namespace/" isn't a valid mailbox name. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mail_storage_set_error(box->storage,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen MAIL_ERROR_PARAMS,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "Invalid mailbox name");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (ns_sep != list_sep && box->list->set.escape_char == '\0' &&
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen strchr(vname, list_sep) != NULL) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, t_strdup_printf(
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "Character not allowed in mailbox name: '%c'", list_sep));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (vname[0] == ns_sep &&
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen !box->storage->set->mail_full_filesystem_access) {
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen "Invalid mailbox name: Begins with hierarchy separator");
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen return -1;
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen }
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen if (!mailbox_name_verify_separators(vname, ns_sep, &error) ||
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen !mailbox_list_is_valid_name(box->list, box->name, &error)) {
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen t_strdup_printf("Invalid mailbox name: %s", error));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int mailbox_verify_existing_name(struct mailbox *box)
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainen{
5a6343181a5183b1ae1c39d40fc5a1deb3b840d9Timo Sirainen const char *path;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen if (box->opened)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen return 0;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (mailbox_verify_name(box) < 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen /* Make sure box->_path is set, so mailbox_get_path() works from
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen now on. Note that this may also fail with some backends if the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox doesn't exist. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX, &path) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (box->storage->error != MAIL_ERROR_NOTFOUND ||
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen !mailbox_is_autocreated(box))
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* if this is an autocreated mailbox, create it now */
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen if (mailbox_autocreate(box) < 0)
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen return -1;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen mailbox_close(box);
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen &path) < 0)
41789540204ce091b2c06629d9a31788082e5da8Timo Sirainen return -1;
41789540204ce091b2c06629d9a31788082e5da8Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenstatic bool mailbox_name_has_control_chars(const char *name)
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen{
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen const char *p;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen for (p = name; *p != '\0'; p++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((unsigned char)*p < ' ')
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint mailbox_verify_create_name(struct mailbox *box)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen char sep = mail_namespace_get_sep(box->list->ns);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* mailbox_alloc() already checks that vname is valid UTF8,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen so we don't need to verify that.
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen check vname instead of storage name, because vname is what is
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen visible to users, while storage name may be a fixed length GUID. */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (mailbox_verify_name(box) < 0)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return -1;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (mailbox_name_has_control_chars(box->vname)) {
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen "Control characters not allowed in new mailbox names");
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mailbox_list_name_is_too_large(box->vname, sep)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Mailbox name too long");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen return 0;
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen}
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool have_listable_namespace_prefix(struct mail_namespace *ns,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *name)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen unsigned int name_len = strlen(name);
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen for (; ns != NULL; ns = ns->next) {
56ba5a9b62e3ce527e898a8fe3b1a015ab30ed54Timo Sirainen if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen continue;
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ns->prefix_len <= name_len)
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen continue;
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen /* if prefix has multiple hierarchies, match
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen any of the hierarchies */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (strncmp(ns->prefix, name, name_len) == 0 &&
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen ns->prefix[name_len] == mail_namespace_get_sep(ns))
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen return TRUE;
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen }
e3540e734a79fd4f971652925079c2e26a4b5524Timo Sirainen return FALSE;
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen}
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainenint mailbox_exists(struct mailbox *box, bool auto_boxes,
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen enum mailbox_existence *existence_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen switch (box->open_error) {
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen case 0:
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch break;
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch case MAIL_ERROR_NOTFOUND:
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch *existence_r = MAILBOX_EXISTENCE_NONE;
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch return 0;
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch default:
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch /* unsure if this exists or not */
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch return -1;
e4eb49e29197c6783ec93b868100394e189f4e0cTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mailbox_verify_name(box) < 0) {
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen /* the mailbox name is invalid. we don't know if it currently
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen exists or not, but since it can never be accessed in any way
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen report it as if it didn't exist. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *existence_r = MAILBOX_EXISTENCE_NONE;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return 0;
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen }
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (auto_boxes && box->set != NULL && mailbox_is_autocreated(box)) {
baca06331782e2752734199486e51a26d7c93d75Timo Sirainen *existence_r = MAILBOX_EXISTENCE_SELECT;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen return 0;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen }
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (box->v.exists(box, auto_boxes, existence_r) < 0)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen return -1;
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (!box->inbox_user && *existence_r == MAILBOX_EXISTENCE_NOSELECT &&
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen have_listable_namespace_prefix(box->storage->user->namespaces,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen box->vname)) {
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen /* listable namespace prefix always exists. */
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen *existence_r = MAILBOX_EXISTENCE_NOSELECT;
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen return 0;
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* if this is a shared namespace with only INBOX and
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_shared_explicit_inbox=no, we'll need to mark the namespace as
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen usable here since nothing else will. */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int ATTR_NULL(2)
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainenmailbox_open_full(struct mailbox *box, struct istream *input)
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen{
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen int ret;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (box->opened)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen return 0;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen switch (box->open_error) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen case 0:
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen break;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen case MAIL_ERROR_NOTFOUND:
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen return -1;
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen default:
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen mail_storage_set_internal_error(box->storage);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen box->storage->error = box->open_error;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen return -1;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen }
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (mailbox_verify_existing_name(box) < 0)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen return -1;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (input != NULL) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if ((box->storage->class_flags &
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) == 0) {
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen mail_storage_set_critical(box->storage,
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen "Storage doesn't support streamed mailboxes");
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen box->input = input;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen box->flags |= MAILBOX_FLAG_READONLY;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_ref(box->input);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen T_BEGIN {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = box->v.open(box);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } T_END;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (ret < 0 && box->storage->error == MAIL_ERROR_NOTFOUND &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen box->input == NULL && mailbox_is_autocreated(box)) T_BEGIN {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = mailbox_autocreate_and_reopen(box);
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen } T_END;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (ret < 0) {
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (box->input != NULL)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen i_stream_unref(&box->input);
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen return -1;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen }
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen return 0;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen}
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainenstatic bool mailbox_try_undelete(struct mailbox *box)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen{
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen time_t mtime;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (mail_index_get_modification_time(box->index, &mtime) < 0)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen return FALSE;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (mtime + MAILBOX_DELETE_RETRY_SECS > time(NULL))
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen return FALSE;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (mailbox_mark_index_deleted(box, FALSE) < 0)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen return FALSE;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen box->mailbox_deleted = FALSE;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen return TRUE;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen}
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainenint mailbox_open(struct mailbox *box)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen{
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (mailbox_open_full(box, NULL) < 0) {
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if (!box->mailbox_deleted)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen return -1;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* mailbox has been marked as deleted. if this deletion
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen started (and crashed) a long time ago, it can be confusing
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen to user that the mailbox can't be opened. so we'll just
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen undelete it and reopen. */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen if(!mailbox_try_undelete(box))
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mailbox_open_full(box, NULL) < 0)
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen return -1;
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen }
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen return 0;
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen}
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainenstatic int mailbox_alloc_index_pvt(struct mailbox *box)
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen{
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen const char *index_dir;
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen int ret;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen if (box->index_pvt != NULL)
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen return 1;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen &index_dir);
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (ret <= 0)
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen return ret; /* error / no private indexes */
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (mailbox_create_missing_dir(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE) < 0)
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen return -1;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen box->index_pvt = mail_index_alloc_cache_get(NULL, index_dir,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen t_strconcat(box->index_prefix, ".pvt", NULL));
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen mail_index_set_fsync_mode(box->index_pvt,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen box->storage->set->parsed_fsync_mode, 0);
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen mail_index_set_lock_method(box->index_pvt,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen box->storage->set->parsed_lock_method,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen mail_storage_get_lock_timeout(box->storage, -1U));
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen return 1;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen}
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainenint mailbox_open_index_pvt(struct mailbox *box)
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen{
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen int ret;
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (box->view_pvt != NULL)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen return 1;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (mailbox_get_private_flags_mask(box) == 0)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen return 0;
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen if ((ret = mailbox_alloc_index_pvt(box)) <= 0)
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen return ret;
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen if (mail_index_open(box->index_pvt, MAIL_INDEX_OPEN_FLAG_CREATE) < 0)
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen return -1;
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen box->view_pvt = mail_index_view_open(box->index_pvt);
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen return 1;
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen}
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainenint mailbox_open_stream(struct mailbox *box, struct istream *input)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen{
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen return mailbox_open_full(box, input);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen}
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenint mailbox_enable(struct mailbox *box, enum mailbox_feature features)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen{
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (mailbox_verify_name(box) < 0)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen return -1;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen return box->v.enable(box, features);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen}
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenenum mailbox_feature mailbox_get_enabled_features(struct mailbox *box)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen{
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen return box->enabled_features;
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen}
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainenvoid mail_storage_free_binary_cache(struct mail_storage *storage)
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen{
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen if (storage->binary_cache.box == NULL)
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen return;
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen timeout_remove(&storage->binary_cache.to);
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen i_stream_destroy(&storage->binary_cache.input);
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen memset(&storage->binary_cache, 0, sizeof(storage->binary_cache));
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen}
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenvoid mailbox_close(struct mailbox *box)
{
if (!box->opened)
return;
if (box->transaction_count != 0) {
i_panic("Trying to close mailbox %s with open transactions",
box->name);
}
box->v.close(box);
if (box->storage->binary_cache.box == box)
mail_storage_free_binary_cache(box->storage);
box->opened = FALSE;
box->mailbox_deleted = FALSE;
array_clear(&box->search_results);
}
void mailbox_free(struct mailbox **_box)
{
struct mailbox *box = *_box;
*_box = NULL;
mailbox_close(box);
box->v.free(box);
DLLIST_REMOVE(&box->storage->mailboxes, box);
mail_storage_obj_unref(box->storage);
if (box->metadata_pool != NULL)
pool_unref(&box->metadata_pool);
pool_unref(&box->pool);
}
bool mailbox_equals(const struct mailbox *box1,
const struct mail_namespace *ns2, const char *vname2)
{
struct mail_namespace *ns1 = mailbox_get_namespace(box1);
const char *name1;
if (ns1 != ns2)
return FALSE;
name1 = mailbox_get_vname(box1);
if (strcmp(name1, vname2) == 0)
return TRUE;
return strcasecmp(name1, "INBOX") == 0 &&
strcasecmp(vname2, "INBOX") == 0;
}
int mailbox_create(struct mailbox *box, const struct mailbox_update *update,
bool directory)
{
int ret;
if (mailbox_verify_create_name(box) < 0)
return -1;
box->creating = TRUE;
ret = box->v.create_box(box, update, directory);
box->creating = FALSE;
return ret;
}
int mailbox_update(struct mailbox *box, const struct mailbox_update *update)
{
i_assert(update->min_next_uid == 0 ||
update->min_first_recent_uid == 0 ||
update->min_first_recent_uid <= update->min_next_uid);
if (mailbox_verify_existing_name(box) < 0)
return -1;
return box->v.update_box(box, update);
}
int mailbox_mark_index_deleted(struct mailbox *box, bool del)
{
struct mail_index_transaction *trans;
enum mail_index_transaction_flags trans_flags = 0;
enum mailbox_flags old_flag;
int ret;
if (box->marked_deleted && del) {
/* we already marked it deleted. this allows plugins to
"lock" the deletion earlier. */
return 0;
}
old_flag = box->flags & MAILBOX_FLAG_OPEN_DELETED;
box->flags |= MAILBOX_FLAG_OPEN_DELETED;
ret = mailbox_open(box);
box->flags = (box->flags & ~MAILBOX_FLAG_OPEN_DELETED) | old_flag;
if (ret < 0)
return -1;
trans_flags = del ? 0 : MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL;
trans = mail_index_transaction_begin(box->view, trans_flags);
if (del)
mail_index_set_deleted(trans);
else
mail_index_set_undeleted(trans);
if (mail_index_transaction_commit(&trans) < 0) {
mailbox_set_index_error(box);
return -1;
}
/* sync the mailbox. this finishes the index deletion and it can
succeed only for a single session. we do it here, so the rest of
the deletion code doesn't have to worry about race conditions. */
if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0)
return -1;
box->marked_deleted = del;
return 0;
}
int mailbox_delete(struct mailbox *box)
{
int ret;
if (*box->name == '\0') {
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
"Storage root can't be deleted");
return -1;
}
if (box->inbox_any) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"INBOX can't be deleted.");
return -1;
}
box->deleting = TRUE;
if (mailbox_open(box) < 0) {
if (mailbox_get_last_mail_error(box) != MAIL_ERROR_NOTFOUND)
return -1;
/* \noselect mailbox */
}
ret = box->v.delete_box(box);
if (ret < 0 && box->marked_deleted) {
/* deletion failed. revert the mark so it can maybe be
tried again later. */
if (mailbox_mark_index_deleted(box, FALSE) < 0)
return -1;
}
box->deleting = FALSE;
mailbox_close(box);
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;
}
int mailbox_rename(struct mailbox *src, struct mailbox *dest)
{
const char *error = NULL;
if (mailbox_verify_existing_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 (!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;
}
return src->v.rename_box(src, dest);
}
int mailbox_set_subscribed(struct mailbox *box, bool set)
{
if (mailbox_verify_name(box) < 0)
return -1;
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;
}
int mailbox_get_status(struct mailbox *box,
enum mailbox_status_items items,
struct mailbox_status *status_r)
{
memset(status_r, 0, sizeof(*status_r));
if (mailbox_verify_existing_name(box) < 0)
return -1;
return box->v.get_status(box, items, status_r);
}
void mailbox_get_open_status(struct mailbox *box,
enum mailbox_status_items items,
struct mailbox_status *status_r)
{
i_assert(box->opened);
memset(status_r, 0, sizeof(*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)
{
memset(metadata_r, 0, sizeof(*metadata_r));
if (mailbox_verify_existing_name(box) < 0)
return -1;
if (box->metadata_pool != NULL)
p_clear(box->metadata_pool);
if (box->v.get_metadata(box, items, metadata_r) < 0)
return -1;
i_assert((items & MAILBOX_METADATA_GUID) == 0 ||
!guid_128_is_empty(metadata_r->guid));
return 0;
}
enum mail_flags mailbox_get_private_flags_mask(struct mailbox *box)
{
if (box->v.get_private_flags_mask != NULL)
return box->v.get_private_flags_mask(box);
else if (box->list->set.index_pvt_dir != NULL)
return MAIL_SEEN; /* FIXME */
else
return 0;
}
int mailbox_attribute_set(struct mailbox *box, enum mail_attribute_type type,
const char *key, const char *value)
{
return box->v.attribute_set(box, type, key, value);
}
int mailbox_attribute_unset(struct mailbox *box, enum mail_attribute_type type,
const char *key)
{
return box->v.attribute_set(box, type, key, NULL);
}
int mailbox_attribute_get(struct mailbox *box, enum mail_attribute_type type,
const char *key, const char **value_r)
{
return box->v.attribute_get(box, type, key, value_r);
}
struct mailbox_attribute_iter *
mailbox_attribute_iter_init(struct mailbox *box, enum mail_attribute_type type,
const char *prefix)
{
return box->v.attribute_iter_init(box, type, prefix);
}
const char *mailbox_attribute_iter_next(struct mailbox_attribute_iter *iter)
{
return iter->box->v.attribute_iter_next(iter);
}
int mailbox_attribute_iter_deinit(struct mailbox_attribute_iter **_iter)
{
struct mailbox_attribute_iter *iter = *_iter;
*_iter = NULL;
return iter->box->v.attribute_iter_deinit(iter);
}
struct mailbox_sync_context *
mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct mailbox_sync_context *ctx;
if (box->transaction_count != 0) {
i_panic("Trying to sync mailbox %s with open transactions",
box->name);
}
T_BEGIN {
ctx = box->v.sync_init(box, flags);
} T_END;
return ctx;
}
bool mailbox_sync_next(struct mailbox_sync_context *ctx,
struct mailbox_sync_rec *sync_rec_r)
{
return ctx->box->v.sync_next(ctx, sync_rec_r);
}
int mailbox_sync_deinit(struct mailbox_sync_context **_ctx,
struct mailbox_sync_status *status_r)
{
struct mailbox_sync_context *ctx = *_ctx;
struct mailbox *box = ctx->box;
const char *errormsg;
enum mail_error error;
int ret;
*_ctx = NULL;
memset(status_r, 0, sizeof(*status_r));
ret = box->v.sync_deinit(ctx, status_r);
if (ret < 0 && box->inbox_user &&
!box->storage->user->inbox_open_error_logged) {
errormsg = mailbox_get_last_error(box, &error);
if (error == MAIL_ERROR_NOTPOSSIBLE) {
box->storage->user->inbox_open_error_logged = TRUE;
i_error("Syncing INBOX failed: %s", errormsg);
}
}
if (ret == 0)
box->synced = TRUE;
return ret;
}
int mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct mailbox_sync_context *ctx;
struct mailbox_sync_status status;
if (array_count(&box->search_results) == 0) {
/* we don't care about mailbox's current state, so we might
as well fix inconsistency state */
flags |= MAILBOX_SYNC_FLAG_FIX_INCONSISTENT;
}
ctx = mailbox_sync_init(box, flags);
return mailbox_sync_deinit(&ctx, &status);
}
#undef mailbox_notify_changes
void mailbox_notify_changes(struct mailbox *box,
mailbox_notify_callback_t *callback, void *context)
{
i_assert(box->opened);
box->notify_callback = callback;
box->notify_context = context;
box->v.notify_changes(box);
}
void mailbox_notify_changes_stop(struct mailbox *box)
{
i_assert(box->opened);
box->notify_callback = NULL;
box->notify_context = NULL;
box->v.notify_changes(box);
}
struct mail_search_context *
mailbox_search_init(struct mailbox_transaction_context *t,
struct mail_search_args *args,
const enum mail_sort_type *sort_program,
enum mail_fetch_field wanted_fields,
struct mailbox_header_lookup_ctx *wanted_headers)
{
mail_search_args_ref(args);
if (!args->simplified)
mail_search_args_simplify(args);
return t->box->v.search_init(t, args, sort_program,
wanted_fields, wanted_headers);
}
int mailbox_search_deinit(struct mail_search_context **_ctx)
{
struct mail_search_context *ctx = *_ctx;
struct mail_search_args *args = ctx->args;
int ret;
*_ctx = NULL;
mailbox_search_results_initial_done(ctx);
ret = ctx->transaction->box->v.search_deinit(ctx);
mail_search_args_unref(&args);
return ret;
}
bool mailbox_search_next(struct mail_search_context *ctx, struct mail **mail_r)
{
bool tryagain;
while (!mailbox_search_next_nonblock(ctx, mail_r, &tryagain)) {
if (!tryagain)
return FALSE;
}
return TRUE;
}
bool mailbox_search_next_nonblock(struct mail_search_context *ctx,
struct mail **mail_r, bool *tryagain_r)
{
struct mailbox *box = ctx->transaction->box;
*mail_r = NULL;
if (!box->v.search_next_nonblock(ctx, mail_r, tryagain_r))
return FALSE;
else {
mailbox_search_results_add(ctx, (*mail_r)->uid);
return TRUE;
}
}
bool mailbox_search_seen_lost_data(struct mail_search_context *ctx)
{
return ctx->seen_lost_data;
}
int mailbox_search_result_build(struct mailbox_transaction_context *t,
struct mail_search_args *args,
enum mailbox_search_result_flags flags,
struct mail_search_result **result_r)
{
struct mail_search_context *ctx;
struct mail *mail;
int ret;
ctx = mailbox_search_init(t, args, NULL, 0, NULL);
*result_r = mailbox_search_result_save(ctx, flags);
while (mailbox_search_next(ctx, &mail)) ;
ret = mailbox_search_deinit(&ctx);
if (ret < 0)
mailbox_search_result_free(result_r);
return ret;
}
struct mailbox_transaction_context *
mailbox_transaction_begin(struct mailbox *box,
enum mailbox_transaction_flags flags)
{
struct mailbox_transaction_context *trans;
i_assert(box->opened);
box->transaction_count++;
trans = box->v.transaction_begin(box, flags);
trans->flags = flags;
return trans;
}
int mailbox_transaction_commit(struct mailbox_transaction_context **t)
{
struct mail_transaction_commit_changes changes;
int ret;
/* Store changes temporarily so that plugins overriding
transaction_commit() can look at them. */
ret = mailbox_transaction_commit_get_changes(t, &changes);
if (changes.pool != NULL)
pool_unref(&changes.pool);
return ret;
}
int mailbox_transaction_commit_get_changes(
struct mailbox_transaction_context **_t,
struct mail_transaction_commit_changes *changes_r)
{
struct mailbox_transaction_context *t = *_t;
int ret;
t->box->transaction_count--;
changes_r->pool = NULL;
*_t = NULL;
T_BEGIN {
ret = t->box->v.transaction_commit(t, changes_r);
} T_END;
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;
t->box->transaction_count--;
*_t = NULL;
t->box->v.transaction_rollback(t);
}
unsigned int mailbox_transaction_get_count(const struct mailbox *box)
{
return box->transaction_count;
}
void mailbox_transaction_set_max_modseq(struct mailbox_transaction_context *t,
uint64_t max_modseq,
ARRAY_TYPE(seq_range) *seqs)
{
mail_index_transaction_set_max_modseq(t->itrans, max_modseq, seqs);
}
struct mailbox *
mailbox_transaction_get_mailbox(const struct mailbox_transaction_context *t)
{
return t->box;
}
struct mail_save_context *
mailbox_save_alloc(struct mailbox_transaction_context *t)
{
struct mail_save_context *ctx;
ctx = t->box->v.save_alloc(t);
ctx->data.received_date = (time_t)-1;
ctx->data.save_date = (time_t)-1;
return ctx;
}
void mailbox_save_set_flags(struct mail_save_context *ctx,
enum mail_flags flags,
struct mail_keywords *keywords)
{
ctx->data.flags = flags;
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;
keywords_list = mail_get_keywords(mail);
ctx->data.keywords = str_array_length(keywords_list) == 0 ? NULL :
mailbox_keywords_create_valid(ctx->transaction->box,
keywords_list);
ctx->data.flags = mail_get_flags(mail);
}
void mailbox_save_set_min_modseq(struct mail_save_context *ctx,
uint64_t min_modseq)
{
ctx->data.min_modseq = min_modseq;
}
void mailbox_save_set_received_date(struct mail_save_context *ctx,
time_t received_date, int timezone_offset)
{
ctx->data.received_date = received_date;
ctx->data.received_tz_offset = timezone_offset;
}
void mailbox_save_set_save_date(struct mail_save_context *ctx,
time_t save_date)
{
ctx->data.save_date = save_date;
}
void mailbox_save_set_from_envelope(struct mail_save_context *ctx,
const char *envelope)
{
i_free(ctx->data.from_envelope);
ctx->data.from_envelope = i_strdup(envelope);
}
void mailbox_save_set_uid(struct mail_save_context *ctx, uint32_t uid)
{
ctx->data.uid = uid;
}
void mailbox_save_set_guid(struct mail_save_context *ctx, const char *guid)
{
i_assert(guid == NULL || *guid != '\0');
i_free(ctx->data.guid);
ctx->data.guid = i_strdup(guid);
}
void mailbox_save_set_pop3_uidl(struct mail_save_context *ctx, const char *uidl)
{
i_assert(*uidl != '\0');
i_assert(strchr(uidl, '\n') == NULL);
i_free(ctx->data.pop3_uidl);
ctx->data.pop3_uidl = i_strdup(uidl);
}
void mailbox_save_set_pop3_order(struct mail_save_context *ctx,
unsigned int order)
{
i_assert(order > 0);
ctx->data.pop3_order = order;
}
void mailbox_save_set_dest_mail(struct mail_save_context *ctx,
struct mail *mail)
{
ctx->dest_mail = mail;
}
int mailbox_save_begin(struct mail_save_context **ctx, struct istream *input)
{
struct mailbox *box = (*ctx)->transaction->box;
int ret;
if (mail_index_is_deleted(box->index)) {
mailbox_set_deleted(box);
return -1;
}
if (!(*ctx)->copying_via_save)
(*ctx)->saving = TRUE;
if (box->v.save_begin == NULL) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Saving messages not supported");
ret = -1;
} else {
ret = box->v.save_begin(*ctx, input);
}
if (ret < 0) {
mailbox_save_cancel(ctx);
return -1;
}
return 0;
}
int mailbox_save_continue(struct mail_save_context *ctx)
{
return ctx->transaction->box->v.save_continue(ctx);
}
int mailbox_save_finish(struct mail_save_context **_ctx)
{
struct mail_save_context *ctx = *_ctx;
struct mailbox *box = ctx->transaction->box;
struct mail_keywords *keywords = ctx->data.keywords;
int ret;
*_ctx = NULL;
ret = box->v.save_finish(ctx);
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
return ret;
}
void mailbox_save_cancel(struct mail_save_context **_ctx)
{
struct mail_save_context *ctx = *_ctx;
struct mail_keywords *keywords = ctx->data.keywords;
struct mail_private *mail;
*_ctx = NULL;
ctx->transaction->box->v.save_cancel(ctx);
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
if (ctx->dest_mail != NULL) {
/* the dest_mail is no longer valid. if we're still saving
more mails, the mail sequence may get reused. make sure
the mail gets reset in between */
mail = (struct mail_private *)ctx->dest_mail;
mail->v.close(&mail->mail);
}
}
struct mailbox_transaction_context *
mailbox_save_get_transaction(struct mail_save_context *ctx)
{
return ctx->transaction;
}
int mailbox_copy(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
struct mailbox *box = ctx->transaction->box;
struct mail_keywords *keywords = ctx->data.keywords;
struct mail *real_mail;
int ret;
*_ctx = NULL;
if (mail_index_is_deleted(box->index)) {
mailbox_set_deleted(box);
mailbox_save_cancel(&ctx);
return -1;
}
/* bypass virtual storage, so hard linking can be used whenever
possible */
real_mail = mail_get_real_mail(mail);
ret = ctx->transaction->box->v.copy(ctx, real_mail);
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
return ret;
}
int mailbox_move(struct mail_save_context **_ctx, struct mail *mail)
{
struct mail_save_context *ctx = *_ctx;
ctx->moving = TRUE;
if (mailbox_copy(_ctx, mail) < 0)
return -1;
mail_expunge(mail);
return 0;
}
int mailbox_save_using_mail(struct mail_save_context **ctx, struct mail *mail)
{
(*ctx)->saving = TRUE;
return mailbox_copy(ctx, mail);
}
bool mailbox_is_inconsistent(struct mailbox *box)
{
return box->mailbox_deleted || box->v.is_inconsistent(box);
}
void mailbox_set_deleted(struct mailbox *box)
{
mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
"Mailbox was deleted under us");
box->mailbox_deleted = TRUE;
}
int mailbox_get_path_to(struct mailbox *box, enum mailbox_list_path_type type,
const char **path_r)
{
int ret;
if (type == MAILBOX_LIST_PATH_TYPE_MAILBOX && box->_path != NULL) {
if (box->_path[0] == '\0') {
*path_r = NULL;
return 0;
}
*path_r = box->_path;
return 1;
}
ret = mailbox_list_get_path(box->list, box->name, type, path_r);
if (ret < 0) {
mail_storage_copy_list_error(box->storage, box->list);
return -1;
}
if (type == MAILBOX_LIST_PATH_TYPE_MAILBOX && box->_path == NULL)
box->_path = ret == 0 ? "" : p_strdup(box->pool, *path_r);
return ret;
}
const char *mailbox_get_path(struct mailbox *box)
{
i_assert(box->_path != NULL);
i_assert(box->_path[0] != '\0');
return box->_path;
}
static void mailbox_get_permissions_if_not_set(struct mailbox *box)
{
if (box->_perm.file_create_mode != 0)
return;
if (box->input != NULL) {
box->_perm.file_uid = geteuid();
box->_perm.file_create_mode = 0600;
box->_perm.dir_create_mode = 0700;
box->_perm.file_create_gid = (gid_t)-1;
box->_perm.file_create_gid_origin = "defaults";
return;
}
mailbox_list_get_permissions(box->list, box->name, &box->_perm);
box->_perm.file_create_gid_origin =
p_strdup(box->pool, box->_perm.file_create_gid_origin);
}
const struct mailbox_permissions *mailbox_get_permissions(struct mailbox *box)
{
mailbox_get_permissions_if_not_set(box);
if (!box->_perm.mail_index_permissions_set && box->index != NULL) {
box->_perm.mail_index_permissions_set = TRUE;
mail_index_set_permissions(box->index,
box->_perm.file_create_mode,
box->_perm.file_create_gid,
box->_perm.file_create_gid_origin);
}
return &box->_perm;
}
void mailbox_refresh_permissions(struct mailbox *box)
{
memset(&box->_perm, 0, sizeof(box->_perm));
(void)mailbox_get_permissions(box);
}
int mailbox_create_fd(struct mailbox *box, const char *path, int flags,
int *fd_r)
{
const struct mailbox_permissions *perm = mailbox_get_permissions(box);
mode_t old_mask;
int fd;
i_assert((flags & O_CREAT) != 0);
*fd_r = -1;
old_mask = umask(0);
fd = open(path, flags, perm->file_create_mode);
umask(old_mask);
if (fd != -1) {
/* ok */
} else if (errno == EEXIST) {
/* O_EXCL used, caller will handle this error */
return 0;
} else if (errno == ENOENT) {
mailbox_set_deleted(box);
return -1;
} else if (errno == ENOTDIR) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox doesn't allow inferior mailboxes");
return -1;
} else if (mail_storage_set_error_from_errno(box->storage)) {
return -1;
} else {
mail_storage_set_critical(box->storage,
"open(%s, O_CREAT) failed: %m", path);
return -1;
}
if (perm->file_create_gid != (gid_t)-1) {
if (fchown(fd, (uid_t)-1, perm->file_create_gid) == 0) {
/* ok */
} else if (errno == EPERM) {
mail_storage_set_critical(box->storage, "%s",
eperm_error_get_chgrp("fchown", path,
perm->file_create_gid,
perm->file_create_gid_origin));
} else {
mail_storage_set_critical(box->storage,
"fchown(%s) failed: %m", path);
}
}
*fd_r = fd;
return 1;
}
int mailbox_mkdir(struct mailbox *box, const char *path,
enum mailbox_list_path_type type)
{
const struct mailbox_permissions *perm = mailbox_get_permissions(box);
const char *root_dir;
if (!perm->gid_origin_is_mailbox_path) {
/* mailbox root directory doesn't exist, create it */
root_dir = mailbox_list_get_root_forced(box->list, type);
if (mailbox_list_mkdir_root(box->list, root_dir, type) < 0) {
mail_storage_copy_list_error(box->storage, box->list);
return -1;
}
}
if (mkdir_parents_chgrp(path, perm->dir_create_mode,
perm->file_create_gid,
perm->file_create_gid_origin) == 0)
return 1;
else if (errno == EEXIST)
return 0;
else if (errno == ENOTDIR) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox doesn't allow inferior mailboxes");
return -1;
} else if (mail_storage_set_error_from_errno(box->storage)) {
return -1;
} else {
mail_storage_set_critical(box->storage,
"mkdir_parents(%s) failed: %m", path);
return -1;
}
}
int mailbox_create_missing_dir(struct mailbox *box,
enum mailbox_list_path_type type)
{
const char *mail_dir, *dir;
struct stat st;
int ret;
if ((ret = mailbox_get_path_to(box, type, &dir)) <= 0)
return ret;
if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
&mail_dir) < 0)
return -1;
if (null_strcmp(dir, mail_dir) == 0) {
if ((box->list->props & MAILBOX_LIST_PROP_AUTOCREATE_DIRS) == 0)
return 0;
/* the directory might not have been created yet */
}
/* we call this function even when the directory exists, so first do a
quick check to see if we need to mkdir anything */
if (stat(dir, &st) == 0)
return 0;
return mailbox_mkdir(box, dir, type);
}
unsigned int mail_storage_get_lock_timeout(struct mail_storage *storage,
unsigned int secs)
{
return storage->set->mail_max_lock_timeout == 0 ? secs :
I_MIN(secs, storage->set->mail_max_lock_timeout);
}
enum mail_index_open_flags
mail_storage_settings_to_index_flags(const struct mail_storage_settings *set)
{
enum mail_index_open_flags index_flags = 0;
#ifndef MMAP_CONFLICTS_WRITE
if (set->mmap_disable)
#endif
index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
if (set->dotlock_use_excl)
index_flags |= MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL;
if (set->mail_nfs_index)
index_flags |= MAIL_INDEX_OPEN_FLAG_NFS_FLUSH;
return index_flags;
}