mail-storage.c revision e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85
/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "llist.h"
#include "istream.h"
#include "eacces-error.h"
#include "mkdir-parents.h"
#include "var-expand.h"
#include "mail-index-private.h"
#include "mail-index-alloc-cache.h"
#include "mailbox-list-private.h"
#include "mail-storage-private.h"
#include "mail-storage-settings.h"
#include "mail-namespace.h"
#include "mail-search.h"
#include "mailbox-search-result-private.h"
#include <stdlib.h>
#include <ctype.h>
struct mail_storage_module_register mail_storage_module_register = { 0 };
struct mail_module_register mail_module_register = { 0 };
void mail_storage_init(void)
{
}
void mail_storage_deinit(void)
{
}
{
/* append it after the list, so the autodetection order is correct */
}
{
struct mail_storage *const *classes;
unsigned int i, count;
for (i = 0; i < count; i++) {
if (classes[i] == storage_class) {
break;
}
}
}
{
struct mail_storage *const *classes;
unsigned int i, count;
for (i = 0; i < count; i++) {
return classes[i];
}
return NULL;
}
static struct mail_storage *
struct mailbox_list_settings *set)
{
struct mail_storage *const *classes;
unsigned int i, count;
for (i = 0; i < count; i++) {
return classes[i];
}
}
return NULL;
}
static void
{
const char *p;
/* check if data is in driver:data format (eg. mbox:~/mail) */
p = *data;
while (i_isalnum(*p)) p++;
if (*p == ':' && p != *data) {
/* no autodetection if the storage driver is given. */
*data = p + 1;
}
}
static struct mail_storage *
struct mailbox_list_settings *list_set,
const char **error_r)
{
struct mail_storage *storage_class;
const char *home;
if (storage_class == NULL) {
"Unknown mail storage driver %s", driver);
return NULL;
}
return storage_class;
}
if (storage_class != NULL)
return storage_class;
"Mail storage autodetection failed with home=%s", home);
} else {
"Ambiguous mail location setting, "
"don't know what to do with it: %s "
"(try prefixing it with mbox: or maildir:)",
}
return NULL;
}
static int
{
/* storage doesn't use directories (e.g. shared root) */
return 0;
}
/* ok */
return 0;
return -1;
return -1;
/* can't create a new user, but we don't want to fail
the storage creation. */
} else if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
"Root mail directory doesn't exist: %s", root_dir);
return -1;
}
/* we need to create the root directory. */
return -1;
} else {
/* created */
return 0;
}
}
static struct mail_storage *
const struct mail_storage *storage_class,
const struct mailbox_list_settings *set)
{
((storage->class_flags &
MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) == 0 ||
return storage;
}
return NULL;
}
{
struct mailbox_list_settings list_set;
enum mailbox_list_flags list_flags = 0;
const char *p;
if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
/* if pop3_uidl_format contains %m, we want to keep the
header MD5 sums stored even if we're not running POP3
right now. */
if (p[1] == '%')
p += 2;
else if (var_get_key(++p) == 'm') {
break;
}
}
}
/* autodetect */
/* internal shared namespace */
} else {
error_r) < 0)
return -1;
}
if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0 &&
*error_r = "Root mail directory not given";
return -1;
}
if (storage_class == NULL)
return -1;
/* first storage for namespace */
list_flags, error_r) < 0)
return -1;
return -1;
}
/* using an existing storage */
return 0;
}
return -1;
}
T_BEGIN {
} T_END;
return 0;
}
{
}
{
return;
}
{
}
{
}
{
char str[256];
MAIL_ERRSTR_CRITICAL_MSG_STAMP, tm) > 0 ?
}
const char *fmt, ...)
{
/* critical errors may contain sensitive data, so let user
see only "Internal error" with a timestamp to make it
easier to look from log files the actual error message. */
}
}
struct mailbox_list *list)
{
const char *str;
enum mail_error error;
}
{
else
}
const struct mail_storage_settings *
{
}
{
}
struct mail_storage_callbacks *callbacks,
void *context)
{
}
{
}
enum mail_error *error_r)
{
/* We get here only in error situations, so we have to return some
error. If storage->error is NONE, it means we forgot to set it at
some point.. */
"BUG: Unknown internal error";
}
/* This shouldn't happen.. */
i_strdup_printf("BUG: Unknown 0x%x error",
}
return storage->error_string;
}
{
return (storage->class_flags &
}
{
const char *error_string;
enum mail_error error;
return FALSE;
/* debugging is enabled - admin may be debugging a
(permission) problem, so return FALSE to get the caller to
log the full error message. */
return FALSE;
}
return TRUE;
}
enum mailbox_flags flags)
{
struct mail_storage *storage;
/* just use the first storage. FIXME: does this break? */
}
T_BEGIN {
} T_END;
return box;
}
{
int ret;
return 0;
"Invalid mailbox name");
return -1;
}
MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) == 0) {
"Storage doesn't support streamed mailboxes");
return -1;
}
}
T_BEGIN {
} T_END;
if (ret < 0) {
return -1;
}
return 0;
}
{
}
{
}
{
}
{
return box->enabled_features;
}
{
return;
if (box->transaction_count != 0) {
i_panic("Trying to close mailbox %s with open transactions",
}
}
{
}
bool directory)
{
"Invalid mailbox name");
return -1;
}
directory) < 0) {
return -1;
}
}
{
}
{
struct mail_index_transaction *trans;
if (mail_index_transaction_commit(&trans) < 0) {
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. */
}
{
enum mail_error error;
int ret;
"Storage root can't be deleted");
return -1;
}
"INBOX can't be deleted.");
return -1;
}
if (mailbox_open(box) < 0) {
if (error != MAIL_ERROR_NOTFOUND)
return -1;
/* \noselect mailbox */
} else {
if (mailbox_mark_index_deleted(box) < 0)
return -1;
}
return ret;
}
{
}
struct mail_namespace *
{
}
{
}
{
}
{
}
{
}
{
}
{
return FALSE;
}
enum mailbox_status_items items,
struct mailbox_status *status_r)
{
}
{
"Storage doesn't support mailbox GUIDs");
}
if (mailbox_open(box) < 0)
return -1;
}
}
struct mailbox_sync_context *
{
struct mailbox_sync_context *ctx;
if (box->transaction_count != 0) {
i_panic("Trying to sync mailbox %s with open transactions",
}
T_BEGIN {
} T_END;
return ctx;
}
struct mailbox_sync_rec *sync_rec_r)
{
}
struct mailbox_sync_status *status_r)
{
}
{
struct mailbox_sync_context *ctx;
struct mailbox_sync_status status;
/* we don't care about mailbox's current state, so we might
as well fix inconsistency state */
}
}
{
}
{
}
struct mail_keywords **keywords_r)
{
const char *empty_keyword_list = NULL;
}
struct mail_keywords *
const char *const keywords[])
{
const char *empty_keyword_list = NULL;
struct mail_keywords *kw;
i_unreached();
return kw;
}
struct mail_keywords *
{
}
{
}
struct mail_keywords **_keywords)
{
}
const char **error_r)
{
}
{
}
{
}
{
}
{
return FALSE;
backend_uid, uid_r);
}
bool only_with_msgs)
{
else
}
{
struct mailbox_virtual_pattern pat;
} else {
}
}
struct mailbox_header_lookup_ctx *
{
}
{
}
{
return;
}
struct mail_search_context *
mailbox_search_init(struct mailbox_transaction_context *t,
struct mail_search_args *args,
const enum mail_sort_type *sort_program)
{
if (!args->simplified)
}
{
int ret;
return ret;
}
{
bool tryagain;
if (!tryagain)
return FALSE;
}
return TRUE;
}
{
return FALSE;
else {
return TRUE;
}
}
{
return ctx->seen_lost_data;
}
int mailbox_search_result_build(struct mailbox_transaction_context *t,
struct mail_search_args *args,
struct mail_search_result **result_r)
{
struct mail_search_context *ctx;
int ret;
if (ret < 0)
return ret;
}
struct mailbox_transaction_context *
{
struct mailbox_transaction_context *trans;
box->transaction_count++;
return trans;
}
int mailbox_transaction_commit(struct mailbox_transaction_context **t)
{
int ret;
/* Store changes temporarily so that plugins overriding
transaction_commit() can look at them. */
return ret;
}
struct mailbox_transaction_context **_t,
struct mail_transaction_commit_changes *changes_r)
{
struct mailbox_transaction_context *t = *_t;
t->box->transaction_count--;
}
{
struct mailbox_transaction_context *t = *_t;
t->box->transaction_count--;
t->box->v.transaction_rollback(t);
}
{
return box->transaction_count;
}
void mailbox_transaction_set_max_modseq(struct mailbox_transaction_context *t,
{
}
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;
return ctx;
}
enum mail_flags flags,
struct mail_keywords *keywords)
{
}
{
const char *const *keywords_list;
}
{
}
{
}
{
}
const char *envelope)
{
}
{
}
{
}
{
}
{
}
{
int ret;
"Saving messages not supported");
ret = -1;
} else {
}
if (ret < 0) {
return -1;
}
return 0;
}
{
}
{
int ret;
return ret;
}
{
}
{
int ret;
return ret;
}
{
}
{
"Mailbox was deleted under us");
}
{
const char *origin, *dir_origin;
return;
}
&dir_gid, &dir_origin);
}
int *fd_r)
{
int fd;
*fd_r = -1;
if (fd != -1) {
/* ok */
/* O_EXCL used, caller will handle this error */
return 0;
return -1;
return -1;
} else {
"open(%s, O_CREAT) failed: %m", path);
return -1;
}
/* ok */
} else {
"fchown(%s) failed: %m", path);
}
}
return 1;
}