virtual-storage.c revision 4ba9a1d3facc515b3feb5238a16bcf91f76fac61
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen/* Copyright (c) 2008-2010 Dovecot authors, see the included COPYING file */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "lib.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "array.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "ioloop.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "str.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "mkdir-parents.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "unlink-directory.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "index-mail.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "mail-copy.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "mail-search.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "mailbox-list-private.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "virtual-plugin.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "virtual-transaction.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "virtual-storage.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include <stdio.h>
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include <stdlib.h>
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include <unistd.h>
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include <dirent.h>
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include <sys/stat.h>
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#define VIRTUAL_LIST_CONTEXT(obj) \
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen MODULE_CONTEXT(obj, virtual_mailbox_list_module)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstruct virtual_mailbox_list {
56d1345c43bbd28c36b7faa85e4163bd9e874290Timo Sirainen union mailbox_list_module_context module_ctx;
713a54f695b8ad63826d22ebbe52f55c347e8c88Timo Sirainen};
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenextern struct mail_storage virtual_storage;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenextern struct mailbox virtual_mailbox;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
713a54f695b8ad63826d22ebbe52f55c347e8c88Timo Sirainenstruct virtual_storage_module virtual_storage_module =
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen MODULE_CONTEXT_INIT(&mail_storage_module_register);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(virtual_mailbox_list_module,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen &mailbox_list_module_register);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic bool ns_is_visible(struct mail_namespace *ns)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return (ns->flags & NAMESPACE_FLAG_LIST_PREFIX) != 0 ||
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen (ns->flags & NAMESPACE_FLAG_LIST_CHILDREN) != 0 ||
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen (ns->flags & NAMESPACE_FLAG_HIDDEN) == 0;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic const char *get_user_visible_mailbox_name(struct mailbox *box)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (ns_is_visible(box->list->ns))
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return box->vname;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return t_strdup_printf("<hidden>%c%s",
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen box->list->hierarchy_sep, box->name);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvoid virtual_box_copy_error(struct mailbox *dest, struct mailbox *src)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *name, *str;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen enum mail_error error;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen name = get_user_visible_mailbox_name(src);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str = mail_storage_get_last_error(src->storage, &error);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str = t_strdup_printf("%s (for backend mailbox %s)", str, name);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mail_storage_set_error(dest->storage, error, str);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic struct mail_storage *virtual_storage_alloc(void)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct virtual_storage *storage;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen pool_t pool;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen pool = pool_alloconly_create("virtual storage", 1024);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen storage = p_new(pool, struct virtual_storage, 1);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen storage->storage = virtual_storage;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen storage->storage.pool = pool;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen p_array_init(&storage->open_stack, pool, 8);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return &storage->storage;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvirtual_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct mailbox_list_settings *set)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (set->layout == NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen set->layout = MAILBOX_LIST_NAME_FS;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (set->subscription_fname == NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen set->subscription_fname = VIRTUAL_SUBSCRIPTION_FILE_NAME;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstruct virtual_backend_box *
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvirtual_backend_box_lookup_name(struct virtual_mailbox *mbox, const char *name)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct virtual_backend_box *const *bboxes;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen unsigned int i, count;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (i = 0; i < count; i++) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (strcmp(bboxes[i]->name, name) == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return bboxes[i];
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return NULL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstruct virtual_backend_box *
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvirtual_backend_box_lookup(struct virtual_mailbox *mbox, uint32_t mailbox_id)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct virtual_backend_box *const *bboxes;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen unsigned int i, count;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (mailbox_id == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return NULL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (i = 0; i < count; i++) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (bboxes[i]->mailbox_id == mailbox_id)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return bboxes[i];
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return NULL;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic bool virtual_mailbox_is_in_open_stack(struct virtual_storage *storage,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *name)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *const *names;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen unsigned int i, count;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen names = array_get(&storage->open_stack, &count);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (i = 0; i < count; i++) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (strcmp(names[i], name) == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return TRUE;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return FALSE;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic int virtual_backend_box_open_failed(struct virtual_mailbox *mbox,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct virtual_backend_box *bbox)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen enum mail_error error;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *str, *name;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str = mail_storage_get_last_error(mailbox_get_storage(bbox->box),
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen &error);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen name = t_strdup(get_user_visible_mailbox_name(bbox->box));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mailbox_free(&bbox->box);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (error == MAIL_ERROR_NOTFOUND) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* ignore this. it could be intentional. */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (mbox->storage->storage.user->mail_debug) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_debug("virtual mailbox %s: "
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen "Skipping non-existing mailbox %s",
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mbox->box.vname, name);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return 0;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (error == MAIL_ERROR_PERM && bbox->wildcard) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* this mailbox wasn't explicitly specified. just skip it. */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return 0;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str = t_strdup_printf(
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen "Virtual mailbox open failed because of mailbox %s: %s",
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen name, str);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mail_storage_set_error(mbox->box.storage, error, str);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return -1;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic int virtual_backend_box_open(struct virtual_mailbox *mbox,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct virtual_backend_box *bbox,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen enum mailbox_flags flags)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct mail_user *user = mbox->storage->storage.user;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct mail_namespace *ns;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *mailbox;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_assert(bbox->box == NULL);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen flags |= MAILBOX_FLAG_KEEP_RECENT;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mailbox = bbox->name;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen ns = mail_namespace_find(user->namespaces, &mailbox);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen bbox->box = mailbox_alloc(ns->list, mailbox, flags);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (mailbox_open(bbox->box) < 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return virtual_backend_box_open_failed(mbox, bbox);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_array_init(&bbox->uids, 64);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_array_init(&bbox->sync_pending_removes, 64);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mail_search_args_init(bbox->search_args, bbox->box, FALSE, NULL);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return 1;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic int virtual_mailboxes_open(struct virtual_mailbox *mbox,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen enum mailbox_flags flags)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct virtual_backend_box *const *bboxes;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen unsigned int i, count;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen int ret;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (i = 0; i < count; ) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen ret = virtual_backend_box_open(mbox, bboxes[i], flags);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (ret <= 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (ret < 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen break;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mail_search_args_unref(&bboxes[i]->search_args);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen array_delete(&mbox->backend_boxes, i, 1);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen } else {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i++;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (i == count)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return 0;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* failed */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (; i > 0; i--) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mailbox_free(&bboxes[i-1]->box);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen array_free(&bboxes[i-1]->uids);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return -1;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic struct mailbox *
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvirtual_mailbox_alloc(struct mail_storage *_storage, struct mailbox_list *list,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *name, enum mailbox_flags flags)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct virtual_storage *storage = (struct virtual_storage *)_storage;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct virtual_mailbox *mbox;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen pool_t pool;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen pool = pool_alloconly_create("virtual mailbox", 1024+512);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mbox = p_new(pool, struct virtual_mailbox, 1);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mbox->box = virtual_mailbox;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mbox->box.pool = pool;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mbox->box.storage = _storage;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen mbox->box.list = list;
mbox->box.mail_vfuncs = &virtual_mail_vfuncs;
index_storage_mailbox_alloc(&mbox->box, name, flags,
VIRTUAL_INDEX_PREFIX);
mbox->storage = storage;
mbox->vseq_lookup_prev_mailbox = i_strdup("");
mbox->virtual_ext_id =
mail_index_ext_register(mbox->box.index, "virtual", 0,
sizeof(struct virtual_mail_index_record),
sizeof(uint32_t));
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);
}
i_free_and_null(mbox->vseq_lookup_prev_mailbox);
}
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;
}
return index_storage_mailbox_open(box, FALSE);
}
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_mailbox_get_guid(struct mailbox *box,
uint8_t guid[MAIL_GUID_128_SIZE] ATTR_UNUSED)
{
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"Virtual mailboxes have no GUIDs");
return -1;
}
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, box->notify_min_interval,
virtual_notify_callback, box);
}
}
}
static int
virtual_list_get_mailbox_flags(struct mailbox_list *list,
const char *dir, const char *fname,
enum mailbox_list_file_type type,
struct stat *st_r,
enum mailbox_info_flags *flags)
{
struct virtual_mailbox_list *mlist = VIRTUAL_LIST_CONTEXT(list);
struct stat st2;
const char *virtual_path;
int ret;
ret = mlist->module_ctx.super.
get_mailbox_flags(list, dir, fname, type, st_r, flags);
if (ret <= 0 || MAILBOX_INFO_FLAGS_FINISHED(*flags))
return ret;
/* see if it's a selectable mailbox */
virtual_path = t_strconcat(dir, "/", fname, "/"VIRTUAL_CONFIG_FNAME,
NULL);
if (stat(virtual_path, &st2) < 0)
*flags |= MAILBOX_NOSELECT;
return ret;
}
static void virtual_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
struct mailbox_list *list)
{
struct mailbox_list_vfuncs *v = list->vlast;
struct virtual_mailbox_list *mlist;
mlist = p_new(list->pool, struct virtual_mailbox_list, 1);
mlist->module_ctx.super = *v;
list->vlast = &mlist->module_ctx.super;
v->get_mailbox_flags = virtual_list_get_mailbox_flags;
MODULE_CONTEXT_SET(list, virtual_mailbox_list_module, mlist);
}
static int virtual_backend_uidmap_cmp(const uint32_t *uid,
const struct virtual_backend_uidmap *map)
{
return *uid < map->real_uid ? -1 :
*uid > map->real_uid ? 1 : 0;
}
static bool
virtual_get_virtual_uid(struct mailbox *box, const char *backend_mailbox,
uint32_t backend_uidvalidity,
uint32_t backend_uid, uint32_t *uid_r)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
struct virtual_backend_box *bbox;
struct mailbox_status status;
const struct virtual_backend_uidmap *uids;
if (strcmp(mbox->vseq_lookup_prev_mailbox, backend_mailbox) == 0)
bbox = mbox->vseq_lookup_prev_bbox;
else {
i_free(mbox->vseq_lookup_prev_mailbox);
mbox->vseq_lookup_prev_mailbox = i_strdup(backend_mailbox);
bbox = virtual_backend_box_lookup_name(mbox, backend_mailbox);
mbox->vseq_lookup_prev_bbox = bbox;
}
if (bbox == NULL)
return FALSE;
mailbox_get_status(bbox->box, STATUS_UIDVALIDITY, &status);
if (status.uidvalidity != backend_uidvalidity)
return FALSE;
uids = array_bsearch(&bbox->uids, &backend_uid,
virtual_backend_uidmap_cmp);
if (uids == NULL)
return FALSE;
*uid_r = uids->virtual_uid;
return TRUE;
}
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 void
virtual_get_virtual_box_patterns(struct mailbox *box,
ARRAY_TYPE(mailbox_virtual_patterns) *includes,
ARRAY_TYPE(mailbox_virtual_patterns) *excludes)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
array_append_array(includes, &mbox->list_include_patterns);
array_append_array(excludes, &mbox->list_exclude_patterns);
}
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,
NULL,
virtual_storage_add_list,
virtual_storage_get_list_settings,
NULL,
virtual_mailbox_alloc,
NULL
}
};
struct mailbox virtual_mailbox = {
.v = {
index_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
virtual_mailbox_open,
virtual_mailbox_close,
virtual_mailbox_free,
virtual_mailbox_create,
virtual_mailbox_update,
index_storage_mailbox_delete,
index_storage_mailbox_rename,
index_storage_get_status,
virtual_mailbox_get_guid,
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,
index_transaction_set_max_modseq,
index_keywords_create,
index_keywords_create_from_indexes,
index_keywords_ref,
index_keywords_unref,
index_keyword_is_valid,
index_storage_get_seq_range,
index_storage_get_uid_range,
index_storage_get_expunges,
virtual_get_virtual_uid,
virtual_get_virtual_backend_boxes,
virtual_get_virtual_box_patterns,
virtual_mail_alloc,
index_header_lookup_init,
index_header_lookup_deinit,
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,
virtual_is_inconsistent
}
};