mbox-storage.c revision a8a89d6265c9bbaf814d8146c93e39609d6e4da2
/* Copyright (C) 2002-2003 Timo Sirainen */
#include "lib.h"
#include "array.h"
#include "istream.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 "mail-copy.h"
#include "index-mail.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
/* 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) \
/* 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"
};
unsigned int mbox_hide_headers_count =
sizeof(mbox_hide_headers) / sizeof(mbox_hide_headers[0]);
/* 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"
};
unsigned int mbox_save_drop_headers_count =
sizeof(mbox_save_drop_headers) / sizeof(mbox_save_drop_headers[0]);
extern struct mail_storage mbox_storage;
extern struct mailbox mbox_mailbox;
static bool mbox_mailbox_list_module_id_set = FALSE;
static unsigned int mbox_mailbox_list_module_id;
{
return -1;
}
{
else
return FALSE;
return TRUE;
}
{
if (debug) {
i_info("mbox autodetect: %s: stat(%s) failed: %m",
}
return FALSE;
}
if (debug) {
i_info("mbox autodetect: %s: is a directory (%s)",
}
return FALSE;
}
if (debug) {
i_info("mbox autodetect: %s: no R/W access (%s)",
}
return FALSE;
}
if (debug)
return TRUE;
}
{
if (debug) {
i_info("mbox autodetect: %s: stat(%s) failed: %m",
}
return FALSE;
}
if (debug) {
i_info("mbox autodetect: %s: is not a directory (%s)",
}
return FALSE;
}
if (debug) {
i_info("mbox autodetect: %s: no R/W/X access (%s)",
}
return FALSE;
}
if (debug)
return TRUE;
}
{
const char *path;
if (debug) {
i_info("mbox autodetect: data=%s, splitting ':' -> %s",
} else {
}
}
return TRUE;
return TRUE;
return TRUE;
return TRUE;
return FALSE;
}
{
if (debug)
return path;
}
if (debug)
if (debug)
return path;
}
if (debug)
}
if (debug)
i_info("mbox: checking if we are chrooted:");
return "/";
if (debug)
i_info("mbox: root mail directory not found");
return NULL;
}
static const char *
{
if (debug)
return path;
}
if (debug)
if (debug)
return path;
}
if (debug)
}
if (debug)
return path;
}
static const char *create_root_dir(bool debug)
{
i_error("mbox: We need root mail directory, "
"but can't find it or HOME environment");
return NULL;
}
return NULL;
}
if (debug)
return path;
}
static int
{
const char *p;
bool autodetect;
if (autodetect) {
if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0) {
i_error("mbox: root mail directory not given");
return -1;
}
/* we'll need to figure out the mail location ourself.
it's root dir if we've already chroot()ed, otherwise
} else {
/* <root mail directory> | <INBOX path>
[:INBOX=<path>] [:INDEX=<dir>] */
if (debug)
if (p == NULL) {
/* if the data points to a file, treat it as an INBOX */
if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0 ||
else {
}
} else {
do {
p++;
}
p = strchr(p, ':');
} while (p != NULL);
}
}
if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0)
return -1;
return -1;
} else {
/* strip trailing '/' */
}
/* make sure the directory exists */
/* yep, go ahead */
return -1;
} else if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
return -1;
i_error("mkdir_parents(%s) failed: %m",
return -1;
}
}
}
return 0;
}
static const char *
enum mailbox_list_path_type type)
{
struct mbox_storage *storage =
const char *path, *p;
if (type == MAILBOX_LIST_PATH_TYPE_CONTROL ||
if (p == NULL)
return "";
}
return path;
}
static struct mail_storage *
enum file_lock_method lock_method)
{
struct mbox_storage *storage;
struct index_storage *istorage;
struct mailbox_list_settings list_set;
struct mailbox_list *list;
const char *error;
return NULL;
return NULL;
}
if (!mbox_mailbox_list_module_id_set) {
}
}
{
}
const char *name)
{
const char *index_dir;
if (*index_dir == '\0')
return 0;
"mkdir_parents(%s) failed: %m", index_dir);
return -1;
}
return 0;
}
{
const char *inbox_path;
int fd;
/* make sure inbox file itself exists */
if (fd != -1)
"open(%s, O_CREAT) failed: %m", inbox_path);
}
return 0;
}
{
return FALSE;
}
{
const char *env;
unsigned int min_size;
return FALSE;
if (min_size == 0)
return FALSE;
else {
"stat(%s) failed: %m", path);
return FALSE;
}
}
}
static struct mbox_mailbox *
{
struct mbox_mailbox *mbox;
mbox->mbox_ext_idx =
return mbox;
}
static struct mailbox *
enum mailbox_open_flags flags)
{
struct mbox_mailbox *mbox;
struct mail_index *index;
if ((flags & MAILBOX_OPEN_NO_INDEX_FILES) != 0)
index_dir = "";
if (*index_dir != '\0') {
/* make sure the index directories exist */
return NULL;
}
else {
}
}
mailbox_close(&box);
return NULL;
}
}
}
static struct mailbox *
{
struct mail_index *index;
struct mbox_mailbox *mbox;
if ((flags & MAILBOX_OPEN_NO_INDEX_FILES) != 0)
index_dir = "";
else {
/* make sure the required directories are also there */
return NULL;
}
return NULL;
}
static struct mailbox *
{
const char *path;
/* make sure INBOX exists */
if (verify_inbox(_storage) < 0)
return NULL;
}
return NULL;
}
"Mailbox isn't selectable: %s", name);
return NULL;
}
}
} else if (!mbox_handle_errors(istorage)) {
path);
}
return NULL;
}
bool directory)
{
const char *path, *p;
int fd;
return -1;
}
/* We might actually be able to create mailboxes under INBOX
because the real INBOX file isn't usually named as INBOX
in the root mail directory. that would anyway be a special
case which would require special handling elsewhere, so just
don't allow it. */
"Mailbox doesn't allow inferior mailboxes");
return -1;
}
/* make sure it doesn't exist already */
return -1;
}
"Mailbox doesn't allow inferior mailboxes");
} else if (!mbox_handle_errors(storage)) {
"stat() failed for mbox file %s: %m", path);
}
return -1;
}
/* create the hierarchy if needed */
if (p != NULL) {
p = t_strdup_until(path, p);
if (mkdir_parents(p, CREATE_MODE) < 0) {
if (mbox_handle_errors(storage))
return -1;
"mkdir_parents(%s) failed: %m", p);
return -1;
}
if (directory) {
/* wanted to create only the directory */
return 0;
}
}
/* create the mailbox file */
if (fd != -1) {
return 0;
}
/* mailbox was just created between stat() and open() call.. */
} else if (!mbox_handle_errors(storage)) {
"Can't create mailbox %s: %m", name);
}
return -1;
}
{
return -1;
}
return -1;
}
} else if (!mbox_handle_errors(storage)) {
"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 (!mbox_handle_errors(storage)) {
"rmdir() failed for %s: %m", index_dir);
return -1;
}
}
return 0;
"Folder %s isn't empty, can't delete it.",
name);
} else if (!mbox_handle_errors(storage)) {
"rmdir() failed for %s: %m", path);
}
return -1;
}
/* delete the index directory first, so that if we crash we don't
leave indexes for deleted mailboxes lying around */
if (*index_dir != '\0') {
"unlink_directory(%s) failed: %m", index_dir);
return -1;
}
}
} else if (!mbox_handle_errors(storage)) {
"unlink() failed for %s: %m", path);
}
return -1;
}
return 0;
}
{
return -1;
}
/* Not allowed - see explanation in mbox_mailbox_create */
"Target mailbox doesn't allow inferior mailboxes");
return -1;
}
/* create the hierarchy */
if (p != NULL) {
p = t_strdup_until(newpath, p);
if (mkdir_parents(p, CREATE_MODE) < 0) {
if (mbox_handle_errors(storage))
return -1;
"mkdir_parents(%s) failed: %m", p);
return -1;
}
}
/* first check that the destination mailbox doesn't exist.
this is racy, but we need to be atomic and there's hardly any
possibility that someone actually tries to rename two mailboxes
to same new one */
"Target mailbox already exists");
return -1;
"Target mailbox doesn't allow inferior mailboxes");
return -1;
newpath);
return -1;
}
/* NOTE: renaming INBOX works just fine with us, it's simply recreated
the next time it's needed. */
} else if (!mbox_handle_errors(storage)) {
}
return -1;
}
/* we need to rename the index directory as well */
if (*old_indexdir != '\0') {
"rename(%s, %s) failed: %m",
}
}
return 0;
}
{
const struct mail_index_header *hdr;
int ret = 0;
!mbox->mbox_readonly) {
/* we've done changes to mbox which haven't been written yet.
do it now. */
ret = -1;
}
if (mbox->mbox_global_lock_id != 0)
return ret;
}
static void
{
else if (!mbox->no_mbox_file)
}
enum mailbox_info_flags *flags,
enum mailbox_list_file_type type)
{
int ret = 1;
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 &&
(iter_flags & MAILBOX_LIST_ITER_FAST_FLAGS) != 0) {
*flags |= MAILBOX_NOINFERIORS;
return 1;
}
/* need to stat() then */
t_push();
else
*flags |= MAILBOX_NOSELECT;
ret = 0;
else {
ret = -1;
}
t_pop();
return ret;
}
static void mbox_class_init(void)
{
}
static void mbox_class_deinit(void)
{
}
struct mail_storage mbox_storage = {
{
}
};
struct mailbox mbox_mailbox = {
{
}
};