virtual-storage.c revision 9847ec56efa15fa063eea9988eee2d4ed9ec7d58
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen/* Copyright (c) 2008-2013 Dovecot authors, see the included COPYING file */
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "lib.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "array.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "ioloop.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "str.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "mkdir-parents.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "unlink-directory.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "index-mail.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "mail-copy.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "mail-search.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "mailbox-list-private.h"
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen#include "virtual-plugin.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "virtual-transaction.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include "virtual-storage.h"
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include <stdio.h>
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include <stdlib.h>
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen#include <unistd.h>
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen#include <dirent.h>
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainen#include <sys/stat.h>
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainen
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainenextern struct mail_storage virtual_storage;
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainenextern struct mailbox virtual_mailbox;
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainenextern struct virtual_mailbox_vfuncs virtual_mailbox_vfuncs;
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainen
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainenstruct virtual_storage_module virtual_storage_module =
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainen MODULE_CONTEXT_INIT(&mail_storage_module_register);
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainen
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainenstatic bool ns_is_visible(struct mail_namespace *ns)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen{
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen return (ns->flags & NAMESPACE_FLAG_LIST_PREFIX) != 0 ||
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen (ns->flags & NAMESPACE_FLAG_LIST_CHILDREN) != 0 ||
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen (ns->flags & NAMESPACE_FLAG_HIDDEN) == 0;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen}
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainenstatic const char *get_user_visible_mailbox_name(struct mailbox *box)
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen{
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen if (ns_is_visible(box->list->ns))
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen return box->vname;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen else {
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen return t_strdup_printf("<hidden>%c%s",
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen mail_namespace_get_sep(box->list->ns),
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen box->vname);
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen }
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen}
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainenvoid virtual_box_copy_error(struct mailbox *dest, struct mailbox *src)
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen{
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen const char *name, *str;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen enum mail_error error;
fd1f0e9ef52b3e157cfd1a01c464c2ac7458ab17Timo Sirainen
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen name = get_user_visible_mailbox_name(src);
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen str = mailbox_get_last_error(src, &error);
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen str = t_strdup_printf("%s (for backend mailbox %s)", str, name);
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen mail_storage_set_error(dest->storage, error, str);
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen}
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen
306f6bb8791755257c0db900f17659402c660057Timo Sirainenstatic struct mail_storage *virtual_storage_alloc(void)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen{
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen struct virtual_storage *storage;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen pool_t pool;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen pool = pool_alloconly_create("virtual storage", 1024);
6a7bc57cdd2aaa7778478bf76c20c61640c725e6Timo Sirainen storage = p_new(pool, struct virtual_storage, 1);
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen storage->storage = virtual_storage;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen storage->storage.pool = pool;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen p_array_init(&storage->open_stack, pool, 8);
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen return &storage->storage;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen}
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainenstatic void
1388b590dbd85245b591346f860bc1319953318aTimo Sirainenvirtual_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen struct mailbox_list_settings *set)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen{
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen if (set->layout == NULL)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen set->layout = MAILBOX_LIST_NAME_FS;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen if (set->subscription_fname == NULL)
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen set->subscription_fname = VIRTUAL_SUBSCRIPTION_FILE_NAME;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen}
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainenstruct virtual_backend_box *
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainenvirtual_backend_box_lookup_name(struct virtual_mailbox *mbox, const char *name)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen{
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen struct virtual_backend_box *const *bboxes;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen unsigned int i, count;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen for (i = 0; i < count; i++) {
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen if (strcmp(bboxes[i]->name, name) == 0)
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen return bboxes[i];
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen }
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen return NULL;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen}
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainenstruct virtual_backend_box *
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainenvirtual_backend_box_lookup(struct virtual_mailbox *mbox, uint32_t mailbox_id)
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen{
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen struct virtual_backend_box *const *bboxes;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen unsigned int i, count;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen if (mailbox_id == 0)
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen return NULL;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen for (i = 0; i < count; i++) {
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen if (bboxes[i]->mailbox_id == mailbox_id)
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen return bboxes[i];
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen }
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen return NULL;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen}
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainenstatic bool virtual_mailbox_is_in_open_stack(struct virtual_storage *storage,
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen const char *name)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen{
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen const char *const *names;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen unsigned int i, count;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen names = array_get(&storage->open_stack, &count);
5c6410e8882d021ad9cff91d87b3ce68e309bd44Timo Sirainen for (i = 0; i < count; i++) {
5c6410e8882d021ad9cff91d87b3ce68e309bd44Timo Sirainen if (strcmp(names[i], name) == 0)
5c6410e8882d021ad9cff91d87b3ce68e309bd44Timo Sirainen return TRUE;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen }
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen return FALSE;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen}
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainenstatic int virtual_backend_box_open_failed(struct virtual_mailbox *mbox,
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen struct virtual_backend_box *bbox)
ec096c8a0f52a4bb5d12aa9afe1a576368aa8094Timo Sirainen{
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen enum mail_error error;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen const char *str, *name;
193f5296d2a6b847970c222d8a261b89aae46331Timo Sirainen
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen str = mailbox_get_last_error(bbox->box, &error);
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen name = t_strdup(get_user_visible_mailbox_name(bbox->box));
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen mailbox_free(&bbox->box);
4dc5662260a63669054cd0dc1bac2ccab3fa2ae7Timo Sirainen if (error == MAIL_ERROR_NOTFOUND) {
4dc5662260a63669054cd0dc1bac2ccab3fa2ae7Timo Sirainen /* ignore this. it could be intentional. */
4dc5662260a63669054cd0dc1bac2ccab3fa2ae7Timo Sirainen if (mbox->storage->storage.user->mail_debug) {
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainen i_debug("virtual mailbox %s: "
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainen "Skipping non-existing mailbox %s",
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen mbox->box.vname, name);
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen }
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen return 0;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen }
0a3d3ca7db7cbdc947ccabe740c40561b3f5c066Timo Sirainen
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen if (error == MAIL_ERROR_PERM && bbox->wildcard) {
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen /* this mailbox wasn't explicitly specified. just skip it. */
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen return 0;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen }
193f5296d2a6b847970c222d8a261b89aae46331Timo Sirainen str = t_strdup_printf(
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen "Virtual mailbox open failed because of mailbox %s: %s",
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen name, str);
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen mail_storage_set_error(mbox->box.storage, error, str);
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen return -1;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen}
193f5296d2a6b847970c222d8a261b89aae46331Timo Sirainen
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainenstatic int virtual_backend_box_open(struct virtual_mailbox *mbox,
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen struct virtual_backend_box *bbox,
193f5296d2a6b847970c222d8a261b89aae46331Timo Sirainen enum mailbox_flags flags)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen{
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen struct mail_user *user = mbox->storage->storage.user;
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen struct mail_namespace *ns;
f6c0407545ee77d4647c8cd912e3156b0a48e2f1Timo Sirainen struct mailbox_status status;
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen const char *mailbox;
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen
a40f21e8239a87a8fab2648955b0f568908ca8b5Timo Sirainen i_assert(bbox->box == NULL);
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen if (bbox->clear_recent)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen flags |= MAILBOX_FLAG_DROP_RECENT;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen mailbox = bbox->name;
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen ns = mail_namespace_find(user->namespaces, mailbox);
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen bbox->box = mailbox_alloc(ns->list, mailbox, flags);
6a029ebed745994ce2e5f64182d8b5c8f10d53d6Timo Sirainen
if (mailbox_open(bbox->box) < 0)
return virtual_backend_box_open_failed(mbox, bbox);
i_array_init(&bbox->uids, 64);
i_array_init(&bbox->sync_pending_removes, 64);
mail_search_args_init(bbox->search_args, bbox->box, FALSE, NULL);
mailbox_get_open_status(bbox->box, 0, &status);
if (!status.have_guids)
mbox->have_guids = FALSE;
if (!status.have_save_guids)
mbox->have_save_guids = FALSE;
return 1;
}
static int virtual_mailboxes_open(struct virtual_mailbox *mbox,
enum mailbox_flags flags)
{
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
int ret;
mbox->have_guids = TRUE;
mbox->have_save_guids = TRUE;
bboxes = array_get(&mbox->backend_boxes, &count);
for (i = 0; i < count; ) {
ret = virtual_backend_box_open(mbox, bboxes[i], flags);
if (ret <= 0) {
if (ret < 0)
break;
mail_search_args_unref(&bboxes[i]->search_args);
array_delete(&mbox->backend_boxes, i, 1);
bboxes = array_get(&mbox->backend_boxes, &count);
} else {
i++;
}
}
if (i == count)
return 0;
else {
/* failed */
for (; i > 0; i--) {
mailbox_free(&bboxes[i-1]->box);
array_free(&bboxes[i-1]->uids);
}
return -1;
}
}
static struct mailbox *
virtual_mailbox_alloc(struct mail_storage *_storage, struct mailbox_list *list,
const char *vname, enum mailbox_flags flags)
{
struct virtual_storage *storage = (struct virtual_storage *)_storage;
struct virtual_mailbox *mbox;
pool_t pool;
pool = pool_alloconly_create("virtual mailbox", 2048);
mbox = p_new(pool, struct virtual_mailbox, 1);
mbox->box = virtual_mailbox;
mbox->box.pool = pool;
mbox->box.storage = _storage;
mbox->box.list = list;
mbox->box.mail_vfuncs = &virtual_mail_vfuncs;
mbox->vfuncs = virtual_mailbox_vfuncs;
index_storage_mailbox_alloc(&mbox->box, vname, flags, MAIL_INDEX_PREFIX);
mbox->storage = storage;
mbox->virtual_ext_id = (uint32_t)-1;
return &mbox->box;
}
static void virtual_mailbox_close_internal(struct virtual_mailbox *mbox)
{
struct virtual_backend_box **bboxes;
unsigned int i, count;
bboxes = array_get_modifiable(&mbox->backend_boxes, &count);
for (i = 0; i < count; i++) {
if (bboxes[i]->search_result != NULL)
mailbox_search_result_free(&bboxes[i]->search_result);
if (bboxes[i]->box == NULL)
continue;
mail_search_args_deinit(bboxes[i]->search_args);
mailbox_free(&bboxes[i]->box);
if (array_is_created(&bboxes[i]->sync_outside_expunges))
array_free(&bboxes[i]->sync_outside_expunges);
array_free(&bboxes[i]->sync_pending_removes);
array_free(&bboxes[i]->uids);
}
}
static int
virtual_mailbox_exists(struct mailbox *box, bool auto_boxes ATTR_UNUSED,
enum mailbox_existence *existence_r)
{
return index_storage_mailbox_exists_full(box, VIRTUAL_CONFIG_FNAME,
existence_r);
}
static int virtual_mailbox_open(struct mailbox *box)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
int ret = 0;
if (virtual_mailbox_is_in_open_stack(mbox->storage, box->name)) {
mail_storage_set_critical(box->storage,
"Virtual mailbox loops: %s", box->name);
return -1;
}
if (!array_is_created(&mbox->backend_boxes))
ret = virtual_config_read(mbox);
if (ret == 0) {
array_append(&mbox->storage->open_stack, &box->name, 1);
ret = virtual_mailboxes_open(mbox, box->flags);
array_delete(&mbox->storage->open_stack,
array_count(&mbox->storage->open_stack)-1, 1);
}
if (ret < 0) {
virtual_mailbox_close_internal(mbox);
return -1;
}
if (index_storage_mailbox_open(box, FALSE) < 0)
return -1;
mbox->virtual_ext_id =
mail_index_ext_register(mbox->box.index, "virtual", 0,
sizeof(struct virtual_mail_index_record),
sizeof(uint32_t));
return 0;
}
static void virtual_mailbox_close(struct mailbox *box)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
virtual_mailbox_close_internal(mbox);
index_storage_mailbox_close(box);
}
static void virtual_mailbox_free(struct mailbox *box)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
virtual_config_free(mbox);
index_storage_mailbox_free(box);
}
static int
virtual_mailbox_create(struct mailbox *box,
const struct mailbox_update *update ATTR_UNUSED,
bool directory ATTR_UNUSED)
{
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Can't create virtual mailboxes");
return -1;
}
static int
virtual_mailbox_update(struct mailbox *box,
const struct mailbox_update *update ATTR_UNUSED)
{
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Can't update virtual mailboxes");
return -1;
}
static int
virtual_storage_get_status(struct mailbox *box,
enum mailbox_status_items items,
struct mailbox_status *status_r)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
if ((items & STATUS_LAST_CACHED_SEQ) != 0)
items |= STATUS_MESSAGES;
if (index_storage_get_status(box, items, status_r) < 0)
return -1;
if ((items & STATUS_LAST_CACHED_SEQ) != 0) {
/* Virtual mailboxes have no cached data of their own, so the
current value is always 0. The most important use for this
functionality is for "doveadm index" to do FTS indexing and
it doesn't really matter there if we set this value
correctly or not. So for now just assume that everything is
indexed. */
status_r->last_cached_seq = status_r->messages;
}
if (mbox->have_guids)
status_r->have_guids = TRUE;
if (mbox->have_save_guids)
status_r->have_save_guids = TRUE;
return 0;
}
static int
virtual_mailbox_get_metadata(struct mailbox *box,
enum mailbox_metadata_items items,
struct mailbox_metadata *metadata_r)
{
if (index_mailbox_get_metadata(box, items, metadata_r) < 0)
return -1;
if ((items & MAILBOX_METADATA_GUID) != 0) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Virtual mailboxes have no GUIDs");
return -1;
}
return 0;
}
static void
virtual_notify_callback(struct mailbox *bbox ATTR_UNUSED, struct mailbox *box)
{
box->notify_callback(box, box->notify_context);
}
static void virtual_notify_changes(struct mailbox *box)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
bboxes = array_get(&mbox->backend_boxes, &count);
for (i = 0; i < count; i++) {
struct mailbox *bbox = bboxes[i]->box;
if (box->notify_callback == NULL)
mailbox_notify_changes_stop(bbox);
else
mailbox_notify_changes(bbox, virtual_notify_callback, box);
}
}
static void
virtual_get_virtual_uids(struct mailbox *box,
struct mailbox *backend_mailbox,
const ARRAY_TYPE(seq_range) *backend_uids,
ARRAY_TYPE(seq_range) *virtual_uids_r)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
struct virtual_backend_box *bbox;
const struct virtual_backend_uidmap *uids;
struct seq_range_iter iter;
unsigned int n, i, count;
uint32_t uid;
if (mbox->lookup_prev_bbox != NULL &&
strcmp(mbox->lookup_prev_bbox->box->vname, backend_mailbox->vname) == 0)
bbox = mbox->lookup_prev_bbox;
else {
bbox = virtual_backend_box_lookup_name(mbox, backend_mailbox->vname);
mbox->lookup_prev_bbox = bbox;
}
if (bbox == NULL)
return;
uids = array_get(&bbox->uids, &count); i = 0;
seq_range_array_iter_init(&iter, backend_uids); n = 0;
while (seq_range_array_iter_nth(&iter, n++, &uid)) {
while (i < count && uids[i].real_uid < uid) i++;
if (i < count && uids[i].real_uid == uid) {
seq_range_array_add(virtual_uids_r,
uids[i].virtual_uid);
i++;
}
}
}
static void
virtual_get_virtual_uid_map(struct mailbox *box,
struct mailbox *backend_mailbox,
const ARRAY_TYPE(seq_range) *backend_uids,
ARRAY_TYPE(uint32_t) *virtual_uids_r)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
struct virtual_backend_box *bbox;
const struct virtual_backend_uidmap *uids;
struct seq_range_iter iter;
unsigned int n, i, count;
uint32_t uid;
if (mbox->lookup_prev_bbox != NULL &&
strcmp(mbox->lookup_prev_bbox->box->vname, backend_mailbox->vname) == 0)
bbox = mbox->lookup_prev_bbox;
else {
bbox = virtual_backend_box_lookup_name(mbox, backend_mailbox->vname);
mbox->lookup_prev_bbox = bbox;
}
if (bbox == NULL)
return;
uids = array_get(&bbox->uids, &count); i = 0;
seq_range_array_iter_init(&iter, backend_uids); n = 0;
while (seq_range_array_iter_nth(&iter, n++, &uid)) {
while (i < count && uids[i].real_uid < uid) i++;
if (i == count || uids[i].real_uid > uid) {
uint32_t zero = 0;
array_append(virtual_uids_r, &zero, 1);
} else {
array_append(virtual_uids_r, &uids[i].virtual_uid, 1);
i++;
}
}
}
static void
virtual_get_virtual_backend_boxes(struct mailbox *box,
ARRAY_TYPE(mailboxes) *mailboxes,
bool only_with_msgs)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
bboxes = array_get(&mbox->backend_boxes, &count);
for (i = 0; i < count; i++) {
if (!only_with_msgs || array_count(&bboxes[i]->uids) > 0)
array_append(mailboxes, &bboxes[i]->box, 1);
}
}
static bool virtual_is_inconsistent(struct mailbox *box)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
if (mbox->inconsistent)
return TRUE;
return index_storage_is_inconsistent(box);
}
struct mail_storage virtual_storage = {
.name = VIRTUAL_STORAGE_NAME,
.class_flags = MAIL_STORAGE_CLASS_FLAG_NOQUOTA,
.v = {
NULL,
virtual_storage_alloc,
NULL,
index_storage_destroy,
NULL,
virtual_storage_get_list_settings,
NULL,
virtual_mailbox_alloc,
NULL
}
};
struct mailbox virtual_mailbox = {
.v = {
index_storage_is_readonly,
index_storage_mailbox_enable,
virtual_mailbox_exists,
virtual_mailbox_open,
virtual_mailbox_close,
virtual_mailbox_free,
virtual_mailbox_create,
virtual_mailbox_update,
index_storage_mailbox_delete,
index_storage_mailbox_rename,
virtual_storage_get_status,
virtual_mailbox_get_metadata,
index_storage_set_subscribed,
index_storage_attribute_set,
index_storage_attribute_get,
index_storage_attribute_iter_init,
index_storage_attribute_iter_next,
index_storage_attribute_iter_deinit,
NULL,
NULL,
virtual_storage_sync_init,
index_mailbox_sync_next,
index_mailbox_sync_deinit,
NULL,
virtual_notify_changes,
virtual_transaction_begin,
virtual_transaction_commit,
virtual_transaction_rollback,
NULL,
virtual_mail_alloc,
virtual_search_init,
virtual_search_deinit,
virtual_search_next_nonblock,
virtual_search_next_update_seq,
virtual_save_alloc,
virtual_save_begin,
virtual_save_continue,
virtual_save_finish,
virtual_save_cancel,
mail_storage_copy,
NULL,
NULL,
NULL,
virtual_is_inconsistent
}
};
struct virtual_mailbox_vfuncs virtual_mailbox_vfuncs = {
virtual_get_virtual_uids,
virtual_get_virtual_uid_map,
virtual_get_virtual_backend_boxes
};