maildir-storage.c revision cafbfb142d25594144b99542c9d67f7484cad470
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (C) 2002-2006 Timo Sirainen */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "ioloop.h"
dfa2201c6ac8ddb2d2798dee15662cfe774e644eMartti Rannanjärvi#include "array.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "hostpid.h"
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen#include "home-expand.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen#include "mkdir-parents.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "unlink-directory.h"
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include "maildir-storage.h"
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen#include "maildir-uidlist.h"
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen#include "maildir-keywords.h"
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen#include "maildir-sync.h"
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen#include "index-mail.h"
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen#include <stdio.h>
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen#include <stdlib.h>
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include <unistd.h>
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen#include <sys/stat.h>
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
13d98ffa534f2e7d04a832c9d0153fc9c568b878Timo Sirainen#define CREATE_MODE 0777 /* umask() should limit it more */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#define MAILDIR_PLUSPLUS_DRIVER_NAME "maildir++"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#define MAILDIR_SUBFOLDER_FILENAME "maildirfolder"
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainenstruct rename_context {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen bool found;
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen size_t oldnamelen;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *newname;
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen};
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenextern struct mail_storage maildir_storage;
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenextern struct mailbox maildir_mailbox;
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenstatic const char *maildirs[] = { "cur", "new", "tmp", NULL };
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenstatic int verify_inbox(struct mail_storage *storage);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainenstatic const char *strip_tail_slash(const char *path)
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen{
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen size_t len = strlen(path);
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (len > 0 && path[len-1] == '/')
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen return t_strndup(path, len-1);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen else
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen return path;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen}
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic const char *strip_tail_slash_and_cut(const char *path)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen{
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen return strip_tail_slash(t_strcut(path, ':'));
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen}
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenmaildir_get_list_settings(struct mailbox_list_settings *list_set,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *data, enum mail_storage_flags flags)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *home, *path, *p;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen memset(list_set, 0, sizeof(*list_set));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list_set->subscription_fname = MAILDIR_SUBSCRIPTION_FILE_NAME;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list_set->maildir_name = "";
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (data == NULL || *data == '\0') {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("maildir: root directory not given");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return -1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen /* we'll need to figure out the maildir location ourself.
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen It's $HOME/Maildir unless we are chrooted. */
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if ((home = getenv("HOME")) != NULL) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen path = t_strconcat(home, "/Maildir", NULL);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (access(path, R_OK|W_OK|X_OK) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (debug) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_info("maildir: root exists (%s)",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen path);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list_set->root_dir = path;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (debug) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_info("maildir: access(%s, rwx): "
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "failed: %m", path);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (debug)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_info("maildir: HOME not set");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (access("/cur", R_OK|W_OK|X_OK) == 0) {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (debug)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen i_info("maildir: /cur exists, assuming chroot");
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen list_set->root_dir = "/";
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen } else {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen /* <Maildir> [:INBOX=<dir>] [:INDEX=<dir>] [:CONTROL=<dir>] */
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (debug)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen i_info("maildir: data=%s", data);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen p = strchr(data, ':');
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (p == NULL)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen list_set->root_dir = data;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen else {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list_set->root_dir = t_strdup_until(data, p);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen do {
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen p++;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strncmp(p, "INBOX=", 6) == 0) {
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek list_set->inbox_path =
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen strip_tail_slash_and_cut(p+6);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else if (strncmp(p, "INDEX=", 6) == 0) {
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen list_set->index_dir =
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen strip_tail_slash_and_cut(p+6);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen } else if (strncmp(p, "CONTROL=", 8) == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list_set->control_dir =
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen strip_tail_slash_and_cut(p+8);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek p = strchr(p, ':');
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen } while (p != NULL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek if (list_set->root_dir == NULL) {
63e207529879438e9f4412d97cdc34bdc82a3702Timo Sirainen if (debug)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen i_info("maildir: couldn't find root dir");
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return -1;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek list_set->root_dir = strip_tail_slash(list_set->root_dir);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (list_set->index_dir != NULL &&
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen strcmp(list_set->index_dir, "MEMORY") == 0)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen list_set->index_dir = "";
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return 0;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen}
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenstatic struct mail_storage *
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipekmaildir_create(const char *data, const char *user,
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen enum mail_storage_flags flags,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen enum mail_storage_lock_method lock_method)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct maildir_storage *storage;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct index_storage *istorage;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen struct mailbox_list_settings list_set;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen struct mailbox_list *list;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen const char *error;
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen struct stat st;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen pool_t pool;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (maildir_get_list_settings(&list_set, data, flags) < 0)
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen return NULL;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen list_set.mail_storage_flags = &flags;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen list_set.mail_storage_lock_method = &lock_method;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen /* normally the maildir is created in verify_inbox() */
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen if (stat(list_set.root_dir, &st) < 0) {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (errno != ENOENT) {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen i_error("stat(%s) failed: %m",
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen list_set.root_dir);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen pool = pool_alloconly_create("storage", 512);
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen storage = p_new(pool, struct maildir_storage, 1);
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (mailbox_list_init("maildir++", &list_set,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_storage_get_list_flags(flags),
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mailbox_storage_list_is_mailbox, storage,
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen &list, &error) < 0) {
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen i_error("maildir++: %s", error);
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen pool_unref(pool);
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen return NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen storage->copy_with_hardlinks =
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen getenv("MAILDIR_COPY_WITH_HARDLINKS") != NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen storage->stat_dirs = getenv("MAILDIR_STAT_DIRS") != NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen storage->temp_prefix = mailbox_list_get_temp_prefix(list);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (list_set.control_dir == NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* put the temp files into tmp/ directory preferrably */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen storage->temp_prefix =
f0d09be40bd0c4423873128ae2f88a4020075dc4Timo Sirainen p_strconcat(pool, "tmp/", storage->temp_prefix, NULL);
f0d09be40bd0c4423873128ae2f88a4020075dc4Timo Sirainen }
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen istorage = INDEX_STORAGE(storage);
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen istorage->storage = maildir_storage;
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen istorage->storage.pool = pool;
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen istorage->user = p_strdup(pool, user);
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen istorage->callbacks = p_new(pool, struct mail_storage_callbacks, 1);
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen index_storage_init(istorage, list, flags, lock_method);
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen (void)verify_inbox(STORAGE(storage));
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen return STORAGE(storage);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk}
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volkstatic void maildir_free(struct mail_storage *_storage)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen{
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk struct index_storage *storage = (struct index_storage *) _storage;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk index_storage_deinit(storage);
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen pool_unref(storage->storage.pool);
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainenstatic bool maildir_autodetect(const char *data, enum mail_storage_flags flags)
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen{
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen struct stat st;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const char *path;
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen data = t_strcut(data, ':');
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen path = t_strconcat(data, "/cur", NULL);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (stat(path, &st) < 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (debug)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen i_info("maildir autodetect: stat(%s) failed: %m", path);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return FALSE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (!S_ISDIR(st.st_mode)) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (debug)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen i_info("maildir autodetect: %s not a directory", path);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return FALSE;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen }
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return TRUE;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen}
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenstatic const char *
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenmaildir_get_unlink_dest(struct mail_storage *storage, const char *name)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen{
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen const char *root_dir;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if ((storage->flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen (*name == '/' || *name == '~'))
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return NULL;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (strcmp(mailbox_list_get_driver_name(storage->list),
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen MAILDIR_PLUSPLUS_DRIVER_NAME) != 0) {
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen /* Not maildir++ driver. Don't use this trick. */
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen return NULL;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen root_dir = mailbox_list_get_path(storage->list, NULL,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen MAILBOX_LIST_PATH_TYPE_DIR);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return t_strdup_printf("%s/%c"MAILDIR_UNLINK_DIRNAME, root_dir,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen mailbox_list_get_hierarchy_sep(storage->list));
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen}
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenstatic int mkdir_verify(struct mail_storage *storage,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen const char *dir, bool verify)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen{
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainen struct stat st;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (verify) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (lstat(dir, &st) == 0)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return 0;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (errno != ENOENT) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen mail_storage_set_critical(storage,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen "lstat(%s) failed: %m", dir);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return -1;
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen }
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen }
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen if (mkdir_parents(dir, CREATE_MODE) < 0 &&
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen (errno != EEXIST || !verify)) {
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen if (errno != EEXIST && (!verify || errno != ENOENT)) {
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen mail_storage_set_critical(storage,
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen "mkdir(%s) failed: %m", dir);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen }
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return -1;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen }
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return 0;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen}
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen/* create or fix maildir, ignore if it already exists */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstatic int create_maildir(struct mail_storage *storage,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const char *dir, bool verify)
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const char **tmp, *path;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (!verify && mkdir_verify(storage, dir, verify) < 0)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return -1;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen for (tmp = maildirs; *tmp != NULL; tmp++) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen path = t_strconcat(dir, "/", *tmp, NULL);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen if (mkdir_verify(storage, path, verify) < 0) {
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen if (!verify || errno != ENOENT)
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen return -1;
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen /* small optimization. if we're verifying, we don't
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen check that the root dir actually exists unless we
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen fail here. */
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen if (mkdir_verify(storage, dir, verify) < 0)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return -1;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (mkdir_verify(storage, path, verify) < 0)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return -1;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen }
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen }
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen return 0;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen}
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstatic int create_index_dir(struct mail_storage *storage, const char *name)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen const char *index_dir, *root_dir, *dir;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen index_dir = mailbox_list_get_path(storage->list, name,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen MAILBOX_LIST_PATH_TYPE_INDEX);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (*index_dir == '\0')
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return 0;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen root_dir = mailbox_list_get_path(storage->list, name,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (strcmp(index_dir, root_dir) == 0)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen return 0;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen dir = t_strdup_printf("%s/%c%s", index_dir,
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen mailbox_list_get_hierarchy_sep(storage->list),
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen name);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (mkdir_parents(dir, CREATE_MODE) < 0 && errno != EEXIST) {
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen mail_storage_set_critical(storage,
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen "mkdir(%s) failed: %m", dir);
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen return -1;
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return 0;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen}
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainenstatic int create_control_dir(struct mail_storage *storage, const char *name)
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen{
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen const char *control_dir, *root_dir, *dir;
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen control_dir = mailbox_list_get_path(storage->list, name,
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen MAILBOX_LIST_PATH_TYPE_CONTROL);
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen root_dir = mailbox_list_get_path(storage->list, name,
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen if (strcmp(control_dir, root_dir) == 0)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return 0;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen dir = t_strdup_printf("%s/%c%s", control_dir,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen mailbox_list_get_hierarchy_sep(storage->list),
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen name);
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen if (mkdir_parents(dir, CREATE_MODE) < 0 && errno != EEXIST) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen mail_storage_set_critical(storage,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen "mkdir(%s) failed: %m", dir);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return -1;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return 0;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen}
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenstatic int verify_inbox(struct mail_storage *storage)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen{
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen const char *path;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen path = mailbox_list_get_path(storage->list, "INBOX",
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (create_maildir(storage, path, TRUE) < 0)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return -1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (create_index_dir(storage, "INBOX") < 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return -1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (create_control_dir(storage, "INBOX") < 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return -1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic bool maildir_is_recent(struct index_mailbox *ibox, uint32_t uid)
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen{
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)ibox;
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen return maildir_uidlist_is_recent(mbox->uidlist, uid);
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen}
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic struct mailbox *
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenmaildir_open(struct maildir_storage *storage, const char *name,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen enum mailbox_open_flags flags)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct index_storage *istorage = INDEX_STORAGE(storage);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct maildir_mailbox *mbox;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct mail_index *index;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen const char *path, *index_dir, *control_dir;
4a514fb20e04df397842cde11cc9ea92abfe9728Timo Sirainen struct stat st;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen int shared;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen pool_t pool;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen path = mailbox_list_get_path(istorage->storage.list, name,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen index_dir = mailbox_list_get_path(istorage->storage.list, name,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen MAILBOX_LIST_PATH_TYPE_INDEX);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen control_dir = mailbox_list_get_path(istorage->storage.list, name,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen MAILBOX_LIST_PATH_TYPE_CONTROL);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if ((flags & MAILBOX_OPEN_NO_INDEX_FILES) != 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen index_dir = "";
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen index = index_storage_alloc(index_dir, path,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen MAILDIR_INDEX_PREFIX);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* for shared mailboxes get the create mode from the
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen permissions of dovecot-shared file. */
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen shared = stat(t_strconcat(path, "/dovecot-shared", NULL), &st) == 0;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen if (shared)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen mail_index_set_permissions(index, st.st_mode & 0666, st.st_gid);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen pool = pool_alloconly_create("mailbox", 1024);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen mbox = p_new(pool, struct maildir_mailbox, 1);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen mbox->ibox.box = maildir_mailbox;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen mbox->ibox.box.pool = pool;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen mbox->ibox.storage = istorage;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen mbox->ibox.mail_vfuncs = &maildir_mail_vfuncs;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen mbox->ibox.is_recent = maildir_is_recent;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen if (index_storage_mailbox_init(&mbox->ibox, index, name, flags,
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen FALSE) < 0) {
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen /* the memory was already freed */
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen return NULL;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen }
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d3e5a14ea363264dcc7640ca7226249d0c27a793Timo Sirainen mbox->storage = storage;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen mbox->path = p_strdup(pool, path);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen mbox->control_dir = p_strdup(pool, control_dir);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mbox->uidlist = maildir_uidlist_init(mbox);
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen mbox->keywords = maildir_keywords_init(mbox);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen if (!shared)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mbox->mail_create_mode = 0600;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen else {
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen mbox->mail_create_mode = st.st_mode & 0666;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen mbox->private_flags_mask = MAIL_SEEN;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (mbox->ibox.keep_locked) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (maildir_uidlist_lock(mbox->uidlist) <= 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct mailbox *box = &mbox->ibox.box;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mailbox_close(&box);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen return NULL;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen return &mbox->ibox.box;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenstatic struct mailbox *
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenmaildir_mailbox_open(struct mail_storage *_storage, const char *name,
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen struct istream *input, enum mailbox_open_flags flags)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen struct maildir_storage *storage = (struct maildir_storage *)_storage;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen const char *path;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct stat st;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen mail_storage_clear_error(_storage);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (input != NULL) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_storage_set_critical(_storage,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen "Maildir doesn't support streamed mailboxes");
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen return NULL;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen }
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen if (strcmp(name, "INBOX") == 0) {
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen if (verify_inbox(_storage) < 0)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen return NULL;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen return maildir_open(storage, "INBOX", flags);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen }
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (!mailbox_list_is_valid_existing_name(_storage->list, name)) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return NULL;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen path = mailbox_list_get_path(_storage->list, name,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (stat(path, &st) == 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* exists - make sure the required directories are also there */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (create_maildir(_storage, path, TRUE) < 0 ||
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen create_control_dir(_storage, name) < 0)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return NULL;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if ((flags & MAILBOX_OPEN_NO_INDEX_FILES) == 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (create_index_dir(_storage, name) < 0)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return NULL;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return maildir_open(storage, name, flags);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen } else if (errno == ENOENT) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_storage_set_error(_storage,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return NULL;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen } else {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_storage_set_critical(_storage, "stat(%s) failed: %m",
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen path);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return NULL;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic int maildir_create_shared(struct mail_storage *storage,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen const char *dir, mode_t mode, gid_t gid)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen const char *path;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mode_t old_mask;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen int fd;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* add the execute bit if either read or write bit is set */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if ((mode & 0600) != 0) mode |= 0100;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if ((mode & 0060) != 0) mode |= 0010;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if ((mode & 0006) != 0) mode |= 0001;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen old_mask = umask(0777 ^ mode);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (create_maildir(storage, dir, FALSE) < 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (errno == EEXIST) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_storage_set_error(storage,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen "Mailbox already exists");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen umask(old_mask);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen if (chown(dir, (uid_t)-1, gid) < 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen mail_storage_set_critical(storage, "chown(%s) failed: %m", dir);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen path = t_strconcat(dir, "/dovecot-shared", NULL);
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen fd = open(path, O_WRONLY | O_CREAT, mode & 0666);
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen umask(old_mask);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (fd == -1) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_storage_set_critical(storage, "open(%s) failed: %m", path);
494a5de15db3b2806ab31d5ecc3e1c306ae14d06Timo Sirainen return -1;
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen }
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (fchown(fd, (uid_t)-1, gid) < 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen mail_storage_set_critical(storage,
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen "fchown(%s) failed: %m", path);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen }
9d4c027e7de01ab948d6221bc27c9b45d32d1ea5Timo Sirainen (void)close(fd);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int maildir_mailbox_create(struct mail_storage *_storage,
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen const char *name,
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen bool directory __attr_unused__)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct stat st;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *path, *root_dir, *shared_path;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen int fd;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen mail_storage_clear_error(_storage);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen if (!mailbox_list_is_valid_create_name(_storage->list, name)) {
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen return -1;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen path = mailbox_list_get_path(_storage->list, name,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen root_dir = mailbox_list_get_path(_storage->list, NULL,
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen /* if dovecot-shared exists in the root dir, create the mailbox using
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen its permissions and gid, and copy the dovecot-shared inside it. */
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen shared_path = t_strconcat(root_dir, "/dovecot-shared", NULL);
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen if (stat(shared_path, &st) == 0) {
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen return maildir_create_shared(_storage, path,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen st.st_mode & 0666, st.st_gid);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (create_maildir(_storage, path, FALSE) < 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (errno == EEXIST) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_storage_set_error(_storage,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen "Mailbox already exists");
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return -1;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* Maildir++ spec want that maildirfolder named file is created for
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen all subfolders. */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen path = t_strconcat(path, "/" MAILDIR_SUBFOLDER_FILENAME, NULL);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen fd = open(path, O_CREAT | O_WRONLY, CREATE_MODE & 0666);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (fd == -1)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_error("open(%s, O_CREAT) failed: %m", path);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen else
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen (void)close(fd);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return 0;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int maildir_mailbox_delete(struct mail_storage *_storage,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *name)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct stat st;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *src, *dest, *index_dir;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen int count;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mail_storage_clear_error(_storage);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (strcmp(name, "INBOX") == 0) {
d3e5a14ea363264dcc7640ca7226249d0c27a793Timo Sirainen mail_storage_set_error(_storage, "INBOX can't be deleted.");
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen return -1;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen if (!mailbox_list_is_valid_existing_name(_storage->list, name)) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return -1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen /* check if the mailbox actually exists */
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen src = mailbox_list_get_path(_storage->list, name,
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen if (stat(src, &st) != 0 && errno == ENOENT) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_storage_set_error(_storage,
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return -1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* Make sure the indexes are closed before trying to delete the
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen directory that contains them. It can still fail with some NFS
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen implementations if indexes are opened by another session, but
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen that can't really be helped. */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen index_storage_destroy_unrefed();
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* if there's a separate index directory, delete it before the actual
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen maildir. this way we never see partially deleted mailboxes. */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen index_dir = mailbox_list_get_path(_storage->list, name,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen MAILBOX_LIST_PATH_TYPE_INDEX);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (strcmp(index_dir, src) != 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen i_assert(*name != '/' && *name != '~');
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (unlink_directory(index_dir, TRUE) < 0 &&
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen errno != ENOTEMPTY) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_storage_set_critical(_storage,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen "unlink_directory(%s) failed: %m", index_dir);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return -1;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen }
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen }
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen dest = maildir_get_unlink_dest(_storage, name);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen if (dest == NULL) {
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen /* absolute maildir path, delete the directory directly
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen without any renaming */
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen dest = src;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen } else {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* rename the .maildir into ..DOVECOT-TRASH which atomically
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen marks it as being deleted. If we die before deleting the
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ..DOVECOT-TRASH directory, it gets deleted the next time
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mailbox listing sees it. */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen count = 0;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen while (rename(src, dest) < 0 && count < 2) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* EBUSY is given by some NFS implementations */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (errno != EEXIST && errno != ENOTEMPTY &&
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen errno != EBUSY) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_storage_set_critical(_storage,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen "rename(%s, %s) failed: %m", src, dest);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return -1;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* already existed, delete it and try again */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (unlink_directory(dest, TRUE) < 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_storage_set_critical(_storage,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen "unlink_directory(%s) failed: %m",
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen dest);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return -1;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen count++;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (unlink_directory(dest, TRUE) < 0 && errno != ENOTEMPTY) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_storage_set_critical(_storage,
1f4399a277b861419b82758ab0462e90c00a4c41Timo Sirainen "unlink_directory(%s) failed: %m", dest);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* it's already renamed to ..dir, which means it's deleted
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen as far as the client is concerned. Report success. */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int rename_indexes(struct mail_storage *storage,
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen const char *oldname, const char *newname)
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *oldpath, *newpath;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen oldpath = mailbox_list_get_path(storage->list, oldname,
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen MAILBOX_LIST_PATH_TYPE_INDEX);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen newpath = mailbox_list_get_path(storage->list, newname,
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen MAILBOX_LIST_PATH_TYPE_INDEX);
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen if (strcmp(oldpath, newpath) == 0)
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen return 0;
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (rename(oldpath, newpath) < 0 && errno != ENOENT) {
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen mail_storage_set_critical(storage, "rename(%s, %s) failed: %m",
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen oldpath, newpath);
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen return -1;
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen }
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen return 0;
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen}
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainenstatic int rename_subfolders(struct mail_storage *storage,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *oldname, const char *newname)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct mailbox_list_iterate_context *iter;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct mailbox_info *info;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ARRAY_DEFINE(names_arr, const char *);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *mask, *oldpath, *newpath, *old_listname, *new_listname;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *const *names;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen unsigned int i, count;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen size_t oldnamelen;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen pool_t pool;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen int ret;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ret = 0;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen oldnamelen = strlen(oldname);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* first get a list of the subfolders and save them to memory, because
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen we can't rely on readdir() not skipping files while the directory
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen is being modified. this doesn't protect against modifications by
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen other processes though. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen pool = pool_alloconly_create("Maildir subfolders list", 1024);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_array_init(&names_arr, 64);
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen mask = t_strdup_printf("%s%c*", oldname,
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen mailbox_list_get_hierarchy_sep(storage->list));
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen iter = mailbox_list_iter_init(storage->list, mask,
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen MAILBOX_LIST_ITER_FAST_FLAGS);
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen while ((info = mailbox_list_iter_next(iter)) != NULL) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *name;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_assert(oldnamelen <= strlen(info->name));
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen name = p_strdup(pool, info->name + oldnamelen);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen array_append(&names_arr, &name, 1);
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (mailbox_list_iter_deinit(&iter) < 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ret = -1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen names = NULL; count = 0;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen } else {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen names = array_get(&names_arr, &count);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen for (i = 0; i < count; i++) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen t_push();
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen old_listname = t_strconcat(oldname, names[i], NULL);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen new_listname = t_strconcat(newname, names[i], NULL);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen oldpath = mailbox_list_get_path(storage->list, old_listname,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen newpath = mailbox_list_get_path(storage->list, new_listname,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen /* FIXME: it's possible to merge two folders if either one of
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen them doesn't have existing root folder. We could check this
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen but I'm not sure if it's worth it. It could be even
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen considered as a feature.
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
8ca217bf3aa23c7922d0d4aa44fcd2320416d61cMartti Rannanjärvi Anyway, the bug with merging is that if both folders have
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen identically named subfolder they conflict. Just ignore those
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen and leave them under the old folder. */
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen if (rename(oldpath, newpath) == 0 ||
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen errno == EEXIST || errno == ENOTEMPTY)
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen ret = 1;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen else {
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen mail_storage_set_critical(storage,
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen "rename(%s, %s) failed: %m", oldpath, newpath);
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen ret = -1;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen t_pop();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen break;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen (void)rename_indexes(storage, old_listname, new_listname);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen t_pop();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_free(&names_arr);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool_unref(pool);
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen return ret;
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen}
e36574dadcac802d6780fa94ee45951e75594c96Timo Sirainen
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainenstatic int maildir_mailbox_rename(struct mail_storage *_storage,
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen const char *oldname, const char *newname)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen{
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen const char *oldpath, *newpath;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen int ret;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen bool found;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen mail_storage_clear_error(_storage);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen if (!mailbox_list_is_valid_existing_name(_storage->list, oldname) ||
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen !mailbox_list_is_valid_create_name(_storage->list, newname)) {
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen return -1;
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen }
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen if (strcmp(oldname, "INBOX") == 0) {
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen mail_storage_set_error(_storage,
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen "Renaming INBOX isn't supported.");
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen return -1;
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen }
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen /* NOTE: it's possible to rename a nonexisting folder which has
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen subfolders. In that case we should ignore the rename() error. */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen oldpath = mailbox_list_get_path(_storage->list, oldname,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen newpath = mailbox_list_get_path(_storage->list, newname,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen ret = rename(oldpath, newpath);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (ret == 0 || errno == ENOENT) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen (void)rename_indexes(_storage, oldname, newname);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen found = ret == 0;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen ret = rename_subfolders(_storage, oldname, newname);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (ret < 0)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen return -1;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (!found && ret == 0) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen mail_storage_set_error(_storage,
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, oldname);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen return -1;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen }
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
4b1781e4c64be52e25b5994e5242dbe696cc7d29Timo Sirainen return 0;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen }
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (errno == EEXIST) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen mail_storage_set_error(_storage,
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen "Target mailbox already exists");
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen return -1;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen } else {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen mail_storage_set_critical(_storage, "rename(%s, %s) failed: %m",
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen oldpath, newpath);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen return -1;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen }
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic int maildir_storage_close(struct mailbox *box)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen int ret = 0;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /*FIXME:if (!maildir_try_flush_dirty_flags(ibox->index, TRUE)) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen mail_storage_set_index_error(ibox);
15bfe73fb3988bb80e6afe6a60b9a715c7207600Timo Sirainen ret = -1;
4809537f0c5a2e1cee9559ec842cc869884d2cb7Timo Sirainen }*/
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (mbox->ibox.keep_locked)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen maildir_uidlist_unlock(mbox->uidlist);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen maildir_keywords_deinit(mbox->keywords);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen maildir_uidlist_deinit(mbox->uidlist);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen index_storage_mailbox_free(box);
8709b2fe6ec2b5ca1d90a63490f8371472062efdTimo Sirainen return ret;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainenstatic void
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenmaildir_notify_changes(struct mailbox *box, unsigned int min_interval,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mailbox_notify_callback_t *callback, void *context)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen mbox->ibox.min_notify_interval = min_interval;
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen mbox->ibox.notify_callback = callback;
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen mbox->ibox.notify_context = context;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (callback == NULL) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen index_mailbox_check_remove_all(&mbox->ibox);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen return;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen }
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen index_mailbox_check_add(&mbox->ibox,
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen t_strconcat(mbox->path, "/new", NULL));
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen index_mailbox_check_add(&mbox->ibox,
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen t_strconcat(mbox->path, "/cur", NULL));
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen}
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainenstatic int
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenmaildir_storage_is_mailbox(struct mail_storage *_storage,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen const char *dir, const char *fname,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen enum mailbox_list_iter_flags iter_flags
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen __attr_unused__,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen enum mailbox_info_flags *flags,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen enum mailbox_list_file_type type)
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen{
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct maildir_storage *storage = (struct maildir_storage *)_storage;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen int ret;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (fname[1] == mailbox_list_get_hierarchy_sep(_storage->list) &&
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen strcmp(fname+2, MAILDIR_UNLINK_DIRNAME) == 0 &&
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen strcmp(mailbox_list_get_driver_name(_storage->list),
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen MAILDIR_PLUSPLUS_DRIVER_NAME) == 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char *path;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen struct stat st;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
758d8b46f9e8fd87cf58bb4912cddf6bf28918cfTimo Sirainen /* this directory is in the middle of being deleted,
758d8b46f9e8fd87cf58bb4912cddf6bf28918cfTimo Sirainen or the process trying to delete it had died.
b7c7a04bc5edb8eebea3837ff624441d9fa3721cTimo Sirainen delete it ourself if it's been there longer than
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen one hour. */
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen t_push();
c905571984fe8ccdb6f2a266b813f19b0643a66cTimo Sirainen path = t_strdup_printf("%s/%s", dir, fname);
c905571984fe8ccdb6f2a266b813f19b0643a66cTimo Sirainen if (stat(path, &st) == 0 &&
c905571984fe8ccdb6f2a266b813f19b0643a66cTimo Sirainen st.st_mtime < ioloop_time - 3600)
c905571984fe8ccdb6f2a266b813f19b0643a66cTimo Sirainen (void)unlink_directory(path, TRUE);
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen t_pop();
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *flags = MAILBOX_NONEXISTENT;
e200d1ba38eeebfb0b9e60150d93753ec6d823c8Timo Sirainen return 0;
e200d1ba38eeebfb0b9e60150d93753ec6d823c8Timo Sirainen }
e200d1ba38eeebfb0b9e60150d93753ec6d823c8Timo Sirainen
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen switch (type) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen case MAILBOX_LIST_FILE_TYPE_DIR:
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen /* all directories are valid maildirs */
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen return 1;
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen case MAILBOX_LIST_FILE_TYPE_FILE:
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen case MAILBOX_LIST_FILE_TYPE_OTHER:
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen /* non-directories are not */
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen *flags = MAILBOX_NOSELECT;
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen return 0;
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen case MAILBOX_LIST_FILE_TYPE_UNKNOWN:
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen case MAILBOX_LIST_FILE_TYPE_SYMLINK:
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* need to check with stat() to be sure */
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen break;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen }
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen /* Check files beginning with .nfs always because they may be
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen temporary files created by the kernel */
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen if (storage->stat_dirs || strncmp(fname, ".nfs", 4) == 0) {
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen const char *path;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen struct stat st;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen t_push();
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen path = t_strdup_printf("%s/%s", dir, fname);
e91543761d0b7b97a1dc28e036e44d76405545c2Timo Sirainen ret = (stat(path, &st) < 0 || !S_ISDIR(st.st_mode)) ? 0 : 1;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen t_pop();
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (ret == 0)
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen *flags = MAILBOX_NONEXISTENT;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen } else {
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen ret = 1;
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen }
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return ret;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen}
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainenstatic void maildir_class_init(void)
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen{
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen maildir_transaction_class_init();
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen}
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainenstatic void maildir_class_deinit(void)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen{
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen maildir_transaction_class_deinit();
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen}
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainenstruct mail_storage maildir_storage = {
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen MEMBER(name) MAILDIR_STORAGE_NAME,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen MEMBER(mailbox_is_file) FALSE,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen {
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen maildir_class_init,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen maildir_class_deinit,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen maildir_create,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen maildir_free,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen maildir_autodetect,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen index_storage_set_callbacks,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen maildir_mailbox_open,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen maildir_mailbox_create,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen maildir_mailbox_delete,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen maildir_mailbox_rename,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen maildir_storage_is_mailbox,
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen index_storage_get_last_error
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen }
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen};
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainenstruct mailbox maildir_mailbox = {
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen MEMBER(name) NULL,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen MEMBER(storage) NULL,
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen {
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen index_storage_is_readonly,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk index_storage_allow_new_keywords,
dbc86748934bc34826d9cc8c43d24df09b3ba402Timo Sirainen maildir_storage_close,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen index_storage_get_status,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen maildir_storage_sync_init,
dbc86748934bc34826d9cc8c43d24df09b3ba402Timo Sirainen index_mailbox_sync_next,
dbc86748934bc34826d9cc8c43d24df09b3ba402Timo Sirainen index_mailbox_sync_deinit,
c78e7a94528078728cc639b26a1c83e11b4d7e1bTimo Sirainen maildir_notify_changes,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen index_transaction_begin,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen index_transaction_commit,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen index_transaction_rollback,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen index_keywords_create,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen index_keywords_free,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen index_storage_get_uids,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen index_mail_alloc,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen index_header_lookup_init,
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen index_header_lookup_deinit,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen index_storage_search_init,
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen index_storage_search_deinit,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen index_storage_search_next,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen index_storage_search_next_update_seq,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen maildir_save_init,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen maildir_save_continue,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen maildir_save_finish,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen maildir_save_cancel,
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen maildir_copy,
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen index_storage_is_inconsistent
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen};
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen