virtual-storage.c revision 825b0e819a7c48a366ddca23ec78b87e8c30e9b4
/* Copyright (c) 2008-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "str.h"
#include "llist.h"
#include "mkdir-parents.h"
#include "unlink-directory.h"
#include "index-mail.h"
#include "mail-copy.h"
#include "mail-search.h"
#include "mailbox-list-private.h"
#include "virtual-plugin.h"
#include "virtual-transaction.h"
#include "virtual-storage.h"
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#define VIRTUAL_DEFAULT_MAX_OPEN_MAILBOXES 64
#define VIRTUAL_BACKEND_CONTEXT(obj) \
struct virtual_backend_mailbox {
union mailbox_module_context module_ctx;
};
extern struct mail_storage virtual_storage;
extern struct mailbox virtual_mailbox;
extern struct virtual_mailbox_vfuncs virtual_mailbox_vfuncs;
{
}
{
else {
return t_strdup_printf("<hidden>%c%s",
}
}
{
enum mail_error error;
}
static struct mail_storage *virtual_storage_alloc(void)
{
struct virtual_storage *storage;
}
static int
const char **error_r)
{
const char *value;
*error_r = "Invalid virtual_max_open_mailboxes setting";
return -1;
}
return 0;
}
static void
struct mailbox_list_settings *set)
{
}
struct virtual_backend_box *
{
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
for (i = 0; i < count; i++) {
return bboxes[i];
}
return NULL;
}
struct virtual_backend_box *
{
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
if (mailbox_id == 0)
return NULL;
for (i = 0; i < count; i++) {
return bboxes[i];
}
return NULL;
}
const char *name)
{
const char *const *names;
unsigned int i, count;
for (i = 0; i < count; i++) {
return TRUE;
}
return FALSE;
}
struct virtual_backend_box *bbox)
{
enum mail_error error;
const char *str;
"Virtual mailbox open failed because of mailbox %s: %s",
/* this mailbox wasn't explicitly specified. just skip it. */
return 0;
}
return -1;
}
struct virtual_backend_box *bbox,
enum mailbox_flags flags)
{
struct mail_namespace *ns;
const char *mailbox;
enum mailbox_existence existence;
if (!bbox->clear_recent)
if (existence != MAILBOX_EXISTENCE_SELECT) {
/* ignore this. it could be intentional. */
i_debug("virtual mailbox %s: "
"Skipping non-existing mailbox %s",
}
return 0;
}
/* we use modseqs for being able to check quickly if backend mailboxes
have changed. make sure the backend has them enabled. */
return 1;
}
enum mailbox_flags flags)
{
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
int ret;
for (i = 0; i < count; ) {
if (ret <= 0) {
if (ret < 0)
break;
} else {
i++;
}
}
if (i == count)
return 0;
else {
/* failed */
for (; i > 0; i--) {
}
return -1;
}
}
static struct mailbox *
{
struct virtual_mailbox *mbox;
}
{
struct mailbox_transaction_context *trans;
(void)mailbox_transaction_commit(&trans);
}
}
{
/* FIXME: IMAP IDLE running - we should support closing this
also if mailbox_list_index=yes */
return FALSE;
}
/* FIXME: we could probably close this by making
syncing support it? */
return FALSE;
}
return TRUE;
}
static bool
struct virtual_backend_box *except_bbox)
{
struct virtual_backend_box *bbox;
/* first try to close a mailbox without any transactions.
we'll also skip any mailbox that has notifications enabled (ideally
these would be handled by mailbox list index) */
if (bbox != except_bbox &&
return TRUE;
}
}
/* next try to close a mailbox that has sync_mail, but no
other transactions */
if (bbox != except_bbox &&
return TRUE;
}
}
return FALSE;
}
{
/* we could have gotten here from e.g. mailbox_autocreate()
without going through virtual_mailbox_close() */
}
}
{
struct virtual_backend_mailbox *vbox;
}
{
struct virtual_mailbox *mbox;
/* not a backend for a virtual mailbox */
return;
}
/* the backend mailbox was already opened. if we didn't get here
from virtual_backend_box_open() we may need to close a mailbox */
;
}
struct virtual_backend_box *bbox)
{
/* try to keep the number of open mailboxes below the threshold
before opening the mailbox */
;
}
struct virtual_backend_box *bbox)
{
}
}
struct virtual_backend_box *bbox)
{
}
{
struct virtual_backend_box **bboxes;
unsigned int i, count;
for (i = 0; i < count; i++) {
continue;
}
}
static int
enum mailbox_existence *existence_r)
{
}
{
bool broken;
int ret = 0;
return -1;
}
if (ret == 0) {
}
if (ret < 0) {
return -1;
}
return -1;
sizeof(struct virtual_mail_index_record),
sizeof(uint32_t));
0, 0);
return -1;
}
/* if GUID is missing write it here */
struct mail_index_transaction *t =
if (mail_index_transaction_commit(&t) < 0) {
"Cannot write GUID for virtual mailbox %s to index",
return -1;
}
}
return 0;
}
{
}
{
}
static int
bool directory ATTR_UNUSED)
{
"Can't create virtual mailboxes");
return -1;
}
static int
{
"Can't update virtual mailboxes");
return -1;
}
{
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
struct mailbox_status status;
return -1;
}
for (i = 0; i < count; i++) {
const char *errstr;
enum mail_error error;
if (error == MAIL_ERROR_NOTFOUND) {
/* backend mailbox was just lost - skip it */
continue;
}
/* Not expected to happen, but we can't return failure
since this could be called from
mailbox_get_open_status() and it would panic.
So just log the error and skip the mailbox. */
"Virtual mailbox %s: Failed to get have_guid existence for backend mailbox %s: %s",
continue;
}
if (!status.have_guids)
if (!status.have_save_guids)
}
return 0;
}
static int
enum mailbox_status_items items,
struct mailbox_status *status_r)
{
if ((items & STATUS_LAST_CACHED_SEQ) != 0)
items |= STATUS_MESSAGES;
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. */
}
if (!mbox->have_guid_flags_set) {
if (virtual_storage_set_have_guid_flags(mbox) < 0)
return -1;
}
if (mbox->have_guids)
if (mbox->have_save_guids)
return 0;
}
static int
enum mailbox_metadata_items items,
struct mailbox_metadata *metadata_r)
{
return -1;
if ((items & MAILBOX_METADATA_GUID) != 0) {
return -1;
}
}
return 0;
}
static void
{
}
{
struct virtual_backend_box *const *bboxp;
return;
}
/* FIXME: if mailbox_list_index=yes, use mailbox-list-notify.h API
to wait for changes and avoid opening all mailboxes here. */
/* we can't report error in here, so do it later */
continue;
}
}
}
static void
struct mailbox *backend_mailbox,
{
struct virtual_backend_box *bbox;
const struct virtual_backend_uidmap *uids;
struct seq_range_iter iter;
unsigned int n, i, count;
else {
}
return;
uids[i].virtual_uid);
i++;
}
}
}
static void
struct mailbox *backend_mailbox,
{
struct virtual_backend_box *bbox;
const struct virtual_backend_uidmap *uids;
struct seq_range_iter iter;
unsigned int n, i, count;
else {
}
return;
} else {
i++;
}
}
}
static void
bool only_with_msgs)
{
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
for (i = 0; i < count; i++) {
}
}
{
if (mbox->inconsistent)
return TRUE;
return index_storage_is_inconsistent(box);
}
static int
{
/* we don't have any quick and easy optimizations for tracking
virtual folders. ideally we'd completely disable mailbox list
indexes for them, but this is the easiest way to do it for now. */
return 1;
}
static void
{
}
struct mail_storage virtual_storage = {
.v = {
NULL,
NULL,
NULL,
NULL,
NULL,
}
};
struct mailbox virtual_mailbox = {
.v = {
NULL,
NULL,
NULL,
NULL,
NULL,
}
};
struct virtual_mailbox_vfuncs virtual_mailbox_vfuncs = {
};