mbox-storage.c revision 2dd39e478269d6fb0bb26d12b394aa30ee965e38
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (C) 2002-2003 Timo Sirainen */
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include "lib.h"
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen#include "ioloop.h"
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen#include "array.h"
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen#include "istream.h"
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen#include "mkdir-parents.h"
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include "unlink-directory.h"
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen#include "home-expand.h"
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include "mbox-storage.h"
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include "mbox-lock.h"
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include "mbox-file.h"
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include "mbox-sync-private.h"
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include "mail-copy.h"
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include "index-mail.h"
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include <stdio.h>
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include <stdlib.h>
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include <unistd.h>
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include <fcntl.h>
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#include <sys/stat.h>
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#define CREATE_MODE 0770 /* umask() should limit it more */
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen/* How often to touch the dotlock file when using KEEP_LOCKED flag */
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#define MBOX_LOCK_TOUCH_MSECS (10*1000)
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen/* Assume that if atime < mtime, there are new mails. If it's good enough for
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen UW-IMAP, it's good enough for us. */
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#define STAT_GET_MARKED(st) \
2a325b952fe47346d76221d2c07a3fe02faf8800Timo Sirainen ((st).st_size == 0 ? MAILBOX_UNMARKED : \
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen (st).st_atime < (st).st_mtime ? MAILBOX_MARKED : MAILBOX_UNMARKED)
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen#define MBOX_LIST_CONTEXT(obj) \
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen MODULE_CONTEXT(obj, mbox_mailbox_list_module)
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen/* NOTE: must be sorted for istream-header-filter. Note that it's not such
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen a good idea to change this list, as the messages will then change from
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen client's point of view. So if you do it, change all mailboxes' UIDVALIDITY
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen so all caches are reset. */
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainenconst char *mbox_hide_headers[] = {
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "Content-Length",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "Status",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-IMAP",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-IMAPbase",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-Keywords",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-Status",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-UID"
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen};
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainenunsigned int mbox_hide_headers_count =
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen sizeof(mbox_hide_headers) / sizeof(mbox_hide_headers[0]);
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen/* A bit ugly duplification of the above list. It's safe to modify this list
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen without bad side effects, just keep the list sorted. */
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainenconst char *mbox_save_drop_headers[] = {
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "Content-Length",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "Status",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-Delivery-ID"
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-IMAP",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-IMAPbase",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-Keywords",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-Status",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "X-UID"
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen};
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainenunsigned int mbox_save_drop_headers_count =
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen sizeof(mbox_save_drop_headers) / sizeof(mbox_save_drop_headers[0]);
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainenextern struct mail_storage mbox_storage;
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainenextern struct mailbox mbox_mailbox;
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mbox_mailbox_list_module,
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen &mailbox_list_module_register);
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainenstatic int mbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen const char *dir, const char *fname,
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen enum mailbox_list_file_type type,
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen enum mailbox_info_flags *flags);
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainenstatic int mbox_list_delete_mailbox(struct mailbox_list *list,
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen const char *name);
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainenint mbox_set_syscall_error(struct mbox_mailbox *mbox, const char *function)
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen{
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen i_assert(function != NULL);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen if (ENOSPACE(errno)) {
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen mail_storage_set_error(&mbox->storage->storage,
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen } else {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen "%s failed with mbox file %s: %m",
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen function, mbox->path);
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen }
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen return -1;
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen}
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainenstatic bool mbox_is_file(const char *path, const char *name, bool debug)
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen{
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen struct stat st;
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen if (stat(path, &st) < 0) {
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen if (debug) {
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen i_info("mbox autodetect: %s: stat(%s) failed: %m",
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen name, path);
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen }
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen return FALSE;
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen }
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen if (S_ISDIR(st.st_mode)) {
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen if (debug) {
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen i_info("mbox autodetect: %s: is a directory (%s)",
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen name, path);
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen }
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen return FALSE;
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen }
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen if (access(path, R_OK|W_OK) < 0) {
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen if (debug) {
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen i_info("mbox autodetect: %s: no R/W access (%s)",
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen name, path);
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen }
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen return FALSE;
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen }
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen if (debug)
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen i_info("mbox autodetect: %s: yes (%s)", name, path);
de41dbb482990a4be10ca9033cf881a850ccdc50Timo Sirainen return TRUE;
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen}
de41dbb482990a4be10ca9033cf881a850ccdc50Timo Sirainen
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainenstatic bool mbox_is_dir(const char *path, const char *name, bool debug)
de41dbb482990a4be10ca9033cf881a850ccdc50Timo Sirainen{
de41dbb482990a4be10ca9033cf881a850ccdc50Timo Sirainen struct stat st;
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen if (stat(path, &st) < 0) {
27bb267255b36d34c638c34a1ade611962f00772Timo Sirainen if (debug) {
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen i_info("mbox autodetect: %s: stat(%s) failed: %m",
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen name, path);
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen }
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen return FALSE;
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen }
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen if (!S_ISDIR(st.st_mode)) {
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen if (debug) {
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen i_info("mbox autodetect: %s: is not a directory (%s)",
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen name, path);
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen }
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen return FALSE;
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen }
7237f2f0a577413e12662228ee2039425fd2f5b0Timo Sirainen if (access(path, R_OK|W_OK|X_OK) < 0) {
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen if (debug) {
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen i_info("mbox autodetect: %s: no R/W/X access (%s)",
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen name, path);
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen }
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen return FALSE;
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen }
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (debug)
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen i_info("mbox autodetect: %s: yes (%s)", name, path);
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen return TRUE;
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen}
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainenstatic bool mbox_autodetect(const char *data, enum mail_storage_flags flags)
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen{
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
a4a7440a1033203c48d5f0174b3d85514b79f3a0Timo Sirainen const char *path;
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen path = t_strcut(data, ':');
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (debug) {
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (strchr(data, ':') != NULL) {
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen i_info("mbox autodetect: data=%s, splitting ':' -> %s",
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen data, path);
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen } else {
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen i_info("mbox autodetect: data=%s", data);
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen }
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen }
77a41c18e6c37ea9d88a300173672746e29fe61bTimo Sirainen
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (*path != '\0' && mbox_is_file(path, "INBOX file", debug))
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen return TRUE;
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (mbox_is_dir(t_strconcat(path, "/"MBOX_INDEX_DIR_NAME, NULL),
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen "has "MBOX_INDEX_DIR_NAME"/", debug))
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen return TRUE;
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (mbox_is_file(t_strconcat(path, "/inbox", NULL), "has inbox", debug))
77a41c18e6c37ea9d88a300173672746e29fe61bTimo Sirainen return TRUE;
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (mbox_is_file(t_strconcat(path, "/mbox", NULL), "has mbox", debug))
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen return TRUE;
77a41c18e6c37ea9d88a300173672746e29fe61bTimo Sirainen
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen return FALSE;
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen}
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainenstatic const char *get_root_dir(enum mail_storage_flags flags)
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen{
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen const char *home, *path;
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen home = getenv("HOME");
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (home != NULL) {
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen path = t_strconcat(home, "/mail", NULL);
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (access(path, R_OK|W_OK|X_OK) == 0) {
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (debug)
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen i_info("mbox: root exists (%s)", path);
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen return path;
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen }
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (debug)
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen i_info("mbox: root: access(%s, rwx) failed: %m", path);
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen path = t_strconcat(home, "/Mail", NULL);
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (access(path, R_OK|W_OK|X_OK) == 0) {
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (debug)
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen i_info("mbox: root exists (%s)", path);
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen return path;
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen }
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (debug)
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen i_info("mbox: root: access(%s, rwx) failed: %m", path);
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen }
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (debug)
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen i_info("mbox: checking if we are chrooted:");
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (mbox_autodetect("", flags))
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen return "/";
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (debug)
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen i_info("mbox: root mail directory not found");
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen return NULL;
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen}
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainenstatic const char *
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainenget_inbox_file(const char *root_dir, bool only_root, bool debug)
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen{
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen const char *user, *path;
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (!only_root && (user = getenv("USER")) != NULL) {
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen path = t_strconcat("/var/mail/", user, NULL);
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (access(path, R_OK|W_OK) == 0) {
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (debug)
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen i_info("mbox: INBOX exists (%s)", path);
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen return path;
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen }
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (debug)
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi i_info("mbox: INBOX: access(%s, rw) failed: %m", path);
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi path = t_strconcat("/var/spool/mail/", user, NULL);
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi if (access(path, R_OK|W_OK) == 0) {
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi if (debug)
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi i_info("mbox: INBOX exists (%s)", path);
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen return path;
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen }
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi if (debug)
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi i_info("mbox: INBOX: access(%s, rw) failed: %m", path);
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi }
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi path = t_strconcat(root_dir, "/inbox", NULL);
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi if (debug)
169b1488b6eea7a968021afa4f929b2e26d75d98Timo Sirainen i_info("mbox: INBOX defaulted to %s", path);
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen return path;
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen}
de41dbb482990a4be10ca9033cf881a850ccdc50Timo Sirainen
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainenstatic const char *create_root_dir(bool debug, const char **error_r)
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen{
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen const char *home, *path;
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen home = getenv("HOME");
c7713320cd35e77543f1bdc7229988a160dae322Timo Sirainen if (home == NULL) {
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen *error_r = "Root mail directory not set and "
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen "home directory is missing";
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen return NULL;
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen }
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen path = t_strconcat(home, "/mail", NULL);
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen if (mkdir_parents(path, CREATE_MODE) < 0) {
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen *error_r = t_strdup_printf("mkdir(%s) failed: %m", path);
eba7f36feec8d02c4c394e55ff4effd47e33d311Timo Sirainen return NULL;
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen }
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen if (debug)
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen i_info("mbox: root directory created: %s", path);
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen return path;
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen}
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainen
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainenstatic int
d78f1ac9dc0f3e6c64cebe9ee331ec6b3c160e89Timo Sirainenmbox_get_list_settings(struct mailbox_list_settings *list_set,
const char *data, enum mail_storage_flags flags,
const char **layout_r, const char **error_r)
{
bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
const char *p;
struct stat st;
bool autodetect;
*layout_r = "fs";
memset(list_set, 0, sizeof(*list_set));
list_set->subscription_fname = MBOX_SUBSCRIPTION_FILE_NAME;
list_set->maildir_name = "";
autodetect = data == NULL || *data == '\0';
if (autodetect) {
if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0) {
*error_r = "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
either $HOME/mail or $HOME/Mail */
list_set->root_dir = get_root_dir(flags);
} else {
/* <root mail directory> | <INBOX path>
[:INBOX=<path>] [:INDEX=<dir>] */
if (debug)
i_info("mbox: data=%s", data);
p = strchr(data, ':');
if (p == NULL) {
/* if the data points to a file, treat it as an INBOX */
if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0 ||
stat(data, &st) < 0 || S_ISDIR(st.st_mode))
list_set->root_dir = data;
else {
list_set->root_dir = get_root_dir(flags);
list_set->inbox_path = data;
}
} else {
list_set->root_dir = t_strdup_until(data, p);
do {
p++;
if (strncmp(p, "INBOX=", 6) == 0) {
list_set->inbox_path =
t_strcut(p+6, ':');
} else if (strncmp(p, "INDEX=", 6) == 0) {
list_set->index_dir =
t_strcut(p+6, ':');
} else if (strncmp(p, "LAYOUT=", 7) == 0) {
*layout_r = t_strcut(p+7, ':');
}
p = strchr(p, ':');
} while (p != NULL);
}
}
if (list_set->root_dir == NULL || *list_set->root_dir == '\0') {
if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
*error_r = "Root mail directory not given";
return -1;
}
list_set->root_dir = create_root_dir(debug, error_r);
if (list_set->root_dir == NULL)
return -1;
} else {
/* strip trailing '/' */
size_t len = strlen(list_set->root_dir);
if (len > 1 && list_set->root_dir[len-1] == '/') {
list_set->root_dir =
t_strndup(list_set->root_dir, len-1);
}
list_set->root_dir = home_expand(list_set->root_dir);
/* make sure the directory exists */
if (*list_set->root_dir == '\0' ||
lstat(list_set->root_dir, &st) == 0) {
/* yep, go ahead */
} else if (errno != ENOENT && errno != ENOTDIR) {
*error_r = t_strdup_printf("lstat(%s) failed: %m",
list_set->root_dir);
return -1;
} else if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
*error_r = t_strdup_printf(
"Root mail directory doesn't exist: %s",
list_set->root_dir);
return -1;
} else if (mkdir_parents(list_set->root_dir, CREATE_MODE) < 0 &&
errno != EEXIST) {
*error_r = t_strdup_printf("mkdir(%s) failed: %m",
list_set->root_dir);
return -1;
}
}
if (list_set->inbox_path == NULL) {
list_set->inbox_path =
get_inbox_file(list_set->root_dir, !autodetect, debug);
}
if (list_set->index_dir != NULL &&
strcmp(list_set->index_dir, "MEMORY") == 0)
list_set->index_dir = "";
return 0;
}
static const char *
mbox_list_get_path(struct mailbox_list *list, const char *name,
enum mailbox_list_path_type type)
{
struct mbox_storage *storage = MBOX_LIST_CONTEXT(list);
const char *path, *p;
path = storage->list_module_ctx.super.get_path(list, name, type);
if (type == MAILBOX_LIST_PATH_TYPE_CONTROL ||
type == MAILBOX_LIST_PATH_TYPE_INDEX) {
p = strrchr(path, '/');
if (p == NULL)
return "";
return t_strconcat(t_strdup_until(path, p),
"/"MBOX_INDEX_DIR_NAME"/", p+1, NULL);
}
return path;
}
static struct mail_storage *mbox_alloc(void)
{
struct mbox_storage *storage;
pool_t pool;
pool = pool_alloconly_create("mbox storage", 512+256);
storage = p_new(pool, struct mbox_storage, 1);
storage->storage = mbox_storage;
storage->storage.pool = pool;
return &storage->storage;
}
static int mbox_create(struct mail_storage *_storage, const char *data,
const char **error_r)
{
struct mbox_storage *storage = (struct mbox_storage *)_storage;
struct mailbox_list_settings list_set;
const char *layout;
if (mbox_get_list_settings(&list_set, data,
_storage->flags, &layout, error_r) < 0)
return -1;
list_set.mail_storage_flags = &_storage->flags;
list_set.lock_method = &_storage->lock_method;
if (mailbox_list_init(_storage->ns, layout, &list_set,
mail_storage_get_list_flags(_storage->flags),
&_storage->list, error_r) < 0)
return -1;
storage->list_module_ctx.super = _storage->list->v;
if (strcmp(layout, "fs") == 0 && *list_set.maildir_name == '\0') {
/* have to use .imap/ directories */
_storage->list->v.get_path = mbox_list_get_path;
}
_storage->list->v.iter_is_mailbox = mbox_list_iter_is_mailbox;
_storage->list->v.delete_mailbox = mbox_list_delete_mailbox;
MODULE_CONTEXT_SET_FULL(_storage->list, mbox_mailbox_list_module,
storage, &storage->list_module_ctx);
return 0;
}
static int verify_inbox(struct mail_storage *storage)
{
const char *inbox_path, *rootdir;
int fd;
inbox_path = mailbox_list_get_path(storage->list, "INBOX",
MAILBOX_LIST_PATH_TYPE_MAILBOX);
rootdir = mailbox_list_get_path(storage->list, "",
MAILBOX_LIST_PATH_TYPE_DIR);
/* make sure inbox file itself exists */
fd = open(inbox_path, O_RDWR | O_CREAT | O_EXCL, 0660);
if (fd != -1)
(void)close(fd);
else if (errno == ENOTDIR &&
strncmp(inbox_path, rootdir, strlen(rootdir)) == 0) {
mail_storage_set_critical(storage,
"mbox root directory can't be a file: %s "
"(http://wiki.dovecot.org/MailLocation/Mbox)",
rootdir);
} else if (errno != EEXIST) {
mail_storage_set_critical(storage,
"open(%s, O_CREAT) failed: %m", inbox_path);
}
return 0;
}
static bool want_memory_indexes(struct mbox_storage *storage, const char *path)
{
const char *env;
struct stat st;
unsigned int min_size;
env = getenv("MBOX_MIN_INDEX_SIZE");
if (env == NULL)
return FALSE;
min_size = strtoul(env, NULL, 10);
if (min_size == 0)
return FALSE;
if (stat(path, &st) < 0) {
if (errno == ENOENT)
st.st_size = 0;
else {
mail_storage_set_critical(&storage->storage,
"stat(%s) failed: %m", path);
return FALSE;
}
}
return st.st_size / 1024 < min_size;
}
static void mbox_lock_touch_timeout(struct mbox_mailbox *mbox)
{
(void)file_dotlock_touch(mbox->mbox_dotlock);
}
static struct mbox_mailbox *
mbox_alloc_mailbox(struct mbox_storage *storage, struct mail_index *index,
const char *name, const char *path,
enum mailbox_open_flags flags)
{
struct mbox_mailbox *mbox;
pool_t pool;
pool = pool_alloconly_create("mbox mailbox", 1024+512);
mbox = p_new(pool, struct mbox_mailbox, 1);
mbox->ibox.box = mbox_mailbox;
mbox->ibox.box.pool = pool;
mbox->ibox.storage = &storage->storage;
mbox->ibox.mail_vfuncs = &mbox_mail_vfuncs;
mbox->ibox.index = index;
mbox->storage = storage;
mbox->path = p_strdup(mbox->ibox.box.pool, path);
mbox->mbox_fd = -1;
mbox->mbox_lock_type = F_UNLCK;
mbox->mbox_ext_idx =
mail_index_ext_register(index, "mbox", 0,
sizeof(uint64_t), sizeof(uint64_t));
mbox->mbox_very_dirty_syncs = getenv("MBOX_VERY_DIRTY_SYNCS") != NULL;
mbox->mbox_do_dirty_syncs = mbox->mbox_very_dirty_syncs ||
getenv("MBOX_DIRTY_SYNCS") != NULL;
if ((storage->storage.flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) != 0)
mbox->mbox_save_md5 = TRUE;
if ((flags & MAILBOX_OPEN_KEEP_LOCKED) != 0) {
if (mbox_lock(mbox, F_WRLCK, &mbox->mbox_global_lock_id) <= 0) {
struct mailbox *box = &mbox->ibox.box;
mailbox_close(&box);
return NULL;
}
if (mbox->mbox_dotlock != NULL) {
mbox->keep_lock_to =
timeout_add(MBOX_LOCK_TOUCH_MSECS,
mbox_lock_touch_timeout, mbox);
}
}
index_storage_mailbox_init(&mbox->ibox, name, flags,
want_memory_indexes(storage, path));
return mbox;
}
static struct mailbox *
mbox_open(struct mbox_storage *storage, const char *name,
enum mailbox_open_flags flags)
{
struct mail_storage *_storage = &storage->storage;
struct mbox_mailbox *mbox;
struct mail_index *index;
const char *path;
path = mailbox_list_get_path(_storage->list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
index = index_storage_alloc(_storage, name, flags, MBOX_INDEX_PREFIX);
mbox = mbox_alloc_mailbox(storage, index, name, path, flags);
if (access(path, R_OK|W_OK) < 0) {
if (errno < EACCES)
mbox_set_syscall_error(mbox, "access()");
else {
mbox->ibox.readonly = TRUE;
mbox->mbox_readonly = TRUE;
}
}
return &mbox->ibox.box;
}
static struct mailbox *
mbox_mailbox_open_stream(struct mbox_storage *storage, const char *name,
struct istream *input, enum mailbox_open_flags flags)
{
struct mail_storage *_storage = &storage->storage;
struct mail_index *index;
struct mbox_mailbox *mbox;
const char *path;
flags |= MAILBOX_OPEN_READONLY;
path = mailbox_list_get_path(_storage->list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
index = index_storage_alloc(_storage, name, flags, MBOX_INDEX_PREFIX);
mbox = mbox_alloc_mailbox(storage, index, name, path, flags);
if (mbox == NULL)
return NULL;
i_stream_ref(input);
mbox->mbox_file_stream = input;
mbox->mbox_readonly = TRUE;
mbox->no_mbox_file = TRUE;
mbox->path = "(read-only mbox stream)";
return &mbox->ibox.box;
}
static struct mailbox *
mbox_mailbox_open(struct mail_storage *_storage, const char *name,
struct istream *input, enum mailbox_open_flags flags)
{
struct mbox_storage *storage = (struct mbox_storage *)_storage;
const char *path;
struct stat st;
if (input != NULL)
return mbox_mailbox_open_stream(storage, name, input, flags);
if (strcmp(name, "INBOX") == 0) {
/* make sure INBOX exists */
if (verify_inbox(_storage) < 0)
return NULL;
return mbox_open(storage, "INBOX", flags);
}
path = mailbox_list_get_path(_storage->list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (stat(path, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
t_strdup_printf("Mailbox isn't selectable: %s",
name));
return NULL;
}
return mbox_open(storage, name, flags);
}
if (ENOTFOUND(errno)) {
mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
} else if (!mail_storage_set_error_from_errno(_storage)) {
mail_storage_set_critical(_storage, "stat(%s) failed: %m",
path);
}
return NULL;
}
static int mbox_mailbox_create(struct mail_storage *_storage, const char *name,
bool directory)
{
const char *path, *p;
struct stat st;
int fd;
/* make sure it doesn't exist already */
path = mailbox_list_get_path(_storage->list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (stat(path, &st) == 0) {
mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox already exists");
return -1;
}
if (errno != ENOENT) {
if (errno == ENOTDIR) {
mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox doesn't allow inferior mailboxes");
} else if (!mail_storage_set_error_from_errno(_storage)) {
mail_storage_set_critical(_storage,
"stat() failed for mbox file %s: %m", path);
}
return -1;
}
/* create the hierarchy if needed */
p = directory ? path + strlen(path) : strrchr(path, '/');
if (p != NULL) {
p = t_strdup_until(path, p);
if (mkdir_parents(p, CREATE_MODE) < 0) {
if (!mail_storage_set_error_from_errno(_storage)) {
mail_storage_set_critical(_storage,
"mkdir_parents(%s) failed: %m", p);
}
return -1;
}
if (directory) {
/* wanted to create only the directory */
return 0;
}
}
/* create the mailbox file */
fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0660);
if (fd != -1) {
(void)close(fd);
return 0;
}
if (errno == EEXIST) {
/* mailbox was just created between stat() and open() call.. */
mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox already exists");
} else if (!mail_storage_set_error_from_errno(_storage)) {
mail_storage_set_critical(_storage,
"Can't create mailbox %s: %m", name);
}
return -1;
}
static int mbox_storage_mailbox_close(struct mailbox *box)
{
struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
const struct mail_index_header *hdr;
int ret = 0;
if (mbox->ibox.view != NULL) {
hdr = mail_index_get_header(mbox->ibox.view);
if ((hdr->flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0 &&
!mbox->mbox_readonly) {
/* we've done changes to mbox which haven't been
written yet. do it now. */
if (mbox_sync(mbox, MBOX_SYNC_REWRITE) < 0)
ret = -1;
}
}
if (mbox->mbox_global_lock_id != 0)
(void)mbox_unlock(mbox, mbox->mbox_global_lock_id);
if (mbox->keep_lock_to != NULL)
timeout_remove(&mbox->keep_lock_to);
mbox_file_close(mbox);
if (mbox->mbox_file_stream != NULL)
i_stream_destroy(&mbox->mbox_file_stream);
return index_storage_mailbox_close(box);
}
static void mbox_notify_changes(struct mailbox *box)
{
struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
if (box->notify_callback == NULL)
index_mailbox_check_remove_all(&mbox->ibox);
else if (!mbox->no_mbox_file)
index_mailbox_check_add(&mbox->ibox, mbox->path);
}
static bool
is_inbox_file(struct mailbox_list *list, const char *path, const char *fname)
{
const char *inbox_path;
if (strcasecmp(fname, "INBOX") != 0)
return FALSE;
inbox_path = mailbox_list_get_path(list, "INBOX",
MAILBOX_LIST_PATH_TYPE_MAILBOX);
return strcmp(inbox_path, path) == 0;
}
static int mbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
const char *dir, const char *fname,
enum mailbox_list_file_type type,
enum mailbox_info_flags *flags_r)
{
struct mail_storage *storage = MBOX_LIST_CONTEXT(ctx->list);
const char *path, *root_dir;
size_t len;
struct stat st;
int ret = 1;
if (strcmp(fname, MBOX_INDEX_DIR_NAME) == 0) {
*flags_r = MAILBOX_NOSELECT;
return 0;
}
if (strcmp(fname, MBOX_SUBSCRIPTION_FILE_NAME) == 0) {
root_dir = mailbox_list_get_path(storage->list, NULL,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (strcmp(root_dir, dir) == 0) {
*flags_r = MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
return 0;
}
}
/* skip all .lock files */
len = strlen(fname);
if (len > 5 && strcmp(fname+len-5, ".lock") == 0) {
*flags_r = MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
return 0;
}
/* try to avoid stat() with these checks */
if (type == MAILBOX_LIST_FILE_TYPE_DIR) {
*flags_r = MAILBOX_NOSELECT | MAILBOX_CHILDREN;
return 1;
}
if (type != MAILBOX_LIST_FILE_TYPE_SYMLINK &&
type != MAILBOX_LIST_FILE_TYPE_UNKNOWN &&
(ctx->flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) != 0) {
*flags_r = MAILBOX_NOINFERIORS;
return 1;
}
/* need to stat() then */
t_push();
path = t_strconcat(dir, "/", fname, NULL);
if (stat(path, &st) == 0) {
if (S_ISDIR(st.st_mode))
*flags_r = MAILBOX_NOSELECT | MAILBOX_CHILDREN;
else {
*flags_r = MAILBOX_NOINFERIORS | STAT_GET_MARKED(st);
if (is_inbox_file(ctx->list, path, fname) &&
strcmp(fname, "INBOX") != 0) {
/* 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;
}
}
} else if (errno == EACCES || errno == ELOOP)
*flags_r = MAILBOX_NOSELECT;
else if (ENOTFOUND(errno)) {
*flags_r = MAILBOX_NONEXISTENT;
ret = 0;
} else {
mail_storage_set_critical(storage, "stat(%s) failed: %m", path);
ret = -1;
}
t_pop();
return ret;
}
static int mbox_list_delete_mailbox(struct mailbox_list *list,
const char *name)
{
struct mbox_storage *storage = MBOX_LIST_CONTEXT(list);
struct stat st;
const char *path, *index_dir;
path = mailbox_list_get_path(list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (lstat(path, &st) < 0) {
if (ENOTFOUND(errno)) {
mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
} else if (!mailbox_list_set_error_from_errno(list)) {
mailbox_list_set_critical(list,
"lstat() failed for %s: %m", path);
}
return -1;
}
if (S_ISDIR(st.st_mode)) {
/* deleting a directory. allow it only if it doesn't contain
anything. Delete the ".imap" directory first in case there
have been indexes. */
index_dir = mailbox_list_get_path(list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
index_dir = *index_dir == '\0' ? "" :
t_strconcat(index_dir, "/"MBOX_INDEX_DIR_NAME, NULL);
if (*index_dir != '\0' && rmdir(index_dir) < 0 &&
!ENOTFOUND(errno) && errno != ENOTEMPTY) {
if (!mailbox_list_set_error_from_errno(list)) {
mailbox_list_set_critical(list,
"rmdir() failed for %s: %m", index_dir);
}
return -1;
}
if (rmdir(path) == 0)
return 0;
if (ENOTFOUND(errno)) {
mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
} else if (errno == ENOTEMPTY) {
mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
t_strdup_printf("Directory %s isn't empty, "
"can't delete it.", name));
} else if (!mailbox_list_set_error_from_errno(list)) {
mailbox_list_set_critical(list,
"rmdir() failed for %s: %m", path);
}
return -1;
}
/* delete index / control files first */
index_storage_destroy_unrefed();
if (storage->list_module_ctx.super.delete_mailbox(list, name) < 0)
return -1;
if (unlink(path) < 0) {
if (ENOTFOUND(errno)) {
mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
} else if (!mailbox_list_set_error_from_errno(list)) {
mailbox_list_set_critical(list,
"unlink() failed for %s: %m", path);
}
return -1;
}
return 0;
}
static void mbox_class_init(void)
{
mbox_transaction_class_init();
}
static void mbox_class_deinit(void)
{
mbox_transaction_class_deinit();
}
struct mail_storage mbox_storage = {
MEMBER(name) MBOX_STORAGE_NAME,
MEMBER(mailbox_is_file) TRUE,
{
mbox_class_init,
mbox_class_deinit,
mbox_alloc,
mbox_create,
NULL,
mbox_autodetect,
mbox_mailbox_open,
mbox_mailbox_create
}
};
struct mailbox mbox_mailbox = {
MEMBER(name) NULL,
MEMBER(storage) NULL,
{
index_storage_is_readonly,
index_storage_allow_new_keywords,
mbox_storage_mailbox_close,
index_storage_get_status,
mbox_storage_sync_init,
index_mailbox_sync_next,
index_mailbox_sync_deinit,
NULL,
mbox_notify_changes,
index_transaction_begin,
index_transaction_commit,
index_transaction_rollback,
index_keywords_create,
index_keywords_free,
index_storage_get_uids,
index_mail_alloc,
index_header_lookup_init,
index_header_lookup_deinit,
index_storage_search_init,
index_storage_search_deinit,
index_storage_search_next_nonblock,
index_storage_search_next_update_seq,
mbox_save_init,
mbox_save_continue,
mbox_save_finish,
mbox_save_cancel,
mail_storage_copy,
index_storage_is_inconsistent
}
};