mail-storage.c revision 7baab0b0b60df7ce9093d0881cd322dff1e79491
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "ioloop.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "array.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "llist.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "unichar.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "istream.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "eacces-error.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "mkdir-parents.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "var-expand.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "mail-index-private.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "mail-index-alloc-cache.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "mailbox-list-private.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "mail-storage-private.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "mail-storage-settings.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "mail-namespace.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "mail-search.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "mail-search-register.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "mailbox-search-result-private.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <stdlib.h>
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen#include <ctype.h>
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen#define MAILBOX_DELETE_RETRY_SECS (60*5)
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainenextern struct mail_search_register *mail_search_register_imap;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenextern struct mail_search_register *mail_search_register_human;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstruct mail_module_register mail_module_register = { 0 };
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo SirainenARRAY_TYPE(mail_storage) mail_storage_classes;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenvoid mail_storage_init(void)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen mailbox_lists_init();
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen mail_storage_hooks_init();
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen i_array_init(&mail_storage_classes, 8);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenvoid mail_storage_deinit(void)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen if (mail_search_register_human != NULL)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen mail_search_register_deinit(&mail_search_register_human);
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen if (mail_search_register_imap != NULL)
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen mail_search_register_deinit(&mail_search_register_imap);
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen if (array_is_created(&mail_storage_classes))
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen array_free(&mail_storage_classes);
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen mail_storage_hooks_deinit();
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen mailbox_lists_deinit();
59e26ff34b05cd971a111f8a42fc60c13d9f688bTimo Sirainen}
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
f988b93c2ef773987bcdcbfb4cca39b955e3a392Timo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen /* append it after the list, so the autodetection order is correct */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen{
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen struct mail_storage *const *classes;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen unsigned int i, count;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen classes = array_get(&mail_storage_classes, &count);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen for (i = 0; i < count; i++) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (classes[i] == storage_class) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen array_delete(&mail_storage_classes, i, 1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
571fd6ff94570ee11a72a20b649acfdac2495919Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct mail_storage *const *classes;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen unsigned int i, count;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_assert(name != NULL);
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen classes = array_get(&mail_storage_classes, &count);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen for (i = 0; i < count; i++) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (strcasecmp(classes[i]->name, name) == 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return classes[i];
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen }
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen return NULL;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen}
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainenstatic struct mail_storage *
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen struct mailbox_list_settings *set)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen{
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen struct mail_storage *const *classes;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen unsigned int i, count;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen classes = array_get(&mail_storage_classes, &count);
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen for (i = 0; i < count; i++) {
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen if (classes[i]->v.autodetect != NULL) {
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen if (classes[i]->v.autodetect(ns, set))
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return classes[i];
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char *p;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen p = *data;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen while (i_isalnum(*p)) p++;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen if (*p == ':' && p != *data) {
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen /* no autodetection if the storage driver is given. */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen *driver = t_strdup_until(*data, p);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen *data = p + 1;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen }
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen}
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic struct mail_storage *
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mailbox_list_settings *list_set,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen enum mail_storage_flags flags, const char **error_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen struct mail_storage *storage_class = NULL;
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen const char *home;
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen if (driver != NULL) {
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen storage_class = mail_storage_find_class(driver);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (storage_class == NULL) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *error_r = t_strdup_printf(
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen "Unknown mail storage driver %s", driver);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return NULL;
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (list_set->root_dir == NULL || *list_set->root_dir == '\0') {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* no root directory given. is this allowed? */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const struct mailbox_list *list;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen list = list_set->layout == NULL ? NULL :
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen mailbox_list_find_class(list_set->layout);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (storage_class == NULL &&
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen (flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* autodetection should take care of this */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else if (storage_class != NULL &&
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* root not required for this storage */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else if (list != NULL &&
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen (list->props & MAILBOX_LIST_PROP_NO_ROOT) != 0) {
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen /* root not required for this layout */
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen } else {
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen *error_r = "Root mail directory not given";
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen return NULL;
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen }
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (storage_class != NULL) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen storage_class->v.get_list_settings(ns, list_set);
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen return storage_class;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (storage_class != NULL)
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen return storage_class;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (void)mail_user_get_home(ns->user, &home);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen *error_r = t_strdup_printf(
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "Mail storage autodetection failed with home=%s", home);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen *error_r = t_strdup_printf(
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen "Ambiguous mail location setting, "
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen "don't know what to do with it: %s "
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen "(try prefixing it with mbox: or maildir:)",
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen ns->set->location);
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen }
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen return NULL;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainenstatic int
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenmail_storage_verify_root(const char *root_dir, bool autocreate,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char **error_r)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct stat st;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (stat(root_dir, &st) == 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* exists */
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen return 1;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen } else if (errno == EACCES) {
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen return -1;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen } else if (errno != ENOENT && errno != ENOTDIR) {
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen return -1;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen } else if (!autocreate) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen *error_r = t_strdup_printf(
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "Root mail directory doesn't exist: %s", root_dir);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else {
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen /* doesn't exist */
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenmail_storage_create_root(struct mailbox_list *list,
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen enum mail_storage_flags flags, const char **error_r)
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen{
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen const char *root_dir, *origin, *error;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen mode_t file_mode, dir_mode;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen gid_t gid;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen bool autocreate;
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen int ret;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen root_dir = mailbox_list_get_path(list, NULL,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch if (root_dir == NULL) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* storage doesn't use directories (e.g. shared root) */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 0;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOVERIFY) != 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (!list->mail_set->mail_debug)
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen return 0;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen /* we don't need to verify, but since debugging is
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen enabled, check and log if the root doesn't exist */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (mail_storage_verify_root(root_dir, FALSE, &error) < 0) {
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen i_debug("Namespace %s: Creating storage despite: %s",
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen list->ns->prefix, error);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 0;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen autocreate = (flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) == 0;
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen ret = mail_storage_verify_root(root_dir, autocreate, error_r);
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen if (ret != 0)
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen return ret;
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen /* we need to create the root directory. */
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen mailbox_list_get_root_permissions(list, &file_mode, &dir_mode,
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen &gid, &origin);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen if (mkdir_parents_chgrp(root_dir, dir_mode, gid, origin) < 0 &&
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen errno != EEXIST) {
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen *error_r = mail_error_create_eacces_msg("mkdir", root_dir);
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen return -1;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen } else {
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen /* created */
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen return 0;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic struct mail_storage *
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainenmail_storage_find(struct mail_user *user,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen const struct mail_storage *storage_class,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen const struct mailbox_list_settings *set)
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen{
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen struct mail_storage *storage = user->storages;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen for (; storage != NULL; storage = storage->next) {
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (strcmp(storage->name, storage_class->name) == 0 &&
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen ((storage->class_flags &
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) == 0 ||
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen strcmp(storage->unique_root_dir, set->root_dir) == 0))
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen return storage;
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen }
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen return NULL;
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen}
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen enum mail_storage_flags flags, const char **error_r)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct mail_storage *storage_class, *storage = NULL;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct mailbox_list_settings list_set;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch enum mailbox_list_flags list_flags = 0;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen const char *data = ns->set->location;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen const char *p;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
4e8d6d03c2ff85448df79b181a2ea850fb5d4199Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen ns->mail_set->pop3_uidl_format != NULL) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen header MD5 sums stored even if we're not running POP3
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen right now. */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen p = ns->mail_set->pop3_uidl_format;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen while ((p = strchr(p, '%')) != NULL) {
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (p[1] == '%')
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen p += 2;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen else if (var_get_key(++p) == 'm') {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen break;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen }
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen memset(&list_set, 0, sizeof(list_set));
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (data == NULL) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* autodetect */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* internal shared namespace */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen list_set.root_dir = ns->user->set->base_dir;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen } else {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (driver == NULL)
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen mail_storage_set_autodetection(&data, &driver);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (mailbox_list_settings_parse(ns->user, data, &list_set,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen error_r) < 0)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return -1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, flags,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen error_r);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (storage_class == NULL)
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen return -1;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen i_assert(list_set.layout != NULL);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (ns->list == NULL) {
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen /* first storage for namespace */
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (mail_storage_is_mailbox_file(storage_class))
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
f988b93c2ef773987bcdcbfb4cca39b955e3a392Timo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen list_flags, error_r) < 0) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen *error_r = t_strdup_printf("Mailbox list driver %s: %s",
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen list_set.layout, *error_r);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return -1;
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen }
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen return -1;
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (storage != NULL) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* using an existing storage */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen storage->refcount++;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen mail_namespace_add_storage(ns, storage);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return 0;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen storage = storage_class->v.alloc();
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen storage->refcount = 1;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen storage->storage_class = storage_class;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen storage->user = ns->user;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen storage->set = ns->mail_set;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen storage->flags = flags;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen storage->list_sync_ext_id = (uint32_t)-1;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (storage->v.create != NULL &&
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen storage->v.create(storage, ns, error_r) < 0) {
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen pool_unref(&storage->pool);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen return -1;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen T_BEGIN {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen hook_mail_storage_created(storage);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen } T_END;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen DLLIST_PREPEND(&ns->user->storages, storage);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen mail_namespace_add_storage(ns, storage);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return 0;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen}
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen{
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen struct mail_storage *storage = *_storage;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(storage->refcount > 0);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* set *_storage=NULL only after calling destroy() callback.
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen for example mdbox wants to access ns->storage */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (--storage->refcount > 0) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen *_storage = NULL;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen return;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen }
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen if (storage->obj_refcount != 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_panic("Trying to deinit storage before freeing its objects");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen DLLIST_REMOVE(&storage->user->storages, storage);
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen if (storage->v.destroy != NULL)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen storage->v.destroy(storage);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_free(storage->error_string);
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen *_storage = NULL;
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen pool_unref(&storage->pool);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen mail_index_alloc_cache_destroy_unrefed();
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen}
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainenvoid mail_storage_obj_ref(struct mail_storage *storage)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen{
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen i_assert(storage->refcount > 0);
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen storage->obj_refcount++;
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen}
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenvoid mail_storage_obj_unref(struct mail_storage *storage)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen{
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(storage->refcount > 0);
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen i_assert(storage->obj_refcount > 0);
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen storage->obj_refcount--;
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen}
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen{
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen i_free_and_null(storage->error_string);
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen storage->error = MAIL_ERROR_NONE;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen}
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen enum mail_error error, const char *string)
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen{
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen i_free(storage->error_string);
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen storage->error_string = i_strdup(string);
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen storage->error = error;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen}
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen{
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen struct tm *tm;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen char str[256];
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen tm = localtime(&ioloop_time);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen i_free(storage->error_string);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen storage->error_string =
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen strftime(str, sizeof(str),
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen MAIL_ERRSTR_CRITICAL_MSG_STAMP, tm) > 0 ?
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen i_strdup(str) : i_strdup(MAIL_ERRSTR_CRITICAL_MSG);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen storage->error = MAIL_ERROR_TEMP;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen}
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen const char *fmt, ...)
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen{
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen va_list va;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen mail_storage_clear_error(storage);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (fmt != NULL) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen va_start(va, fmt);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_error("%s", t_strdup_vprintf(fmt, va));
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen va_end(va);
71da447014454c84828d9dface77219875554d7dTimo Sirainen
71da447014454c84828d9dface77219875554d7dTimo Sirainen /* critical errors may contain sensitive data, so let user
71da447014454c84828d9dface77219875554d7dTimo Sirainen see only "Internal error" with a timestamp to make it
71da447014454c84828d9dface77219875554d7dTimo Sirainen easier to look from log files the actual error message. */
71da447014454c84828d9dface77219875554d7dTimo Sirainen mail_storage_set_internal_error(storage);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenvoid mail_storage_copy_list_error(struct mail_storage *storage,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen struct mailbox_list *list)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen const char *str;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen enum mail_error error;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen str = mailbox_list_get_last_error(list, &error);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen mail_storage_set_error(storage, error, str);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid mail_storage_set_index_error(struct mailbox *box)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (mail_index_is_deleted(box->index))
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mailbox_set_deleted(box);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen else
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mail_storage_set_internal_error(box->storage);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mail_index_reset_error(box->index);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenconst struct mail_storage_settings *
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenmail_storage_get_settings(struct mail_storage *storage)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return storage->set;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstruct mail_user *mail_storage_get_user(struct mail_storage *storage)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return storage->user;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid mail_storage_set_callbacks(struct mail_storage *storage,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mail_storage_callbacks *callbacks,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen void *context)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen storage->callbacks = *callbacks;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen storage->callback_context = context;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenint mail_storage_purge(struct mail_storage *storage)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return storage->v.purge == NULL ? 0 :
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen storage->v.purge(storage);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenconst char *mail_storage_get_last_error(struct mail_storage *storage,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen enum mail_error *error_r)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* We get here only in error situations, so we have to return some
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen error. If storage->error is NONE, it means we forgot to set it at
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen some point.. */
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen if (storage->error == MAIL_ERROR_NONE) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (error_r != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen *error_r = MAIL_ERROR_TEMP;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen return storage->error_string != NULL ? storage->error_string :
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen "BUG: Unknown internal error";
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen }
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen if (storage->error_string == NULL) {
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen /* This shouldn't happen.. */
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen storage->error_string =
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen i_strdup_printf("BUG: Unknown 0x%x error",
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen storage->error);
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen }
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen if (error_r != NULL)
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen *error_r = storage->error;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen return storage->error_string;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen}
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainenconst char *mailbox_get_last_error(struct mailbox *box,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen enum mail_error *error_r)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return mail_storage_get_last_error(box->storage, error_r);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenenum mail_error mailbox_get_last_mail_error(struct mailbox *box)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen enum mail_error error;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (void)mail_storage_get_last_error(box->storage, &error);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return error;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenbool mail_storage_is_mailbox_file(struct mail_storage *storage)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return (storage->class_flags &
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE) != 0;
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainenbool mail_storage_set_error_from_errno(struct mail_storage *storage)
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen{
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen const char *error_string;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen enum mail_error error;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return FALSE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* debugging is enabled - admin may be debugging a
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (permission) problem, so return FALSE to get the caller to
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen log the full error message. */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return FALSE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mail_storage_set_error(storage, error, error_string);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return TRUE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstruct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen enum mailbox_flags flags)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mailbox_list *new_list = list;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mail_storage *storage;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mailbox *box;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
d78be924ad150840e018eda6a8a7d5e46a39bda2Timo Sirainen i_assert(uni_utf8_str_is_valid(vname));
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (strcasecmp(vname, "INBOX") == 0 &&
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen /* make sure INBOX shows up in uppercase everywhere */
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen vname = "INBOX";
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen }
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen if (mailbox_list_get_storage(&new_list, vname, &storage) < 0) {
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen /* just use the first storage. FIXME: does this break? */
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen storage = list->ns->storage;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen }
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen T_BEGIN {
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen box = storage->v.mailbox_alloc(storage, new_list, vname, flags);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen hook_mailbox_allocated(box);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen } T_END;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mail_storage_obj_ref(box->storage);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return box;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic bool have_listable_namespace_prefix(struct mail_namespace *ns,
d78be924ad150840e018eda6a8a7d5e46a39bda2Timo Sirainen const char *name)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen unsigned int name_len = strlen(name);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen for (; ns != NULL; ns = ns->next) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen continue;
46631c1d903c409444b1b1c4a1d41a033c09ee37Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (ns->prefix_len <= name_len)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen continue;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* if prefix has multiple hierarchies, match
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen any of the hierarchies */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (strncmp(ns->prefix, name, name_len) == 0 &&
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ns->prefix[name_len] == mail_namespace_get_sep(ns))
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return TRUE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen return FALSE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenint mailbox_exists(struct mailbox *box, enum mailbox_existence *existence_r)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen if (!mailbox_list_is_valid_existing_name(box->list, box->name)) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen "Invalid mailbox name");
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen return -1;
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen }
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen if (have_listable_namespace_prefix(box->storage->user->namespaces,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen box->vname)) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* listable namespace prefix always exists */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen *existence_r = MAILBOX_EXISTENCE_NOSELECT;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return 0;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return box->v.exists(box, existence_r);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int mailbox_check_mismatching_separators(struct mailbox *box)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mail_namespace *ns = box->list->ns;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen const char *p, *vname = box->vname;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen char list_sep, ns_sep;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen list_sep = mailbox_list_get_hierarchy_sep(box->list);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ns_sep = mail_namespace_get_sep(ns);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (ns_sep == list_sep)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return 0;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (ns->prefix_len > 0) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* vname is prefix with or without separator */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_assert(strncmp(vname, ns->prefix, ns->prefix_len-1) == 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen vname += ns->prefix_len - 1;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (vname[0] != '\0') {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_assert(vname[0] == ns->prefix[ns->prefix_len-1]);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen vname++;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen for (p = vname; *p != '\0'; p++) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (*p == list_sep) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen t_strdup_printf("NO Character not allowed "
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen "in mailbox name: '%c'",
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen list_sep));
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return -1;
71da447014454c84828d9dface77219875554d7dTimo Sirainen }
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen }
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen return 0;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen}
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainenstatic int mailbox_open_full(struct mailbox *box, struct istream *input)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen{
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen int ret;
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen if (box->opened)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen return 0;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen if (mailbox_check_mismatching_separators(box) < 0)
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen return -1;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen if (!mailbox_list_is_valid_existing_name(box->list, box->name)) {
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen "Invalid mailbox name");
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen return -1;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen }
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen if (input != NULL) {
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen if ((box->storage->class_flags &
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) == 0) {
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen mail_storage_set_critical(box->storage,
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen "Storage doesn't support streamed mailboxes");
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen return -1;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen }
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen box->input = input;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen box->flags |= MAILBOX_FLAG_READONLY;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen i_stream_ref(box->input);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen }
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen T_BEGIN {
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen ret = box->v.open(box);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen } T_END;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen if (ret < 0 && box->storage->error == MAIL_ERROR_NOTFOUND &&
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen box->input == NULL && box->inbox_user) T_BEGIN {
/* INBOX should always exist. try to create it and retry. */
(void)mailbox_create(box, NULL, FALSE);
mailbox_close(box);
ret = box->v.open(box);
if (ret < 0 && !box->storage->user->inbox_open_error_logged) {
box->storage->user->inbox_open_error_logged = TRUE;
i_error("Opening INBOX failed: %s",
mailbox_get_last_error(box, NULL));
}
} T_END;
if (ret < 0) {
if (box->input != NULL)
i_stream_unref(&box->input);
return -1;
}
box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
return 0;
}
int mailbox_open(struct mailbox *box)
{
return mailbox_open_full(box, NULL);
}
int mailbox_open_stream(struct mailbox *box, struct istream *input)
{
return mailbox_open_full(box, input);
}
int mailbox_enable(struct mailbox *box, enum mailbox_feature features)
{
return box->v.enable(box, features);
}
enum mailbox_feature mailbox_get_enabled_features(struct mailbox *box)
{
return box->enabled_features;
}
void mailbox_close(struct mailbox *box)
{
if (!box->opened)
return;
if (box->transaction_count != 0) {
i_panic("Trying to close mailbox %s with open transactions",
box->name);
}
box->v.close(box);
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);
mail_storage_obj_unref(box->storage);
pool_unref(&box->pool);
}
int mailbox_create(struct mailbox *box, const struct mailbox_update *update,
bool directory)
{
enum mailbox_dir_create_type type;
int ret;
if (!mailbox_list_is_valid_create_name(box->list, box->name)) {
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
"Invalid mailbox name");
return -1;
}
type = directory ? MAILBOX_DIR_CREATE_TYPE_TRY_NOSELECT :
MAILBOX_DIR_CREATE_TYPE_MAILBOX;
if (box->list->v.create_mailbox_dir(box->list, box->name, type) < 0) {
mail_storage_copy_list_error(box->storage, box->list);
if (directory ||
mailbox_get_last_mail_error(box) != MAIL_ERROR_EXISTS)
return -1;
/* the directory already exists, but the mailbox might not */
}
mailbox_refresh_permissions(box);
box->creating = TRUE;
ret = box->v.create(box, update, directory);
box->creating = FALSE;
return ret;
}
int mailbox_update(struct mailbox *box, const struct mailbox_update *update)
{
return box->v.update(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) {
mail_storage_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;
}
static bool mailbox_try_undelete(struct mailbox *box)
{
time_t mtime;
if (mail_index_get_modification_time(box->index, &mtime) < 0)
return FALSE;
if (mtime + MAILBOX_DELETE_RETRY_SECS > time(NULL))
return FALSE;
if (mailbox_mark_index_deleted(box, FALSE) < 0)
return FALSE;
box->mailbox_deleted = FALSE;
return TRUE;
}
int mailbox_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;
if (!box->mailbox_deleted) {
/* \noselect mailbox */
} else {
/* if deletion happened a long time ago, it means it
crashed while doing it. undelete the mailbox in
that case. */
if (!mailbox_try_undelete(box))
return -1;
/* retry */
if (mailbox_open(box) < 0)
return -1;
}
}
ret = box->v.delete(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;
}
static bool
mail_storages_rename_compatible(struct mail_storage *storage1,
struct mail_storage *storage2)
{
if (storage1 == storage2)
return TRUE;
if (strcmp(storage1->name, storage2->name) != 0)
return FALSE;
if ((storage1->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0)
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)
{
return nullequals(list1->set.alt_dir, list2->set.alt_dir) &&
nullequals(list1->set.index_dir, list2->set.index_dir) &&
nullequals(list1->set.control_dir, list2->set.control_dir);
}
int mailbox_rename(struct mailbox *src, struct mailbox *dest,
bool rename_children)
{
if (!mailbox_list_is_valid_existing_name(src->list, src->name) ||
*src->name == '\0' ||
!mailbox_list_is_valid_create_name(dest->list, dest->name)) {
mail_storage_set_error(src->storage, MAIL_ERROR_PARAMS,
"Invalid mailbox name");
return -1;
}
if (!mail_storages_rename_compatible(src->storage, dest->storage) ||
!mailbox_lists_rename_compatible(src->list, dest->list)) {
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 != NAMESPACE_PRIVATE ||
dest->list->ns->type != NAMESPACE_PRIVATE)) {
mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
"Renaming not supported across non-private namespaces.");
return -1;
}
return src->v.rename(src, dest, rename_children);
}
int mailbox_set_subscribed(struct mailbox *box, bool set)
{
struct mail_namespace *ns;
struct mailbox_list *list = box->list;
const char *subs_name;
if (!mailbox_list_is_valid_existing_name(list, box->name)) {
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
"Invalid mailbox name");
return -1;
}
if ((list->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0)
subs_name = box->name;
else {
/* subscriptions=no namespace, find another one where we can
add the subscription to */
ns = mail_namespace_find_subscribable(list->ns->user->namespaces,
box->vname);
if (ns == NULL) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"This namespace has no subscriptions");
return -1;
}
/* use <orig ns prefix><orig storage name> as the
subscription name */
subs_name = t_strconcat(list->ns->prefix, box->name, NULL);
/* drop the common prefix (typically there isn't one) */
i_assert(strncmp(ns->prefix, subs_name, strlen(ns->prefix)) == 0);
subs_name += strlen(ns->prefix);
list = ns->list;
}
return mailbox_list_set_subscribed(list, subs_name, set);
}
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)
{
return box->v.is_readonly(box);
}
bool mailbox_allow_new_keywords(struct mailbox *box)
{
return box->v.allow_new_keywords(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)
{
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);
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)
{
if (!box->opened) {
if (mailbox_open(box) < 0)
return -1;
}
if (box->v.get_metadata(box, items, metadata_r) < 0)
return -1;
i_assert((items & MAILBOX_METADATA_GUID) == 0 ||
!mail_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 0;
else
return box->v.get_private_flags_mask(box);
}
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);
}
}
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, unsigned int min_interval,
mailbox_notify_callback_t *callback, void *context)
{
box->notify_min_interval = min_interval;
box->notify_callback = callback;
box->notify_context = context;
box->v.notify_changes(box);
}
void mailbox_notify_changes_stop(struct mailbox *box)
{
mailbox_notify_changes(box, 0, NULL, NULL);
}
struct mail_search_context *
mailbox_search_init(struct mailbox_transaction_context *t,
struct mail_search_args *args,
const enum mail_sort_type *sort_program)
{
mail_search_args_ref(args);
if (!args->simplified)
mail_search_args_simplify(args);
return t->box->v.search_init(t, args, sort_program);
}
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)
{
bool tryagain;
while (!mailbox_search_next_nonblock(ctx, mail, &tryagain)) {
if (!tryagain)
return FALSE;
}
return TRUE;
}
bool mailbox_search_next_nonblock(struct mail_search_context *ctx,
struct mail *mail, bool *tryagain_r)
{
struct mailbox *box = ctx->transaction->box;
if (!box->v.search_next_nonblock(ctx, mail, tryagain_r))
return FALSE;
else {
mailbox_search_results_add(ctx, mail->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);
*result_r = mailbox_search_result_save(ctx, flags);
mail = mail_alloc(t, 0, NULL);
while (mailbox_search_next(ctx, mail)) ;
mail_free(&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;
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. */
changes.pool = NULL;
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--;
*_t = NULL;
T_BEGIN {
ret = t->box->v.transaction_commit(t, changes_r);
} T_END;
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->received_date = (time_t)-1;
ctx->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->flags = flags;
ctx->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->keywords = str_array_length(keywords_list) == 0 ? NULL :
mailbox_keywords_create_valid(ctx->transaction->box,
keywords_list);
ctx->flags = mail_get_flags(mail);
}
void mailbox_save_set_min_modseq(struct mail_save_context *ctx,
uint64_t min_modseq)
{
ctx->min_modseq = min_modseq;
}
void mailbox_save_set_received_date(struct mail_save_context *ctx,
time_t received_date, int timezone_offset)
{
ctx->received_date = received_date;
ctx->received_tz_offset = timezone_offset;
}
void mailbox_save_set_save_date(struct mail_save_context *ctx,
time_t save_date)
{
ctx->save_date = save_date;
}
void mailbox_save_set_from_envelope(struct mail_save_context *ctx,
const char *envelope)
{
i_free(ctx->from_envelope);
ctx->from_envelope = i_strdup(envelope);
}
void mailbox_save_set_uid(struct mail_save_context *ctx, uint32_t uid)
{
ctx->uid = uid;
}
void mailbox_save_set_guid(struct mail_save_context *ctx, const char *guid)
{
i_assert(guid == NULL || *guid != '\0');
i_free(ctx->guid);
ctx->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->pop3_uidl);
ctx->pop3_uidl = i_strdup(uidl);
}
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 (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->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->keywords;
*_ctx = NULL;
ctx->transaction->box->v.save_cancel(ctx);
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
}
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->keywords;
int ret;
*_ctx = NULL;
if (mail_index_is_deleted(box->index)) {
mailbox_set_deleted(box);
mailbox_save_cancel(_ctx);
return -1;
}
ret = ctx->transaction->box->v.copy(ctx, mail);
if (keywords != NULL)
mailbox_keywords_unref(&keywords);
return ret;
}
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;
}
const char *mailbox_get_path(struct mailbox *box)
{
const char *path;
if (box->_path == NULL) {
path = mailbox_list_get_path(box->list, box->name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
box->_path = p_strdup(box->pool, path);
}
return box->_path;
}
static void mailbox_get_permissions_if_not_set(struct mailbox *box)
{
const char *origin;
if (box->_perm.file_create_mode != 0)
return;
if (box->input != NULL) {
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.file_create_mode,
&box->_perm.dir_create_mode,
&box->_perm.file_create_gid, &origin);
box->_perm.file_create_gid_origin = p_strdup(box->pool, 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;
}
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);
}