mbox-storage.c revision 3c493c276f599d9b9cd10764876d648003046954
/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "istream.h"
#include "restrict-access.h"
#include "mkdir-parents.h"
#include "unlink-directory.h"
#include "mbox-storage.h"
#include "mbox-lock.h"
#include "mbox-file.h"
#include "mbox-sync-private.h"
#include "istream-raw-mbox.h"
#include "mail-copy.h"
#include "index-mail.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
/* How often to touch the dotlock file when using KEEP_LOCKED flag */
/* Assume that if atime < mtime, there are new mails. If it's good enough for
UW-IMAP, it's good enough for us. */
#define STAT_GET_MARKED(st) \
#define MBOX_LIST_CONTEXT(obj) \
struct mbox_mailbox_list {
const struct mbox_settings *set;
};
/* NOTE: must be sorted for istream-header-filter. Note that it's not such
a good idea to change this list, as the messages will then change from
client's point of view. So if you do it, change all mailboxes' UIDVALIDITY
so all caches are reset. */
const char *mbox_hide_headers[] = {
"Content-Length",
"Status",
"X-IMAP",
"X-IMAPbase",
"X-Keywords",
"X-Status",
"X-UID"
};
/* A bit ugly duplification of the above list. It's safe to modify this list
without bad side effects, just keep the list sorted. */
const char *mbox_save_drop_headers[] = {
"Content-Length",
"Status",
"X-Delivery-ID"
"X-IMAP",
"X-IMAPbase",
"X-Keywords",
"X-Status",
"X-UID"
};
extern struct mail_storage mbox_storage;
extern struct mailbox mbox_mailbox;
{
} else {
"%s failed with mbox file %s: %m",
}
return -1;
}
static const char *
enum mailbox_list_path_type type)
{
const char *path, *p;
if (type == MAILBOX_LIST_PATH_TYPE_CONTROL ||
if (p == NULL)
return "";
}
return path;
}
static struct mail_storage *mbox_storage_alloc(void)
{
struct mbox_storage *storage;
}
static int
const char **error_r ATTR_UNUSED)
{
const char *dir;
if (*dir != '\0') {
}
return 0;
}
struct mailbox_list_settings *set)
{
}
}
{
if (debug) {
i_debug("mbox autodetect: %s: stat(%s) failed: %m",
}
return FALSE;
}
if (debug) {
i_debug("mbox autodetect: %s: is a directory (%s)",
}
return FALSE;
}
if (debug) {
i_debug("mbox autodetect: %s: no R/W access (%s)",
}
return FALSE;
}
if (debug)
return TRUE;
}
{
if (debug) {
i_debug("mbox autodetect: %s: stat(%s) failed: %m",
}
return FALSE;
}
if (debug) {
i_debug("mbox autodetect: %s: is not a directory (%s)",
}
return FALSE;
}
if (debug) {
i_debug("mbox autodetect: %s: no R/W/X access (%s)",
}
return FALSE;
}
if (debug)
return TRUE;
}
{
return TRUE;
return TRUE;
return TRUE;
return FALSE;
}
{
if (debug)
i_debug("maildir: Home directory not set");
home = "";
}
return path;
return path;
return NULL;
}
static const char *
{
const char *path;
if (debug)
return path;
}
if (debug)
if (debug)
return path;
}
if (debug)
return NULL;
}
struct mailbox_list_settings *set)
{
const char *root_dir, *inbox_path;
if (inbox_path == NULL &&
/* using location=<INBOX> */
return FALSE;
}
if (debug)
i_debug("mbox: couldn't find root dir");
return FALSE;
}
}
if (inbox_path == NULL) {
debug);
}
return TRUE;
}
{
return FALSE;
else {
"stat(%s) failed: %m", path);
return FALSE;
}
}
}
static struct mailbox *
enum mailbox_flags flags)
{
struct mbox_mailbox *mbox;
mbox->mbox_ext_idx =
0, 16, 1);
}
{
const char *inbox_path, *rootdir;
int fd;
/* make sure inbox file itself exists */
/* try again with increased privileges */
(void)restrict_access_use_priv_gid();
}
if (fd != -1)
"mbox root directory can't be a file: %s "
rootdir);
return -1;
return -1;
"open(%s, O_CREAT) failed: %m", inbox_path);
return -1;
}
return 0;
}
{
}
{
const char *rootdir;
return -1;
}
}
/* if INBOX isn't under the root directory, it's probably in
}
return -1;
mbox->keep_lock_to =
}
}
return index_storage_mailbox_open(box);
}
{
int ret;
return 0;
}
/* make sure INBOX exists */
return -1;
return mbox_mailbox_open_existing(mbox);
}
return mbox_mailbox_open_existing(mbox);
else if (ret == 0) {
t_strdup_printf("Mailbox isn't selectable: %s",
return -1;
return -1;
return -1;
} else {
return -1;
}
}
static int
{
int ret;
if (mailbox_open(box) < 0)
return -1;
}
return ret;
}
static int
bool directory)
{
if (directory &&
return 0;
/* create the mbox file */
if (ret <= 0) {
if (ret == 0) {
"Mailbox already exists");
}
return -1;
}
}
{
const struct mail_index_header *hdr;
enum mbox_sync_flags sync_flags = 0;
/* clear the corruption by forcing a full resync */
}
/* we've done changes to mbox which haven't been
written yet. do it now. */
}
}
if (mbox->mbox_global_lock_id != 0)
}
static void
struct mailbox_status *status_r)
{
if ((items & STATUS_GUID) != 0) {
sizeof(status_r->mailbox_guid));
}
}
{
else if (!mbox->no_mbox_file)
}
static bool
{
const char *inbox_path;
return FALSE;
}
static bool mbox_name_is_dotlock(const char *name)
{
}
static bool
{
}
static bool
{
}
const char *mailbox_name ATTR_UNUSED,
enum mailbox_list_file_type type,
enum mailbox_info_flags *flags)
{
*flags |= MAILBOX_NOSELECT;
return 0;
}
return 0;
}
}
/* skip all .lock files */
return 0;
}
/* try to avoid stat() with these checks */
if (type == MAILBOX_LIST_FILE_TYPE_DIR) {
return 1;
}
if (type != MAILBOX_LIST_FILE_TYPE_SYMLINK &&
*flags |= MAILBOX_NOINFERIORS;
return 1;
}
/* need to stat() then */
else {
/* it's possible for INBOX to have child
mailboxes as long as the inbox file itself
isn't in <mail root>/INBOX */
*flags &= ~MAILBOX_NOINFERIORS;
}
}
return 1;
/* doesn't exist - probably a non-existing subscribed mailbox */
*flags |= MAILBOX_NONEXISTENT;
return 1;
} else {
/* non-selectable. probably either access denied, or symlink
destination not found. don't bother logging errors. */
*flags |= MAILBOX_NOSELECT;
return 0;
}
}
const char *name)
{
} else if (!mailbox_list_set_error_from_errno(list)) {
"lstat() failed for %s: %m", path);
}
return -1;
}
/* deleting a directory. allow it only if it doesn't contain
anything. Delete the ".imap" directory first in case there
have been indexes. */
if (!mailbox_list_set_error_from_errno(list)) {
"rmdir() failed for %s: %m", index_dir);
}
return -1;
}
return 0;
t_strdup_printf("Directory %s isn't empty, "
"can't delete it.", name));
} else if (!mailbox_list_set_error_from_errno(list)) {
"rmdir() failed for %s: %m", path);
}
return -1;
}
/* delete index / control files first */
return -1;
} else if (!mailbox_list_set_error_from_errno(list)) {
"unlink() failed for %s: %m", path);
}
return -1;
}
return 0;
}
struct mailbox_list *list)
{
struct mbox_mailbox_list *mlist;
/* have to use .imap/ directories */
}
}
static struct mailbox_transaction_context *
{
struct mbox_transaction_context *mt;
}
{
if (lock_id != 0)
if (mbox->mbox_global_lock_id == 0) {
} else {
/* mailbox opened with MAILBOX_FLAG_KEEP_LOCKED */
}
}
static int
struct mail_transaction_commit_changes *changes_r)
{
struct mbox_transaction_context *mt =
(struct mbox_transaction_context *)t;
int ret;
return ret;
}
static void
{
struct mbox_transaction_context *mt =
(struct mbox_transaction_context *)t;
}
struct mail_storage mbox_storage = {
.v = {
}
};
struct mailbox mbox_mailbox = {
.v = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
}
};