mbox-storage.c revision 5137d2d80255938a0f5fb8f3c1a21b34cf11ada3
/* Copyright (C) 2002-2003 Timo Sirainen */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "istream.h"
#include "mkdir-parents.h"
#include "unlink-directory.h"
#include "home-expand.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>
/* 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) \
/* 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;
enum mailbox_list_file_type type,
enum mailbox_info_flags *flags);
const char *name);
{
"Not enough disk space");
} else {
"%s failed with mbox file %s: %m",
}
return -1;
}
{
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 **layout_r)
{
const char *p;
bool autodetect;
*layout_r = "fs";
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)
{
const char *path, *p;
if (type == MAILBOX_LIST_PATH_TYPE_CONTROL ||
if (p == NULL)
return "";
}
return path;
}
static struct mail_storage *mbox_alloc(void)
{
struct mbox_storage *storage;
}
{
struct mailbox_list_settings list_set;
return -1;
return -1;
}
/* have to use .imap/ directories */
}
return 0;
}
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;
}
{
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 *
enum mailbox_open_flags flags)
{
struct mbox_mailbox *mbox;
mbox->mbox_ext_idx =
if ((flags & MAILBOX_OPEN_KEEP_LOCKED) != 0) {
mailbox_close(&box);
return NULL;
}
mbox->keep_lock_to =
}
}
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 */
index_dir = "";
}
else {
}
}
}
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 */
index_dir = "";
}
return NULL;
}
static struct mailbox *
{
/* make sure INBOX exists */
if (verify_inbox(_storage) < 0)
return NULL;
}
"Mailbox isn't selectable: %s", name);
return NULL;
}
}
} else if (mail_storage_errno2str(&error))
else {
path);
}
return NULL;
}
bool directory)
{
int fd;
/* make sure it doesn't exist already */
return -1;
}
"Mailbox doesn't allow inferior mailboxes");
} else if (mail_storage_errno2str(&error))
else {
"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 (mail_storage_errno2str(&error))
else {
"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 (mail_storage_errno2str(&error))
else {
"Can't create mailbox %s: %m", name);
}
return -1;
}
{
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 index_storage_mailbox_close(box);
}
{
else if (!mbox->no_mbox_file)
}
static bool
{
const char *inbox_path;
return FALSE;
}
enum mailbox_list_file_type type,
enum mailbox_info_flags *flags_r)
{
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 &&
return 1;
}
/* need to stat() then */
t_push();
else {
/* it's possible for INBOX to have child
mailboxes as long as the inbox file itself
isn't in <mail root>/INBOX */
*flags_r &= ~MAILBOX_NOINFERIORS;
}
}
ret = 0;
else {
ret = -1;
}
t_pop();
return ret;
}
const char *name)
{
} else if (mail_storage_errno2str(&error))
else {
"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 (mail_storage_errno2str(&error))
else {
"rmdir() failed for %s: %m", index_dir);
}
return -1;
}
return 0;
"Directory %s isn't empty, can't delete it.",
name));
} else if (mail_storage_errno2str(&error))
else {
"rmdir() failed for %s: %m", path);
}
return -1;
}
/* delete index / control files first */
return -1;
} else if (mail_storage_errno2str(&error))
else {
"unlink() failed for %s: %m", path);
}
return -1;
}
return 0;
}
static void mbox_class_init(void)
{
}
static void mbox_class_deinit(void)
{
}
struct mail_storage mbox_storage = {
{
NULL,
}
};
struct mailbox mbox_mailbox = {
{
NULL,
}
};