mail-storage.c revision 0cb1eb9a12488be403e4179877c31729efaa3c2f
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "lib.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "ioloop.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "array.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "llist.h"
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen#include "istream.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "eacces-error.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "mkdir-parents.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "var-expand.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "mail-index-private.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "mail-index-alloc-cache.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "mailbox-list-private.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "mail-storage-private.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "mail-storage-settings.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "mail-namespace.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "mail-search.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "mailbox-search-result-private.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include <stdlib.h>
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include <ctype.h>
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#define MAILBOX_DELETE_RETRY_SECS (60*5)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstruct mail_module_register mail_module_register = { 0 };
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo SirainenARRAY_TYPE(mail_storage) mail_storage_classes;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenvoid mail_storage_init(void)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mailbox_lists_init();
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen mail_storage_hooks_init();
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_array_init(&mail_storage_classes, 8);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenvoid mail_storage_deinit(void)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (array_is_created(&mail_storage_classes))
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen array_free(&mail_storage_classes);
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen mail_storage_hooks_deinit();
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mailbox_lists_deinit();
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen i_assert(mail_storage_find_class(storage_class->name) == NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen /* append it after the list, so the autodetection order is correct */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_append(&mail_storage_classes, &storage_class, 1);
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_storage *const *classes;
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen unsigned int i, count;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen classes = array_get(&mail_storage_classes, &count);
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen for (i = 0; i < count; i++) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if (classes[i] == storage_class) {
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen array_delete(&mail_storage_classes, i, 1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen break;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen}
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainenstruct mail_storage *mail_storage_find_class(const char *name)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_storage *const *classes;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen unsigned int i, count;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(name != NULL);
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen classes = array_get(&mail_storage_classes, &count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (i = 0; i < count; i++) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (strcasecmp(classes[i]->name, name) == 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return classes[i];
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return NULL;
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen}
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainenstatic struct mail_storage *
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainenmail_storage_autodetect(const struct mail_namespace *ns,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mailbox_list_settings *set)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_storage *const *classes;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen unsigned int i, count;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen classes = array_get(&mail_storage_classes, &count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (i = 0; i < count; i++) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (classes[i]->v.autodetect != NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (classes[i]->v.autodetect(ns, set))
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return classes[i];
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return NULL;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic void
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenmail_storage_set_autodetection(const char **data, const char **driver)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const char *p;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p = *data;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen while (i_isalnum(*p)) p++;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (*p == ':' && p != *data) {
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen /* no autodetection if the storage driver is given. */
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen *driver = t_strdup_until(*data, p);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen *data = p + 1;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen }
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen}
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenstatic struct mail_storage *
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenmail_storage_get_class(struct mail_namespace *ns, const char *driver,
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen struct mailbox_list_settings *list_set,
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen const char **error_r)
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen{
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen struct mail_storage *storage_class;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen const char *home;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (driver != NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen storage_class = mail_storage_find_class(driver);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (storage_class == NULL) {
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen *error_r = t_strdup_printf(
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "Unknown mail storage driver %s", driver);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return NULL;
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen }
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen i_assert(list_set->root_dir != NULL);
a5e89374cb2fb2cad575fee6c3b33a9487ab9b3aTimo Sirainen storage_class->v.get_list_settings(ns, list_set);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return storage_class;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen storage_class = mail_storage_autodetect(ns, list_set);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (storage_class != NULL)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return storage_class;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (ns->set->location == NULL || *ns->set->location == '\0') {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen (void)mail_user_get_home(ns->user, &home);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen *error_r = t_strdup_printf(
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "Mail storage autodetection failed with home=%s", home);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen *error_r = t_strdup_printf(
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "Ambiguous mail location setting, "
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen "don't know what to do with it: %s "
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "(try prefixing it with mbox: or maildir:)",
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ns->set->location);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return NULL;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic int
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenmail_storage_create_root(struct mailbox_list *list,
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen enum mail_storage_flags flags, const char **error_r)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen const char *root_dir, *origin;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen struct stat st;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mode_t mode;
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen gid_t gid;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen root_dir = mailbox_list_get_path(list, NULL,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (root_dir == NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* storage doesn't use directories (e.g. shared root) */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (stat(root_dir, &st) == 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* ok */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else if (errno == EACCES) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen *error_r = mail_error_eacces_msg("stat", root_dir);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return -1;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen } else if (errno != ENOENT && errno != ENOTDIR) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen return -1;
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainen } else if (list->ns->type == NAMESPACE_SHARED) {
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainen /* can't create a new user, but we don't want to fail
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen the storage creation. */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen *error_r = t_strdup_printf(
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "Root mail directory doesn't exist: %s", root_dir);
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen return -1;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen }
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen /* we need to create the root directory. */
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainen mailbox_list_get_dir_permissions(list, NULL, &mode, &gid, &origin);
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen if (mkdir_parents_chgrp(root_dir, mode, gid, origin) < 0 &&
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen errno != EEXIST) {
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen *error_r = mail_error_create_eacces_msg("mkdir", root_dir);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen } else {
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen /* created */
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen return 0;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenstatic struct mail_storage *
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenmail_storage_find(struct mail_user *user,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen const struct mail_storage *storage_class,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const struct mailbox_list_settings *set)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct mail_storage *storage = user->storages;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (; storage != NULL; storage = storage->next) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (strcmp(storage->name, storage_class->name) == 0 &&
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ((storage->class_flags &
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) == 0 ||
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen strcmp(storage->unique_root_dir, set->root_dir) == 0))
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return storage;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return NULL;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen enum mail_storage_flags flags, const char **error_r)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_storage *storage_class, *storage = NULL;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen struct mailbox_list_settings list_set;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen enum mailbox_list_flags list_flags = 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const char *data = ns->set->location;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const char *p;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainen ns->mail_set->pop3_uidl_format != NULL) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen /* if pop3_uidl_format contains %m, we want to keep the
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen header MD5 sums stored even if we're not running POP3
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen right now. */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p = ns->mail_set->pop3_uidl_format;
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainen while ((p = strchr(p, '%')) != NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (p[1] == '%')
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p += 2;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen else if (var_get_key(++p) == 'm') {
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainen break;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen memset(&list_set, 0, sizeof(list_set));
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (data == NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* autodetect */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else if (driver != NULL && strcmp(driver, "shared") == 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* internal shared namespace */
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen list_set.root_dir = ns->user->set->base_dir;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (driver == NULL)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_storage_set_autodetection(&data, &driver);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (mailbox_list_settings_parse(data, &list_set, ns,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen error_r) < 0)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return -1;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0 &&
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen list_set.root_dir == NULL) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen *error_r = "Root mail directory not given";
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen storage_class = mail_storage_get_class(ns, driver, &list_set, error_r);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (storage_class == NULL)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen i_assert(list_set.layout != NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (ns->list == NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* first storage for namespace */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (mail_storage_is_mailbox_file(storage_class))
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (mailbox_list_create(list_set.layout, ns, &list_set,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen list_flags, error_r) < 0) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen *error_r = t_strdup_printf("Mailbox list driver %s: %s",
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen list_set.layout, *error_r);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen return -1;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (mail_storage_create_root(ns->list, flags, error_r) < 0)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen return -1;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen storage = mail_storage_find(ns->user, storage_class, &list_set);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (storage != NULL) {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen /* using an existing storage */
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen storage->refcount++;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen mail_namespace_add_storage(ns, storage);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen return 0;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
fd14806f879f6cd4f023750e0c4cac27a7f94fbbTimo Sirainen storage = storage_class->v.alloc();
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen storage->refcount = 1;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen storage->storage_class = storage_class;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen storage->user = ns->user;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen storage->set = ns->mail_set;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen storage->flags = flags;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (storage->v.create != NULL &&
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen storage->v.create(storage, ns, error_r) < 0) {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen pool_unref(&storage->pool);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen return -1;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen T_BEGIN {
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen hook_mail_storage_created(storage);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen } T_END;
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen DLLIST_PREPEND(&ns->user->storages, storage);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen mail_namespace_add_storage(ns, storage);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen return 0;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen}
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenvoid mail_storage_ref(struct mail_storage *storage)
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen{
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen storage->refcount++;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen}
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainenvoid mail_storage_unref(struct mail_storage **_storage)
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen{
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen struct mail_storage *storage = *_storage;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen i_assert(storage->refcount > 0);
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen *_storage = NULL;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen if (--storage->refcount > 0)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen return;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen DLLIST_REMOVE(&storage->user->storages, storage);
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen if (storage->v.destroy != NULL)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen storage->v.destroy(storage);
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen i_free(storage->error_string);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen pool_unref(&storage->pool);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen mail_index_alloc_cache_destroy_unrefed();
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen}
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_free_and_null(storage->error_string);
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen storage->error = MAIL_ERROR_NONE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen enum mail_error error, const char *string)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen{
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen i_free(storage->error_string);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen storage->error_string = i_strdup(string);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen storage->error = error;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct tm *tm;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen char str[256];
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen tm = localtime(&ioloop_time);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_free(storage->error_string);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen storage->error_string =
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen strftime(str, sizeof(str),
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen MAIL_ERRSTR_CRITICAL_MSG_STAMP, tm) > 0 ?
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_strdup(str) : i_strdup(MAIL_ERRSTR_CRITICAL_MSG);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen storage->error = MAIL_ERROR_TEMP;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const char *fmt, ...)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen va_list va;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_storage_clear_error(storage);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (fmt != NULL) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen va_start(va, fmt);
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen i_error("%s", t_strdup_vprintf(fmt, va));
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen va_end(va);
083c67ac280fb4930a280ce1f76fb27a1637e818Timo Sirainen
083c67ac280fb4930a280ce1f76fb27a1637e818Timo Sirainen /* critical errors may contain sensitive data, so let user
083c67ac280fb4930a280ce1f76fb27a1637e818Timo Sirainen see only "Internal error" with a timestamp to make it
083c67ac280fb4930a280ce1f76fb27a1637e818Timo Sirainen easier to look from log files the actual error message. */
083c67ac280fb4930a280ce1f76fb27a1637e818Timo Sirainen mail_storage_set_internal_error(storage);
083c67ac280fb4930a280ce1f76fb27a1637e818Timo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenvoid mail_storage_copy_list_error(struct mail_storage *storage,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mailbox_list *list)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen{
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen const char *str;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen enum mail_error error;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen str = mailbox_list_get_last_error(list, &error);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_storage_set_error(storage, error, str);
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen}
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenvoid mail_storage_set_index_error(struct mailbox *box)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (mail_index_is_deleted(box->index))
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mailbox_set_deleted(box);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen else
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_storage_set_internal_error(box->storage);
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen mail_index_reset_error(box->index);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainenconst struct mail_storage_settings *
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenmail_storage_get_settings(struct mail_storage *storage)
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return storage->set;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainenstruct mail_user *mail_storage_get_user(struct mail_storage *storage)
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen{
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen return storage->user;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen}
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainenvoid mail_storage_set_callbacks(struct mail_storage *storage,
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen struct mail_storage_callbacks *callbacks,
ceae1acc3e3022c6b5fe52a4a34890dffdbcb77fTimo Sirainen void *context)
ceae1acc3e3022c6b5fe52a4a34890dffdbcb77fTimo Sirainen{
a0475b241a56220714d96a41f11a174c11a48bfaTimo Sirainen storage->callbacks = *callbacks;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen storage->callback_context = context;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen}
ceae1acc3e3022c6b5fe52a4a34890dffdbcb77fTimo Sirainen
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainenint mail_storage_purge(struct mail_storage *storage)
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen{
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen return storage->v.purge == NULL ? 0 :
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen storage->v.purge(storage);
a0475b241a56220714d96a41f11a174c11a48bfaTimo Sirainen}
ceae1acc3e3022c6b5fe52a4a34890dffdbcb77fTimo Sirainen
ceae1acc3e3022c6b5fe52a4a34890dffdbcb77fTimo Sirainenconst char *mail_storage_get_last_error(struct mail_storage *storage,
ceae1acc3e3022c6b5fe52a4a34890dffdbcb77fTimo Sirainen enum mail_error *error_r)
ceae1acc3e3022c6b5fe52a4a34890dffdbcb77fTimo Sirainen{
ceae1acc3e3022c6b5fe52a4a34890dffdbcb77fTimo Sirainen /* We get here only in error situations, so we have to return some
a0475b241a56220714d96a41f11a174c11a48bfaTimo Sirainen error. If storage->error is NONE, it means we forgot to set it at
ceae1acc3e3022c6b5fe52a4a34890dffdbcb77fTimo Sirainen some point.. */
ceae1acc3e3022c6b5fe52a4a34890dffdbcb77fTimo Sirainen if (storage->error == MAIL_ERROR_NONE) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (error_r != NULL)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen *error_r = MAIL_ERROR_TEMP;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return storage->error_string != NULL ? storage->error_string :
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "BUG: Unknown internal error";
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
a0475b241a56220714d96a41f11a174c11a48bfaTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (storage->error_string == NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* This shouldn't happen.. */
a0475b241a56220714d96a41f11a174c11a48bfaTimo Sirainen storage->error_string =
a0475b241a56220714d96a41f11a174c11a48bfaTimo Sirainen i_strdup_printf("BUG: Unknown 0x%x error",
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen storage->error);
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (error_r != NULL)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen *error_r = storage->error;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen return storage->error_string;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenbool mail_storage_is_mailbox_file(struct mail_storage *storage)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return (storage->class_flags &
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE) != 0;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen}
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainenbool mail_storage_set_error_from_errno(struct mail_storage *storage)
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen{
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen const char *error_string;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen enum mail_error error;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen return FALSE;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* debugging is enabled - admin may be debugging a
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen (permission) problem, so return FALSE to get the caller to
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen log the full error message. */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return FALSE;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_storage_set_error(storage, error, error_string);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return TRUE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstruct mailbox *mailbox_alloc(struct mailbox_list *list, const char *name,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen enum mailbox_flags flags)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mailbox_list *new_list = list;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_storage *storage;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mailbox *box;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (mailbox_list_get_storage(&new_list, &name, &storage) < 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* just use the first storage. FIXME: does this break? */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen storage = list->ns->storage;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen T_BEGIN {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen box = storage->v.mailbox_alloc(storage, new_list, name, flags);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen hook_mailbox_allocated(box);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } T_END;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return box;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic int mailbox_open_full(struct mailbox *box, struct istream *input)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen int ret;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (box->opened)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (!mailbox_list_is_valid_existing_name(box->list, box->name)) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "Invalid mailbox name");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (input != NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if ((box->storage->class_flags &
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) == 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_storage_set_critical(box->storage,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "Storage doesn't support streamed mailboxes");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen box->input = input;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen box->flags |= MAILBOX_FLAG_READONLY;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_stream_ref(box->input);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen T_BEGIN {
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen ret = box->v.open(box);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } T_END;
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen
if (ret < 0 && box->storage->error == MAIL_ERROR_NOTFOUND &&
box->input == NULL && box->inbox) 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);
} 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;
box->backend_readonly = 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);
pool_unref(&box->pool);
}
int mailbox_create(struct mailbox *box, const struct mailbox_update *update,
bool directory)
{
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;
}
if (box->list->v.create_mailbox_dir(box->list, box->name,
directory) < 0) {
mail_storage_copy_list_error(box->storage, box->list);
return -1;
}
mailbox_refresh_permissions(box);
return box->v.create(box, update, directory);
}
int mailbox_update(struct mailbox *box, const struct mailbox_update *update)
{
return box->v.update(box, update);
}
static int mailbox_mark_index_deleted(struct mailbox *box, bool del)
{
enum mail_index_transaction_flags trans_flags = 0;
struct mail_index_transaction *trans;
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. */
return mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ);
}
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)
{
enum mail_error error;
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) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"INBOX can't be deleted.");
return -1;
}
box->deleting = TRUE;
if (mailbox_open(box) < 0) {
(void)mail_storage_get_last_error(box->storage, &error);
if (error != 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;
}
}
if (box->opened) {
if (mailbox_mark_index_deleted(box, TRUE) < 0)
return -1;
}
ret = box->v.delete(box);
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->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);
}
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;
}
void mailbox_get_status(struct mailbox *box,
enum mailbox_status_items items,
struct mailbox_status *status_r)
{
box->v.get_status(box, items, status_r);
}
int mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
{
if (box->v.get_guid == NULL) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Storage doesn't support mailbox GUIDs");
}
if (!box->opened) {
if (mailbox_open(box) < 0)
return -1;
}
if (box->v.get_guid(box, guid) < 0)
return -1;
i_assert(!mail_guid_128_is_empty(guid));
return 0;
}
struct mailbox_sync_context *
mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct mailbox_sync_context *ctx;
if (box->transaction_count != 0) {
i_panic("Trying to sync mailbox %s with open transactions",
box->name);
}
T_BEGIN {
ctx = box->v.sync_init(box, flags);
} T_END;
return ctx;
}
bool mailbox_sync_next(struct mailbox_sync_context *ctx,
struct mailbox_sync_rec *sync_rec_r)
{
return ctx->box->v.sync_next(ctx, sync_rec_r);
}
int mailbox_sync_deinit(struct mailbox_sync_context **_ctx,
struct mailbox_sync_status *status_r)
{
struct mailbox_sync_context *ctx = *_ctx;
*_ctx = NULL;
memset(status_r, 0, sizeof(*status_r));
return ctx->box->v.sync_deinit(ctx, status_r);
}
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);
}
int mailbox_keywords_create(struct mailbox *box, const char *const keywords[],
struct mail_keywords **keywords_r)
{
const char *empty_keyword_list = NULL;
if (keywords == NULL)
keywords = &empty_keyword_list;
return box->v.keywords_create(box, keywords, keywords_r, FALSE);
}
struct mail_keywords *
mailbox_keywords_create_valid(struct mailbox *box,
const char *const keywords[])
{
const char *empty_keyword_list = NULL;
struct mail_keywords *kw;
if (keywords == NULL)
keywords = &empty_keyword_list;
if (box->v.keywords_create(box, keywords, &kw, TRUE) < 0)
i_unreached();
return kw;
}
struct mail_keywords *
mailbox_keywords_create_from_indexes(struct mailbox *box,
const ARRAY_TYPE(keyword_indexes) *idx)
{
return box->v.keywords_create_from_indexes(box, idx);
}
void mailbox_keywords_ref(struct mailbox *box, struct mail_keywords *keywords)
{
box->v.keywords_ref(keywords);
}
void mailbox_keywords_unref(struct mailbox *box,
struct mail_keywords **_keywords)
{
struct mail_keywords *keywords = *_keywords;
*_keywords = NULL;
box->v.keywords_unref(keywords);
}
bool mailbox_keyword_is_valid(struct mailbox *box, const char *keyword,
const char **error_r)
{
return box->v.keyword_is_valid(box, keyword, error_r);
}
void mailbox_get_seq_range(struct mailbox *box, uint32_t uid1, uint32_t uid2,
uint32_t *seq1_r, uint32_t *seq2_r)
{
box->v.get_seq_range(box, uid1, uid2, seq1_r, seq2_r);
}
void mailbox_get_uid_range(struct mailbox *box,
const ARRAY_TYPE(seq_range) *seqs,
ARRAY_TYPE(seq_range) *uids)
{
box->v.get_uid_range(box, seqs, uids);
}
bool mailbox_get_expunges(struct mailbox *box, uint64_t prev_modseq,
const ARRAY_TYPE(seq_range) *uids_filter,
ARRAY_TYPE(mailbox_expunge_rec) *expunges)
{
return box->v.get_expunges(box, prev_modseq,
uids_filter, expunges);
}
bool mailbox_get_virtual_uid(struct mailbox *box, const char *backend_mailbox,
uint32_t backend_uidvalidity,
uint32_t backend_uid, uint32_t *uid_r)
{
if (box->v.get_virtual_uid == NULL)
return FALSE;
return box->v.get_virtual_uid(box, backend_mailbox, backend_uidvalidity,
backend_uid, uid_r);
}
void mailbox_get_virtual_backend_boxes(struct mailbox *box,
ARRAY_TYPE(mailboxes) *mailboxes,
bool only_with_msgs)
{
if (box->v.get_virtual_backend_boxes == NULL)
array_append(mailboxes, &box, 1);
else
box->v.get_virtual_backend_boxes(box, mailboxes, only_with_msgs);
}
void mailbox_get_virtual_box_patterns(struct mailbox *box,
ARRAY_TYPE(mailbox_virtual_patterns) *includes,
ARRAY_TYPE(mailbox_virtual_patterns) *excludes)
{
if (box->v.get_virtual_box_patterns == NULL) {
struct mailbox_virtual_pattern pat;
memset(&pat, 0, sizeof(pat));
pat.ns = box->list->ns;
pat.pattern = box->name;
array_append(includes, &pat, 1);
} else {
box->v.get_virtual_box_patterns(box, includes, excludes);
}
}
struct mailbox_header_lookup_ctx *
mailbox_header_lookup_init(struct mailbox *box, const char *const headers[])
{
return box->v.header_lookup_init(box, headers);
}
void mailbox_header_lookup_ref(struct mailbox_header_lookup_ctx *ctx)
{
i_assert(ctx->refcount > 0);
ctx->refcount++;
}
void mailbox_header_lookup_unref(struct mailbox_header_lookup_ctx **_ctx)
{
struct mailbox_header_lookup_ctx *ctx = *_ctx;
*_ctx = NULL;
i_assert(ctx->refcount > 0);
if (--ctx->refcount > 0)
return;
ctx->box->v.header_lookup_deinit(ctx);
}
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. */
ret = mailbox_transaction_commit_get_changes(t, &changes);
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)
{
t->box->v.transaction_set_max_modseq(t, 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(ctx->transaction->box, 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_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(box, &keywords);
return ret;
}
void mailbox_save_cancel(struct mail_save_context **_ctx)
{
struct mail_save_context *ctx = *_ctx;
struct mailbox *box = ctx->transaction->box;
struct mail_keywords *keywords = ctx->keywords;
*_ctx = NULL;
ctx->transaction->box->v.save_cancel(ctx);
if (keywords != NULL)
mailbox_keywords_unref(box, &keywords);
}
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(box, &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;
}
void mailbox_refresh_permissions(struct mailbox *box)
{
const char *origin, *dir_origin;
gid_t dir_gid;
if (box->input != NULL) {
box->file_create_mode = 0600;
box->dir_create_mode = 0700;
box->file_create_gid = (gid_t)-1;
box->file_create_gid_origin = "defaults";
return;
}
mailbox_list_get_permissions(box->list, box->name,
&box->file_create_mode,
&box->file_create_gid, &origin);
box->file_create_gid_origin = p_strdup(box->pool, origin);
mailbox_list_get_dir_permissions(box->list, box->name,
&box->dir_create_mode,
&dir_gid, &dir_origin);
}
int mailbox_create_fd(struct mailbox *box, const char *path, int flags,
int *fd_r)
{
mode_t old_mask;
int fd;
i_assert(box->file_create_mode != 0);
i_assert((flags & O_CREAT) != 0);
*fd_r = -1;
old_mask = umask(0);
fd = open(path, flags, box->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 (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 (box->file_create_gid != (gid_t)-1) {
if (fchown(fd, (uid_t)-1, box->file_create_gid) == 0) {
/* ok */
} else if (errno == EPERM) {
mail_storage_set_critical(box->storage, "%s",
eperm_error_get_chgrp("fchown", path,
box->file_create_gid,
box->file_create_gid_origin));
} else {
mail_storage_set_critical(box->storage,
"fchown(%s) failed: %m", path);
}
}
*fd_r = fd;
return 1;
}