virtual-storage.c revision dd37e2ff291fbebac1b94e8aad50f3bdf7531049
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen/* Copyright (c) 2008-2015 Dovecot authors, see the included COPYING file */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenextern struct virtual_mailbox_vfuncs virtual_mailbox_vfuncs;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstruct virtual_storage_module virtual_storage_module =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen MODULE_CONTEXT_INIT(&mail_storage_module_register);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic bool ns_is_visible(struct mail_namespace *ns)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return (ns->flags & NAMESPACE_FLAG_LIST_PREFIX) != 0 ||
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (ns->flags & NAMESPACE_FLAG_LIST_CHILDREN) != 0 ||
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainenstatic const char *get_user_visible_mailbox_name(struct mailbox *box)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid virtual_box_copy_error(struct mailbox *dest, struct mailbox *src)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str = t_strdup_printf("%s (for backend mailbox %s)", str, name);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen mail_storage_set_error(dest->storage, error, str);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic struct mail_storage *virtual_storage_alloc(void)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen pool = pool_alloconly_create("virtual storage", 1024);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen storage = p_new(pool, struct virtual_storage, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvirtual_storage_create(struct mail_storage *_storage,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char **error_r)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct virtual_storage *storage = (struct virtual_storage *)_storage;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen value = mail_user_plugin_getenv(_storage->user, "virtual_max_open_mailboxes");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen storage->max_open_mailboxes = VIRTUAL_DEFAULT_MAX_OPEN_MAILBOXES;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen else if (str_to_uint(value, &storage->max_open_mailboxes) < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen *error_r = "Invalid virtual_max_open_mailboxes setting";
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvirtual_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen set->subscription_fname = VIRTUAL_SUBSCRIPTION_FILE_NAME;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvirtual_backend_box_lookup_name(struct virtual_mailbox *mbox, const char *name)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen unsigned int i, count;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < count; i++) {
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainenvirtual_backend_box_lookup(struct virtual_mailbox *mbox, uint32_t mailbox_id)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int i, count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < count; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic bool virtual_mailbox_is_in_open_stack(struct virtual_storage *storage,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *const *names;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int i, count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen names = array_get(&storage->open_stack, &count);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < count; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic int virtual_backend_box_open_failed(struct virtual_mailbox *mbox,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *str;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen "Virtual mailbox open failed because of mailbox %s: %s",
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_storage_set_error(mbox->box.storage, error, str);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (error == MAIL_ERROR_PERM && bbox->wildcard) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* this mailbox wasn't explicitly specified. just skip it. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic int virtual_backend_box_alloc(struct virtual_mailbox *mbox,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen struct mail_user *user = mbox->storage->storage.user;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ns = mail_namespace_find(user->namespaces, mailbox);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen bbox->box = mailbox_alloc(ns->list, mailbox, flags);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen MODULE_CONTEXT_SET(bbox->box, virtual_storage_module, bbox);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mailbox_exists(bbox->box, TRUE, &existence) < 0)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return virtual_backend_box_open_failed(mbox, bbox);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* ignore this. it could be intentional. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mbox->storage->storage.user->mail_debug) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen "Skipping non-existing mailbox %s",
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen i_array_init(&bbox->sync_pending_removes, 64);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* we use modseqs for being able to check quickly if backend mailboxes
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen have changed. make sure the backend has them enabled. */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen mailbox_enable(bbox->box, MAILBOX_FEATURE_CONDSTORE);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenstatic int virtual_mailboxes_open(struct virtual_mailbox *mbox,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen unsigned int i, count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < count; ) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen ret = virtual_backend_box_alloc(mbox, bboxes[i], flags);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen for (; i > 0; i--) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenstatic struct mailbox *
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenvirtual_mailbox_alloc(struct mail_storage *_storage, struct mailbox_list *list,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen struct virtual_storage *storage = (struct virtual_storage *)_storage;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen pool = pool_alloconly_create("virtual mailbox", 2048);
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen mbox = p_new(pool, struct virtual_mailbox, 1);
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen index_storage_mailbox_alloc(&mbox->box, vname, flags, MAIL_INDEX_PREFIX);
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainenvoid virtual_backend_box_sync_mail_unset(struct virtual_backend_box *bbox)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic bool virtual_backend_box_can_close(struct virtual_backend_box *bbox)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* FIXME: IMAP IDLE running - we should support closing this
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen also if mailbox_list_index=yes */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (array_count(&bbox->sync_pending_removes) > 0) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* FIXME: we could probably close this by making
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen syncing support it? */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenvirtual_backend_box_close_any_except(struct virtual_mailbox *mbox,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* first try to close a mailbox without any transactions.
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen we'll also skip any mailbox that has notifications enabled (ideally
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen these would be handled by mailbox list index) */
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen for (bbox = mbox->open_backend_boxes_head; bbox != NULL; bbox = bbox->next_open) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* next try to close a mailbox that has sync_mail, but no
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen other transactions */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen for (bbox = mbox->open_backend_boxes_head; bbox != NULL; bbox = bbox->next_open) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid virtual_mailbox_opened_hook(struct mailbox *box)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct virtual_backend_box *bbox = VIRTUAL_CONTEXT(box);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* not a backend for a virtual mailbox */
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen /* the backend mailbox was already opened. if we didn't get here
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen from virtual_backend_box_open() we may need to close a mailbox */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen while (mbox->backends_open_count > mbox->storage->max_open_mailboxes &&
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen virtual_backend_box_close_any_except(mbox, bbox))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen DLLIST2_APPEND_FULL(&mbox->open_backend_boxes_head,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenint virtual_backend_box_open(struct virtual_mailbox *mbox,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* try to keep the number of open mailboxes below the threshold
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen before opening the mailbox */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen while (mbox->backends_open_count >= mbox->storage->max_open_mailboxes &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen virtual_backend_box_close_any_except(mbox, bbox))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid virtual_backend_box_close(struct virtual_mailbox *mbox,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mailbox_search_result_free(&bbox->search_result);
unsigned int i, count;
for (i = 0; i < count; i++) {
bool broken;
int ret = 0;
if (ret == 0) {
if (ret < 0) {
sizeof(struct virtual_mail_index_record),
sizeof(uint32_t));
unsigned int i, count;
bool opened;
for (i = 0; i < count; i++) {
/* FIXME: if mailbox_list_index=yes, use mailbox-list-notify.h API
unsigned int n, i, count;
unsigned int n, i, count;
bool only_with_msgs)
unsigned int i, count;
for (i = 0; i < count; i++) {
return TRUE;
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,