mbox-storage.c revision df9db9faf9c3a145a930abb0ec1f13a60ea65703
/* Copyright (C) 2002-2003 Timo Sirainen */
#include "lib.h"
#include "buffer.h"
#include "istream.h"
#include "home-expand.h"
#include "mkdir-parents.h"
#include "unlink-directory.h"
#include "subscription-file/subscription-file.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>
/* Don't allow creating too long mailbox names. They could start causing
problems when they reach the limit. */
/* 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]);
extern struct mail_storage mbox_storage;
extern struct mailbox mbox_mailbox;
{
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 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 IMAP folder, "
"but can't find it or HOME environment");
return NULL;
}
return NULL;
}
if (debug)
return path;
}
static struct mail_storage *
{
struct mbox_storage *storage;
struct index_storage *istorage;
bool autodetect;
if (autodetect) {
/* we'll need to figure out the mail location ourself.
it's root dir if we've already chroot()ed, otherwise
} else {
/* <root folder> | <INBOX path>
[:INBOX=<path>] [:INDEX=<dir>] */
if (debug)
if (p == NULL) {
/* if the data points to a file, treat it as an INBOX */
else {
inbox_file = data;
}
} else {
do {
p++;
p = strchr(p, ':');
} while (p != NULL);
}
}
return NULL;
} else {
/* strip trailing '/' */
/* make sure the directory exists */
if (*root_dir == '\0' ||
/* yep, go ahead */
return NULL;
return NULL;
}
}
if (inbox_file == NULL)
if (debug) {
i_info("mbox: root=%s, index=%s, inbox=%s",
}
}
{
}
{
const char *p;
bool newdir;
return TRUE;
/* make sure it's not absolute path */
return FALSE;
/* make sure the mailbox name doesn't contain any foolishness:
"../" could give access outside the mailbox directory.
"./" and "//" could fool ACL checks. */
for (p = mask; *p != '\0'; p++) {
if (newdir) {
if (p[0] == '/')
return FALSE; /* // */
if (p[0] == '.') {
if (p[1] == '/')
return FALSE; /* ./ */
if (p[1] == '.' && p[2] == '/')
return FALSE; /* ../ */
}
}
newdir = p[0] == '/';
}
return TRUE;
}
const char *name)
{
return FALSE;
}
const char *name)
{
return FALSE;
}
const char *name)
{
const char *p;
return NULL;
}
if (p == NULL) {
} else {
t_strdup_until(name, p),
}
}
const char *name)
{
const char *index_dir;
return 0;
"mkdir_parents(%s) failed: %m", index_dir);
return -1;
}
return 0;
}
{
int fd;
/* make sure inbox file itself exists */
if (fd != -1)
}
return 0;
}
static const char *
{
return storage->inbox_path;
return home_expand(name);
}
{
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;
/* the memory is already freed here, no need to deinit */
return NULL;
}
mbox->mbox_ext_idx =
return mbox;
}
static struct mailbox *
enum mailbox_open_flags flags)
{
struct mbox_mailbox *mbox;
struct mail_index *index;
/* name = "INBOX"
path = "<inbox_file>/INBOX"
} else {
}
if ((flags & MAILBOX_OPEN_NO_INDEX_FILES) != 0)
/* make sure the index directories exist */
return NULL;
}
return NULL;
else {
}
}
}
static struct mailbox *
{
struct mail_index *index;
struct mbox_mailbox *mbox;
if ((flags & MAILBOX_OPEN_NO_INDEX_FILES) != 0)
else {
/* make sure the required directories are also there */
return NULL;
}
return NULL;
}
static const char *
{
if (*name == '\0') {
}
}
static const char *
{
}
static struct mailbox *
{
const char *path;
/* make sure INBOX exists */
if (verify_inbox(istorage) < 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 folder, only allow it if it's empty.
Delete .imap folder before to make sure it goes empty. */
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;
}
/* first unlink the mbox file */
} else if (!mbox_handle_errors(storage)) {
"unlink() failed for %s: %m", path);
}
return -1;
}
/* next delete the index directory */
"unlink_directory(%s) failed: %m", index_dir);
/* mailbox itself is deleted, so return success
anyway */
}
}
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 != NULL) {
"rename(%s, %s) failed: %m",
}
}
return 0;
}
{
const char *path;
}
const char *name,
enum mailbox_name_status *status)
{
const char *path;
return 0;
}
return 0;
}
return 0;
}
return 0;
return 0;
} else {
"stat(%s) failed: %m", path);
return -1;
}
}
{
const struct mail_index_header *hdr;
int ret = 0;
/* we've done changes to mbox which haven't been written yet.
do it now. */
ret = -1;
}
return ret;
}
static void
{
else if (!mbox->no_mbox_file)
}
struct mail_storage mbox_storage = {
{
}
};
struct mailbox mbox_mailbox = {
{
}
};