index_mailbox_check_add(&mbox->box, mbox->box.path);
}
-static int cydir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx
- ATTR_UNUSED,
- const char *dir, const char *fname,
- const char *mailbox_name ATTR_UNUSED,
- enum mailbox_list_file_type type,
- enum mailbox_info_flags *flags)
-{
- const char *mail_path;
- struct stat st;
- int ret = 1;
-
- /* try to avoid stat() with these checks */
- if (type != MAILBOX_LIST_FILE_TYPE_DIR &&
- type != MAILBOX_LIST_FILE_TYPE_SYMLINK &&
- type != MAILBOX_LIST_FILE_TYPE_UNKNOWN) {
- /* it's a file */
- *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
- return 0;
- }
-
- /* need to stat() then */
- mail_path = t_strconcat(dir, "/", fname, NULL);
- if (stat(mail_path, &st) == 0) {
- if (!S_ISDIR(st.st_mode)) {
- /* non-directory */
- *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
- ret = 0;
- } else if (st.st_nlink == 2) {
- /* no subdirectories */
- *flags |= MAILBOX_NOCHILDREN;
- } else if (*ctx->list->set.maildir_name != '\0') {
- /* non-default configuration: we have one directory
- containing the mailboxes. if there are 3 links,
- either this is a selectable mailbox without children
- or non-selectable mailbox with children */
- if (st.st_nlink > 3)
- *flags |= MAILBOX_CHILDREN;
- } else {
- /* default configuration: all subdirectories are
- child mailboxes. */
- if (st.st_nlink > 2)
- *flags |= MAILBOX_CHILDREN;
- }
- } else if (errno == ENOENT) {
- /* doesn't exist - probably a non-existing subscribed mailbox */
- *flags |= MAILBOX_NONEXISTENT;
- } else {
- /* non-selectable. probably either access denied, or symlink
- destination not found. don't bother logging errors. */
- *flags |= MAILBOX_NOSELECT;
- }
- return ret;
-}
-
-static void cydir_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
- struct mailbox_list *list)
-{
- list->v.iter_is_mailbox = cydir_list_iter_is_mailbox;
-}
-
struct mail_storage cydir_storage = {
.name = CYDIR_STORAGE_NAME,
.class_flags = 0,
cydir_storage_alloc,
NULL,
NULL,
- cydir_storage_add_list,
+ NULL,
cydir_storage_get_list_settings,
NULL,
cydir_mailbox_alloc,
return -1;
return 0;
}
-
-int dbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx ATTR_UNUSED,
- const char *dir, const char *fname,
- const char *mailbox_name ATTR_UNUSED,
- enum mailbox_list_file_type type,
- enum mailbox_info_flags *flags)
-{
- const char *path, *maildir_path;
- struct stat st, st2;
- int ret = 1;
-
- /* try to avoid stat() with these checks */
- if (type != MAILBOX_LIST_FILE_TYPE_DIR &&
- type != MAILBOX_LIST_FILE_TYPE_SYMLINK &&
- type != MAILBOX_LIST_FILE_TYPE_UNKNOWN) {
- /* it's a file */
- *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
- return 0;
- }
-
- /* need to stat() then */
- path = t_strconcat(dir, "/", fname, NULL);
- if (stat(path, &st) == 0) {
- if (!S_ISDIR(st.st_mode)) {
- /* non-directory */
- *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
- ret = 0;
- } else if (st.st_nlink == 2) {
- /* no subdirectories */
- *flags |= MAILBOX_NOCHILDREN;
- } else if (*ctx->list->set.maildir_name != '\0') {
- /* default configuration: we have one directory
- containing the mailboxes. if there are 3 links,
- either this is a selectable mailbox without children
- or non-selectable mailbox with children */
- if (st.st_nlink > 3)
- *flags |= MAILBOX_CHILDREN;
- } else {
- /* non-default configuration: all subdirectories are
- child mailboxes. */
- if (st.st_nlink > 2)
- *flags |= MAILBOX_CHILDREN;
- }
- } else if (errno == ENOENT) {
- /* doesn't exist - probably a non-existing subscribed mailbox */
- *flags |= MAILBOX_NONEXISTENT;
- } else {
- /* non-selectable. probably either access denied, or symlink
- destination not found. don't bother logging errors. */
- *flags |= MAILBOX_NOSELECT;
- }
- if ((*flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) == 0) {
- /* make sure it's a selectable mailbox */
- maildir_path = t_strconcat(path, "/",
- ctx->list->set.maildir_name, NULL);
- if (stat(maildir_path, &st2) < 0 || !S_ISDIR(st2.st_mode))
- *flags |= MAILBOX_NOSELECT;
- if (st.st_nlink == 3 && *ctx->list->set.maildir_name != '\0') {
- /* now we know what link count 3 means. */
- if ((*flags & MAILBOX_NOSELECT) != 0)
- *flags |= MAILBOX_CHILDREN;
- else
- *flags |= MAILBOX_NOCHILDREN;
- }
- }
- return ret;
-}
int dbox_mailbox_open(struct mailbox *box);
int dbox_mailbox_create(struct mailbox *box,
const struct mailbox_update *update, bool directory);
-int dbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
- const char *dir, const char *fname,
- const char *mailbox_name,
- enum mailbox_list_file_type type,
- enum mailbox_info_flags *flags);
#endif
#include "mdbox-storage-rebuild.h"
#include "mdbox-storage.h"
-#define MDBOX_LIST_CONTEXT(obj) \
- MODULE_CONTEXT(obj, mdbox_mailbox_list_module)
-
-struct mdbox_mailbox_list {
- union mailbox_list_module_context module_ctx;
-};
-
extern struct mail_storage mdbox_storage;
extern struct mailbox mdbox_mailbox;
extern struct dbox_storage_vfuncs mdbox_dbox_storage_vfuncs;
-static MODULE_CONTEXT_DEFINE_INIT(mdbox_mailbox_list_module,
- &mailbox_list_module_register);
-
static struct mail_storage *mdbox_storage_alloc(void)
{
struct mdbox_storage *storage;
return index_storage_mailbox_delete(box);
}
-static void dbox_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
- struct mailbox_list *list)
-{
- struct mdbox_mailbox_list *mlist;
-
- mlist = p_new(list->pool, struct mdbox_mailbox_list, 1);
- mlist->module_ctx.super = list->v;
- list->v.iter_is_mailbox = dbox_list_iter_is_mailbox;
-
- MODULE_CONTEXT_SET(list, mdbox_mailbox_list_module, mlist);
-}
-
struct mail_storage mdbox_storage = {
.name = MDBOX_STORAGE_NAME,
.class_flags = MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT,
mdbox_storage_alloc,
mdbox_storage_create,
mdbox_storage_destroy,
- dbox_storage_add_list,
+ NULL,
dbox_storage_get_list_settings,
NULL,
mdbox_mailbox_alloc,
#include "sdbox-sync.h"
#include "sdbox-storage.h"
-#define SDBOX_LIST_CONTEXT(obj) \
- MODULE_CONTEXT(obj, sdbox_mailbox_list_module)
-
-struct sdbox_mailbox_list {
- union mailbox_list_module_context module_ctx;
-};
-
extern struct mail_storage dbox_storage;
extern struct mailbox sdbox_mailbox;
extern struct dbox_storage_vfuncs sdbox_dbox_storage_vfuncs;
-static MODULE_CONTEXT_DEFINE_INIT(sdbox_mailbox_list_module,
- &mailbox_list_module_register);
-
static struct mail_storage *sdbox_storage_alloc(void)
{
struct sdbox_storage *storage;
return sdbox_write_index_header(box, update);
}
-static void sdbox_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
- struct mailbox_list *list)
-{
- struct sdbox_mailbox_list *mlist;
-
- mlist = p_new(list->pool, struct sdbox_mailbox_list, 1);
- mlist->module_ctx.super = list->v;
- list->v.iter_is_mailbox = dbox_list_iter_is_mailbox;
-
- MODULE_CONTEXT_SET(list, sdbox_mailbox_list_module, mlist);
-}
-
struct mail_storage dbox_storage = {
.name = SDBOX_STORAGE_NAME,
.class_flags = 0,
sdbox_storage_alloc,
NULL,
NULL,
- sdbox_storage_add_list,
+ NULL,
dbox_storage_get_list_settings,
NULL,
sdbox_mailbox_alloc,
{ type, #name, offsetof(struct maildir_settings, name), NULL }
static const struct setting_define maildir_setting_defines[] = {
- DEF(SET_BOOL, maildir_stat_dirs),
DEF(SET_BOOL, maildir_copy_with_hardlinks),
DEF(SET_BOOL, maildir_copy_preserve_filename),
DEF(SET_BOOL, maildir_very_dirty_syncs),
};
static const struct maildir_settings maildir_default_settings = {
- .maildir_stat_dirs = FALSE,
.maildir_copy_with_hardlinks = TRUE,
.maildir_copy_preserve_filename = FALSE,
.maildir_very_dirty_syncs = FALSE
#define MAILDIR_SETTINGS_H
struct maildir_settings {
- bool maildir_stat_dirs;
bool maildir_copy_with_hardlinks;
bool maildir_copy_preserve_filename;
bool maildir_very_dirty_syncs;
#include "ioloop.h"
#include "mkdir-parents.h"
#include "eacces-error.h"
-#include "unlink-directory.h"
#include "unlink-old-files.h"
#include "mailbox-uidvalidity.h"
-#include "list/mailbox-list-maildir.h"
#include "maildir-storage.h"
#include "maildir-uidlist.h"
#include "maildir-keywords.h"
&mailbox_list_module_register);
static const char *maildir_subdirs[] = { "cur", "new", "tmp" };
-static bool maildir_is_internal_name(const char *name)
-{
- return strcmp(name, "cur") == 0 ||
- strcmp(name, "new") == 0 ||
- strcmp(name, "tmp") == 0;
-}
-
-static bool maildir_storage_is_valid_existing_name(struct mailbox_list *list,
- const char *name)
-{
- struct maildir_mailbox_list_context *mlist = MAILDIR_LIST_CONTEXT(list);
- const char *p;
-
- if (!mlist->module_ctx.super.is_valid_existing_name(list, name))
- return FALSE;
-
- /* Don't allow the mailbox name to end in cur/new/tmp */
- p = strrchr(name, '/');
- if (p != NULL)
- name = p + 1;
- return !maildir_is_internal_name(name);
-}
-
-static bool maildir_storage_is_valid_create_name(struct mailbox_list *list,
- const char *name)
-{
- struct maildir_mailbox_list_context *mlist = MAILDIR_LIST_CONTEXT(list);
- bool ret = TRUE;
-
- if (!mlist->module_ctx.super.is_valid_create_name(list, name))
- return FALSE;
-
- /* Don't allow creating mailboxes under cur/new/tmp */
- T_BEGIN {
- const char *const *tmp;
-
- for (tmp = t_strsplit(name, "/"); *tmp != NULL; tmp++) {
- if (maildir_is_internal_name(*tmp)) {
- ret = FALSE;
- break;
- }
- }
- } T_END;
- return ret;
-}
-
static struct mail_storage *maildir_storage_alloc(void)
{
struct maildir_storage *storage;
if (set->subscription_fname == NULL)
set->subscription_fname = MAILDIR_SUBSCRIPTION_FILE_NAME;
- if (set->inbox_path == NULL &&
+ if (set->inbox_path == NULL && set->maildir_name == NULL &&
(strcmp(set->layout, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0 ||
strcmp(set->layout, MAILBOX_LIST_NAME_FS) == 0) &&
(ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
}
static bool
-maildir_is_mailbox_dir(struct mailbox_list *list ATTR_UNUSED,
- const char *dir ATTR_UNUSED, const char *name)
+maildir_is_internal_name(struct mailbox_list *list ATTR_UNUSED,
+ const char *name)
{
- return maildir_is_internal_name(name);
+ return strcmp(name, "cur") == 0 ||
+ strcmp(name, "new") == 0 ||
+ strcmp(name, "tmp") == 0;
}
static int
-maildir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx
- ATTR_UNUSED,
- const char *dir, const char *fname,
- const char *mailbox_name ATTR_UNUSED,
- enum mailbox_list_file_type type,
- enum mailbox_info_flags *flags)
+maildir_list_get_mailbox_flags(struct mailbox_list *list,
+ const char *dir, const char *fname,
+ enum mailbox_list_file_type type,
+ struct stat *st_r,
+ enum mailbox_info_flags *flags)
{
- struct stat st, st2;
- const char *path, *cur_path;
+ struct maildir_mailbox_list_context *mlist = MAILDIR_LIST_CONTEXT(list);
+ struct stat st2;
+ const char *cur_path;
int ret;
- if (maildir_is_internal_name(fname)) {
- *flags |= MAILBOX_NONEXISTENT;
- return 0;
- }
-
- switch (type) {
- case MAILBOX_LIST_FILE_TYPE_FILE:
- case MAILBOX_LIST_FILE_TYPE_OTHER:
- /* non-directories are not */
+ ret = mlist->module_ctx.super.
+ get_mailbox_flags(list, dir, fname, type, st_r, flags);
+ if (ret <= 0 || MAILBOX_INFO_FLAGS_FINISHED(*flags))
+ return ret;
+
+ /* see if it's a selectable mailbox. after that we can figure out based
+ on the link count if we have child mailboxes or not. for a
+ selectable mailbox we have 3 more links (cur/, new/ and tmp/)
+ than non-selectable. */
+ cur_path = t_strconcat(dir, "/", fname, "/cur", NULL);
+ if (stat(cur_path, &st2) < 0 || !S_ISDIR(st2.st_mode)) {
*flags |= MAILBOX_NOSELECT;
- return 0;
-
- case MAILBOX_LIST_FILE_TYPE_DIR:
- case MAILBOX_LIST_FILE_TYPE_UNKNOWN:
- case MAILBOX_LIST_FILE_TYPE_SYMLINK:
- break;
- }
-
- path = t_strdup_printf("%s/%s", dir, fname);
- if (stat(path, &st) == 0) {
- if (!S_ISDIR(st.st_mode)) {
- if (strncmp(fname, ".nfs", 4) == 0) {
- /* temporary NFS file */
- *flags |= MAILBOX_NONEXISTENT;
- } else {
- *flags |= MAILBOX_NOSELECT |
- MAILBOX_NOINFERIORS;
- }
- return 0;
- }
- ret = 1;
- } else if (errno == ENOENT) {
- /* doesn't exist - probably a non-existing subscribed mailbox */
- *flags |= MAILBOX_NONEXISTENT;
- ret = 0;
+ if (st_r->st_nlink > 2)
+ *flags |= MAILBOX_CHILDREN;
+ else
+ *flags |= MAILBOX_NOCHILDREN;
} else {
- /* non-selectable. probably either access denied, or symlink
- destination not found. don't bother logging errors. */
- *flags |= MAILBOX_NOSELECT;
- ret = 1;
+ if (st_r->st_nlink > 5)
+ *flags |= MAILBOX_CHILDREN;
+ else
+ *flags |= MAILBOX_NOCHILDREN;
}
- if ((*flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) == 0) {
- /* make sure it's a selectable mailbox */
- cur_path = t_strconcat(path, "/cur", NULL);
- if (stat(cur_path, &st2) < 0 || !S_ISDIR(st2.st_mode))
- *flags |= MAILBOX_NOSELECT;
-
- if (*ctx->list->set.maildir_name == '\0') {
- /* now we can figure out based on the link count if we
- have child mailboxes or not. for a selectable
- mailbox we have 3 more links (cur/, new/ and tmp/)
- than non-selectable. */
- if ((*flags & MAILBOX_NOSELECT) == 0) {
- if (st.st_nlink > 5)
- *flags |= MAILBOX_CHILDREN;
- else
- *flags |= MAILBOX_NOCHILDREN;
- } else {
- if (st.st_nlink > 2)
- *flags |= MAILBOX_CHILDREN;
- else
- *flags |= MAILBOX_NOCHILDREN;
- }
- } else {
- /* link count 3 may mean either a selectable mailbox
- or a non-selectable mailbox with 1 child. */
- if (st.st_nlink > 3)
- *flags |= MAILBOX_CHILDREN;
- else if (st.st_nlink == 3) {
- if ((*flags & MAILBOX_NOSELECT) != 0)
- *flags |= MAILBOX_CHILDREN;
- else
- *flags |= MAILBOX_NOCHILDREN;
- }
- }
- }
- return ret;
+ return 1;
}
-static int
-maildirplusplus_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
- const char *dir, const char *fname,
- const char *mailbox_name ATTR_UNUSED,
- enum mailbox_list_file_type type,
- enum mailbox_info_flags *flags)
+static void maildir_storage_add_list(struct mail_storage *storage,
+ struct mailbox_list *list)
{
- struct maildir_mailbox_list_context *mlist =
- MAILDIR_LIST_CONTEXT(ctx->list);
- int ret;
-
- if (fname[1] == mailbox_list_get_hierarchy_sep(ctx->list) &&
- strcmp(fname+2, MAILBOX_LIST_MAILDIR_TRASH_DIR_NAME) == 0) {
- const char *path;
- struct stat st;
-
- /* this directory is in the middle of being deleted,
- or the process trying to delete it had died.
- delete it ourself if it's been there longer than
- one hour. */
- path = t_strdup_printf("%s/%s", dir, fname);
- if (stat(path, &st) == 0 &&
- st.st_mtime < ioloop_time - 3600)
- (void)unlink_directory(path, TRUE);
-
- *flags |= MAILBOX_NONEXISTENT;
- return 0;
- }
-
- switch (type) {
- case MAILBOX_LIST_FILE_TYPE_DIR:
- /* all directories are valid maildirs */
- return 1;
-
- case MAILBOX_LIST_FILE_TYPE_FILE:
- case MAILBOX_LIST_FILE_TYPE_OTHER:
- /* non-directories are not */
- *flags |= MAILBOX_NOSELECT;
- return 0;
+ struct maildir_mailbox_list_context *mlist;
- case MAILBOX_LIST_FILE_TYPE_UNKNOWN:
- case MAILBOX_LIST_FILE_TYPE_SYMLINK:
- /* need to check with stat() to be sure */
- break;
- }
+ mlist = p_new(list->pool, struct maildir_mailbox_list_context, 1);
+ mlist->module_ctx.super = list->v;
+ mlist->set = mail_storage_get_driver_settings(storage);
- /* Check files beginning with .nfs always because they may be
- temporary files created by the kernel */
- if (mlist->set->maildir_stat_dirs || *fname == '\0' ||
- strncmp(fname, ".nfs", 4) == 0) {
- const char *path;
- struct stat st;
-
- /* if fname="", we're checking if a base maildir has INBOX */
- path = *fname == '\0' ? t_strdup_printf("%s/cur", dir) :
- t_strdup_printf("%s/%s", dir, fname);
- if (stat(path, &st) == 0) {
- if (S_ISDIR(st.st_mode))
- ret = 1;
- else {
- if (strncmp(fname, ".nfs", 4) == 0)
- *flags |= MAILBOX_NONEXISTENT;
- else
- *flags |= MAILBOX_NOSELECT;
- ret = 0;
- }
- } else if (errno == ENOENT) {
- /* just deleted? */
- *flags |= MAILBOX_NONEXISTENT;
- ret = 0;
- } else {
- *flags |= MAILBOX_NOSELECT;
- ret = 0;
- }
- } else {
- ret = 1;
- }
- return ret;
+ list->v.is_internal_name = maildir_is_internal_name;
+ list->v.get_mailbox_flags = maildir_list_get_mailbox_flags;
+ MODULE_CONTEXT_SET(list, maildir_mailbox_list_module, mlist);
}
uint32_t maildir_get_uidvalidity_next(struct mailbox_list *list)
return mailbox_uidvalidity_next(list, path);
}
-static void maildir_storage_add_list(struct mail_storage *storage,
- struct mailbox_list *list)
-{
- struct maildir_mailbox_list_context *mlist;
-
- mlist = p_new(list->pool, struct maildir_mailbox_list_context, 1);
- mlist->module_ctx.super = list->v;
- mlist->set = mail_storage_get_driver_settings(storage);
-
- list->v.is_mailbox_dir = maildir_is_mailbox_dir;
- if (strcmp(list->name, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0) {
- list->v.iter_is_mailbox = maildirplusplus_iter_is_mailbox;
- } else {
- list->v.is_valid_existing_name =
- maildir_storage_is_valid_existing_name;
- list->v.is_valid_create_name =
- maildir_storage_is_valid_create_name;
- list->v.iter_is_mailbox = maildir_list_iter_is_mailbox;
- }
- MODULE_CONTEXT_SET(list, maildir_mailbox_list_module, mlist);
-}
-
struct mail_storage maildir_storage = {
.name = MAILDIR_STORAGE_NAME,
.class_flags = 0,
}
static bool
-is_inbox_file(struct mailbox_list *list, const char *path, const char *fname)
+mbox_is_internal_name(struct mailbox_list *list ATTR_UNUSED,
+ const char *name)
{
- const char *inbox_path;
+ unsigned int len;
- 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 bool mbox_name_is_dotlock(const char *name)
-{
- unsigned int len = strlen(name);
-
- return len >= 5 && strcmp(name + len - 5, ".lock") == 0;
-}
-
-static bool
-mbox_is_valid_existing_name(struct mailbox_list *list, const char *name)
-{
- struct mbox_mailbox_list *mlist = MBOX_LIST_CONTEXT(list);
-
- return mlist->module_ctx.super.is_valid_existing_name(list, name) &&
- !mbox_name_is_dotlock(name);
-}
-
-static bool
-mbox_is_valid_create_name(struct mailbox_list *list, const char *name)
-{
- struct mbox_mailbox_list *mlist = MBOX_LIST_CONTEXT(list);
-
- return mlist->module_ctx.super.is_valid_create_name(list, name) &&
- !mbox_name_is_dotlock(name);
-}
-
-static int mbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
- const char *dir, const char *fname,
- const char *mailbox_name ATTR_UNUSED,
- enum mailbox_list_file_type type,
- enum mailbox_info_flags *flags)
-{
- const char *path, *root_dir;
- size_t len;
- struct stat st;
-
- if (strcmp(fname, MBOX_INDEX_DIR_NAME) == 0) {
- *flags |= MAILBOX_NOSELECT;
- return 0;
- }
- if (strcmp(fname, ctx->list->set.subscription_fname) == 0) {
- root_dir = mailbox_list_get_path(ctx->list, NULL,
- MAILBOX_LIST_PATH_TYPE_DIR);
- if (strcmp(root_dir, dir) == 0) {
- *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
- return 0;
- }
- }
-
- /* skip all .lock files */
- len = strlen(fname);
- if (len > 5 && strcmp(fname+len-5, ".lock") == 0) {
- *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
- return 0;
- }
-
- /* try to avoid stat() with these checks */
- if (type == MAILBOX_LIST_FILE_TYPE_DIR) {
- *flags |= 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 |= MAILBOX_NOINFERIORS;
- return 1;
- }
+ /* don't allow *.lock files/dirs */
+ len = strlen(name);
+ if (len > 5 && strcmp(name+len-5, ".lock") == 0)
+ return TRUE;
- /* need to stat() then */
- path = t_strconcat(dir, "/", fname, NULL);
- if (stat(path, &st) == 0) {
- if (S_ISDIR(st.st_mode))
- *flags |= MAILBOX_NOSELECT | MAILBOX_CHILDREN;
- else {
- *flags |= 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 &= ~MAILBOX_NOINFERIORS;
- }
- }
- return 1;
- } else if (errno == ENOENT) {
- /* doesn't exist - probably a non-existing subscribed mailbox */
- *flags |= MAILBOX_NONEXISTENT;
- return 1;
- } else {
- /* non-selectable. probably either access denied, or symlink
- destination not found. don't bother logging errors. */
- *flags |= MAILBOX_NOSELECT;
- return 0;
- }
+ return strcmp(name, MBOX_INDEX_DIR_NAME) == 0;
}
static void mbox_storage_add_list(struct mail_storage *storage,
/* have to use .imap/ directories */
list->v.get_path = mbox_list_get_path;
}
- list->v.iter_is_mailbox = mbox_list_iter_is_mailbox;
- list->v.is_valid_existing_name = mbox_is_valid_existing_name;
- list->v.is_valid_create_name = mbox_is_valid_create_name;
+ list->v.is_internal_name = mbox_is_internal_name;
MODULE_CONTEXT_SET(list, mbox_mailbox_list_module, mlist);
}
{
}
-static int raw_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
- const char *dir, const char *fname,
- const char *mailbox_name ATTR_UNUSED,
- enum mailbox_list_file_type type,
- enum mailbox_info_flags *flags_r)
-{
- const char *path;
- struct stat st;
-
- /* 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 */
- 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;
- return 1;
- } else if (errno == EACCES || errno == ELOOP) {
- *flags_r = MAILBOX_NOSELECT;
- return 1;
- } else if (ENOTFOUND(errno)) {
- *flags_r = MAILBOX_NONEXISTENT;
- return 0;
- } else {
- mailbox_list_set_critical(ctx->list, "stat(%s) failed: %m",
- path);
- return -1;
- }
-}
-
-static void raw_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
- struct mailbox_list *list)
-{
- list->v.iter_is_mailbox = raw_list_iter_is_mailbox;
-}
-
struct mail_storage raw_storage = {
.name = RAW_STORAGE_NAME,
.class_flags = MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE |
raw_storage_alloc,
NULL,
NULL,
- raw_storage_add_list,
+ NULL,
raw_storage_get_list_settings,
NULL,
raw_mailbox_alloc,
index-mailbox-list-sync.c \
mailbox-list-delete.c \
mailbox-list-fs.c \
+ mailbox-list-fs-flags.c \
mailbox-list-fs-iter.c \
mailbox-list-maildir.c \
mailbox-list-maildir-iter.c \
continue;
}
+ mailbox_dir = list->v.is_internal_name != NULL &&
+ list->v.is_internal_name(list, d->d_name);
+
str_truncate(full_path, dir_len);
- mailbox_dir = list->v.is_mailbox_dir != NULL &&
- list->v.is_mailbox_dir(list, str_c(full_path),
- d->d_name);
str_append(full_path, d->d_name);
if (mailbox_dir) {
--- /dev/null
+/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "mailbox-list-fs.h"
+
+#include <sys/stat.h>
+
+/* Assume that if atime < mtime, there are new mails. If it's good enough for
+ UW-IMAP, it's good enough for us. */
+#define STAT_GET_MARKED_FILE(st) \
+ ((st).st_size == 0 ? MAILBOX_UNMARKED : \
+ (st).st_atime < (st).st_mtime ? MAILBOX_MARKED : MAILBOX_UNMARKED)
+
+static int
+list_is_maildir_mailbox(struct mailbox_list *list, const char *dir,
+ const char *fname, enum mailbox_list_file_type type,
+ enum mailbox_info_flags *flags_r)
+{
+ const char *path, *maildir_path;
+ struct stat st, st2;
+ bool mailbox_files;
+
+ switch (type) {
+ case MAILBOX_LIST_FILE_TYPE_FILE:
+ case MAILBOX_LIST_FILE_TYPE_OTHER:
+ /* non-directories aren't valid */
+ *flags_r |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
+ return 0;
+
+ case MAILBOX_LIST_FILE_TYPE_DIR:
+ case MAILBOX_LIST_FILE_TYPE_UNKNOWN:
+ case MAILBOX_LIST_FILE_TYPE_SYMLINK:
+ break;
+ }
+
+ path = t_strdup_printf("%s/%s", dir, fname);
+ if (stat(path, &st) < 0) {
+ if (errno == ENOENT) {
+ *flags_r |= MAILBOX_NONEXISTENT;
+ return 0;
+ } else {
+ /* non-selectable. probably either access denied, or
+ symlink destination not found. don't bother logging
+ errors. */
+ *flags_r |= MAILBOX_NOSELECT;
+ return 1;
+ }
+ }
+ if (!S_ISDIR(st.st_mode)) {
+ if (strncmp(fname, ".nfs", 4) == 0) {
+ /* temporary NFS file */
+ *flags_r |= MAILBOX_NONEXISTENT;
+ } else {
+ *flags_r |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
+ }
+ return 0;
+ }
+
+ /* ok, we've got a directory. see what we can do about it. */
+
+ /* 1st link is "."
+ 2nd link is ".."
+ 3rd link is either child mailbox or mailbox dir
+ rest of the links are child mailboxes
+
+ if mailboxes are files, then 3+ links are all child mailboxes.
+ */
+ mailbox_files = (list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0;
+ if (st.st_nlink == 2 && !mailbox_files) {
+ *flags_r |= MAILBOX_NOSELECT;
+ return 1;
+ }
+
+ /* we have at least one directory. see if this mailbox is selectable */
+ maildir_path = t_strconcat(path, "/", list->set.maildir_name, NULL);
+ if (stat(maildir_path, &st2) < 0)
+ *flags_r |= MAILBOX_NOSELECT | MAILBOX_CHILDREN;
+ else if (!S_ISDIR(st2.st_mode)) {
+ if (mailbox_files) {
+ *flags_r |= st.st_nlink == 2 ?
+ MAILBOX_NOCHILDREN : MAILBOX_CHILDREN;
+ } else {
+ *flags_r |= MAILBOX_NOSELECT | MAILBOX_CHILDREN;
+ }
+ } else {
+ /* now we know what link count 3 means. */
+ if (st.st_nlink == 3)
+ *flags_r |= MAILBOX_NOCHILDREN;
+ else
+ *flags_r |= MAILBOX_CHILDREN;
+ }
+ *flags_r |= MAILBOX_SELECT;
+ return 1;
+}
+
+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;
+}
+
+int fs_list_get_mailbox_flags(struct mailbox_list *list,
+ const char *dir, const char *fname,
+ enum mailbox_list_file_type type,
+ struct stat *st_r,
+ enum mailbox_info_flags *flags_r)
+{
+ struct stat st;
+ const char *path;
+
+ memset(st_r, 0, sizeof(*st_r));
+ *flags_r = 0;
+
+ if (*list->set.maildir_name != '\0') {
+ /* maildir_name is set: we the code is common for all
+ storage types */
+ return list_is_maildir_mailbox(list, dir, fname, type, flags_r);
+ }
+ if (list->v.is_internal_name != NULL &&
+ list->v.is_internal_name(list, fname)) {
+ /* skip internal dirs */
+ *flags_r |= MAILBOX_NOSELECT;
+ return 0;
+ }
+
+ switch (type) {
+ case MAILBOX_LIST_FILE_TYPE_DIR:
+ if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
+ *flags_r |= MAILBOX_NOSELECT | MAILBOX_CHILDREN;
+ return 1;
+ }
+ break;
+ case MAILBOX_LIST_FILE_TYPE_FILE:
+ if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0) {
+ *flags_r |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* we've done all filtering we can before stat()ing */
+ path = t_strconcat(dir, "/", fname, NULL);
+ if (stat(path, &st) < 0) {
+ if (ENOTFOUND(errno)) {
+ *flags_r |= MAILBOX_NONEXISTENT;
+ return 0;
+ } else if (ENOACCESS(errno)) {
+ *flags_r |= MAILBOX_NOSELECT;
+ return 1;
+ } else {
+ /* non-selectable. probably either access denied, or
+ symlink destination not found. don't bother logging
+ errors. */
+ mailbox_list_set_critical(list, "stat(%s) failed: %m",
+ path);
+ return -1;
+ }
+ }
+ *st_r = st;
+
+ if (!S_ISDIR(st.st_mode)) {
+ if (strncmp(fname, ".nfs", 4) == 0) {
+ /* temporary NFS file */
+ *flags_r |= MAILBOX_NONEXISTENT;
+ return 0;
+ }
+
+ if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0) {
+ *flags_r |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
+ return 0;
+ }
+ /* looks like a valid mailbox file */
+ if (is_inbox_file(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 */
+ } else {
+ *flags_r |= MAILBOX_NOINFERIORS;
+ }
+ } else {
+ if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
+ *flags_r |= MAILBOX_NOSELECT | MAILBOX_CHILDREN;
+ return 1;
+ }
+ }
+
+ if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
+ *flags_r |= STAT_GET_MARKED_FILE(st);
+ } else if (list->v.is_internal_name == NULL) {
+ /* link count < 2 can happen with filesystems that don't
+ support link counts. we'll just ignore them for now.. */
+ if (st.st_nlink == 2)
+ *flags_r |= MAILBOX_NOCHILDREN;
+ else if (st.st_nlink > 2)
+ *flags_r |= MAILBOX_CHILDREN;
+ }
+ return 1;
+}
#include "lib.h"
#include "array.h"
-#include "unlink-directory.h"
#include "imap-match.h"
#include "mailbox-tree.h"
#include "mailbox-list-subscriptions.h"
static struct mailbox_info *fs_list_inbox(struct fs_list_iterate_context *ctx)
{
- const char *inbox_path, *dir, *fname;
-
ctx->info.flags = 0;
ctx->info.name = "INBOX";
- inbox_path = mailbox_list_get_path(ctx->ctx.list, "INBOX",
- MAILBOX_LIST_PATH_TYPE_DIR);
- path_split(inbox_path, &dir, &fname);
- if (ctx->ctx.list->v.iter_is_mailbox(&ctx->ctx, dir, fname, "INBOX",
- MAILBOX_LIST_FILE_TYPE_UNKNOWN,
- &ctx->info.flags) < 0)
+ if (mailbox_list_mailbox(ctx->ctx.list, "INBOX", &ctx->info.flags) < 0)
ctx->ctx.failed = TRUE;
ctx->info.flags |= fs_list_get_subscription_flags(ctx, "INBOX");
{
struct mail_namespace *ns = ctx->ctx.list->ns;
const char *fname = entry->fname;
- const char *list_path;
+ const char *list_path, *root_dir;
enum imap_match_result match;
+ struct stat st;
int ret;
/* skip . and .. */
return 0;
}
+ if (strcmp(fname, ctx->ctx.list->set.subscription_fname) == 0) {
+ /* skip subscriptions file */
+ root_dir = mailbox_list_get_path(ctx->ctx.list, NULL,
+ MAILBOX_LIST_PATH_TYPE_DIR);
+ if (strcmp(root_dir, ctx->dir->real_path) == 0)
+ return 0;
+ }
+
+
/* get the info.flags using callback */
- ctx->info.flags = 0;
ret = ctx->ctx.list->v.
- iter_is_mailbox(&ctx->ctx, ctx->dir->real_path, fname,
- list_path, entry->type, &ctx->info.flags);
+ get_mailbox_flags(ctx->ctx.list, ctx->dir->real_path, fname,
+ entry->type, &st, &ctx->info.flags);
if (ret <= 0)
return ret;
struct mailbox_node *node;
enum mailbox_info_flags flags;
const char *path, *dir, *fname;
+ struct stat st;
node = mailbox_tree_iterate_next(ctx->tree_iter, &ctx->info.name);
if (node == NULL)
path = mailbox_list_get_path(ctx->ctx.list, ctx->info.name,
MAILBOX_LIST_PATH_TYPE_DIR);
path_split(path, &dir, &fname);
- ctx->info.flags = 0;
- if (ctx->ctx.list->v.iter_is_mailbox(&ctx->ctx, dir, fname,
- ctx->info.name,
- MAILBOX_LIST_FILE_TYPE_UNKNOWN,
- &ctx->info.flags) < 0)
+ if (ctx->ctx.list->v.get_mailbox_flags(ctx->ctx.list, dir, fname,
+ MAILBOX_LIST_FILE_TYPE_UNKNOWN,
+ &st, &ctx->info.flags) < 0)
ctx->ctx.failed = TRUE;
ctx->info.flags |= flags;
static bool
fs_list_is_valid_common_nonfs(struct mailbox_list *list, const char *name)
{
- const char *p;
- bool newdir;
- size_t maildir_len;
+ bool ret, allow_internal_dirs;
/* make sure it's not absolute path */
if (*name == '/' || *name == '~')
/* make sure the mailbox name doesn't contain any foolishness:
"../" could give access outside the mailbox directory.
"./" and "//" could fool ACL checks. */
- newdir = TRUE;
- maildir_len = strlen(list->set.maildir_name);
- for (p = name; *p != '\0'; p++) {
- if (newdir) {
- if (p[0] == '/')
- return FALSE; /* // */
- if (p[0] == '.') {
- if (p[1] == '/' || p[1] == '\0')
- return FALSE; /* ./ */
- if (p[1] == '.' &&
- (p[2] == '/' || p[2] == '\0'))
- return FALSE; /* ../ */
+ allow_internal_dirs = list->v.is_internal_name == NULL ||
+ *list->set.maildir_name != '\0';
+ T_BEGIN {
+ const char *const *names;
+
+ names = t_strsplit(name, "/");
+ for (; *names != NULL; names++) {
+ const char *n = *names;
+
+ if (*n == '\0')
+ break; /* // */
+ if (*n == '.') {
+ if (n[1] == '\0')
+ break; /* ./ */
+ if (n[1] == '.' && n[2] == '\0')
+ break; /* ../ */
}
- if (maildir_len > 0 &&
- strncmp(p, list->set.maildir_name,
- maildir_len) == 0 &&
- (p[maildir_len] == '\0' ||
- p[maildir_len] == '/')) {
+ if (*list->set.maildir_name != '\0' &&
+ strcmp(list->set.maildir_name, n) == 0) {
/* don't allow maildir_name to be used as part
of the mailbox name */
- return FALSE;
+ break;
}
- }
- newdir = p[0] == '/';
- }
- if (name[0] == '.' && (name[1] == '\0' ||
- (name[1] == '.' && name[2] == '\0'))) {
- /* "." and ".." aren't allowed. */
- return FALSE;
- }
+ if (!allow_internal_dirs &&
+ list->v.is_internal_name(list, n))
+ break;
+ }
+ ret = *names == NULL;
+ } T_END;
- return TRUE;
+ return ret;
}
static bool
{
struct stat st;
const char *path, *dir_path;
+ enum mailbox_info_flags flags;
path = mailbox_list_get_path(_list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (strcmp(name, "INBOX") == 0 || stat(path, &st) == 0) {
- *status = MAILBOX_NAME_EXISTS_MAILBOX;
+ if (*_list->set.maildir_name != '\0' ||
+ _list->v.is_internal_name == NULL || !S_ISDIR(st.st_mode)) {
+ *status = MAILBOX_NAME_EXISTS_MAILBOX;
+ return 0;
+ }
+
+ /* check if mailbox is selectable */
+ if (mailbox_list_mailbox(_list, name, &flags) < 0)
+ return -1;
+ if ((flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) == 0)
+ *status = MAILBOX_NAME_EXISTS_MAILBOX;
+ else
+ *status = MAILBOX_NAME_EXISTS_DIR;
return 0;
}
if (errno == ENOENT) {
fs_list_iter_init,
fs_list_iter_next,
fs_list_iter_deinit,
- NULL,
+ fs_list_get_mailbox_flags,
NULL,
fs_list_set_subscribed,
fs_list_create_mailbox_dir,
const struct mailbox_info *
fs_list_iter_next(struct mailbox_list_iterate_context *ctx);
+int fs_list_get_mailbox_flags(struct mailbox_list *list,
+ const char *dir, const char *fname,
+ enum mailbox_list_file_type type,
+ struct stat *st_r,
+ enum mailbox_info_flags *flags);
+
#endif
#include "lib.h"
#include "str.h"
+#include "ioloop.h"
+#include "unlink-directory.h"
#include "imap-match.h"
#include "mailbox-tree.h"
#include "mailbox-list-subscriptions.h"
#include "mailbox-list-maildir.h"
#include <dirent.h>
+#include <sys/stat.h>
struct maildir_list_iterate_context {
struct mailbox_list_iterate_context ctx;
pool_t pool;
const char *dir;
+ char prefix_char;
struct mailbox_tree_context *tree_ctx;
struct mailbox_tree_iterate_context *tree_iter;
static int
maildir_fill_inbox(struct maildir_list_iterate_context *ctx,
- const char *mailbox_name, struct imap_match_glob *glob,
+ struct imap_match_glob *glob,
bool update_only)
{
const struct mailbox_list_settings *set = &ctx->ctx.list->set;
} else {
/* INBOX is in Maildir root. show it only if it has already
been created */
- ret = ctx->ctx.list->v.
- iter_is_mailbox(&ctx->ctx, ctx->dir, "", mailbox_name,
- MAILBOX_LIST_FILE_TYPE_UNKNOWN, &flags);
+ ret = mailbox_list_mailbox(ctx->ctx.list, "INBOX", &flags);
if (ret < 0)
return -1;
if (ret == 0)
created = FALSE;
node = update_only ?
- mailbox_tree_lookup(ctx->tree_ctx, mailbox_name) :
- mailbox_tree_get(ctx->tree_ctx, mailbox_name, &created);
+ mailbox_tree_lookup(ctx->tree_ctx, "INBOX") :
+ mailbox_tree_get(ctx->tree_ctx, "INBO", &created);
if (created)
node->flags = MAILBOX_NOCHILDREN;
else if (node != NULL)
node->flags &= ~MAILBOX_NONEXISTENT;
- match = imap_match(glob, mailbox_name);
+ match = imap_match(glob, "INBOX");
if ((match & (IMAP_MATCH_YES | IMAP_MATCH_PARENT)) != 0) {
if (!update_only)
node->flags |= MAILBOX_MATCHED;
return 0;
}
+static bool
+maildir_get_type(const char *dir, const char *fname,
+ enum mailbox_list_file_type *type_r,
+ struct stat *st_r,
+ enum mailbox_info_flags *flags)
+{
+ const char *path;
+ struct stat st;
+
+ path = t_strdup_printf("%s/%s", dir, fname);
+ if (stat(path, &st) < 0) {
+ if (errno == ENOENT) {
+ /* just deleted? */
+ *flags |= MAILBOX_NONEXISTENT;
+ } else {
+ *flags |= MAILBOX_NOSELECT;
+ }
+ return FALSE;
+ }
+
+ *st_r = st;
+ if (S_ISDIR(st.st_mode)) {
+ *type_r = MAILBOX_LIST_FILE_TYPE_DIR;
+ return TRUE;
+ } else {
+ if (strncmp(fname, ".nfs", 4) == 0)
+ *flags |= MAILBOX_NONEXISTENT;
+ else
+ *flags |= MAILBOX_NOSELECT;
+ return FALSE;
+ }
+}
+
+int maildir_list_get_mailbox_flags(struct mailbox_list *list,
+ const char *dir, const char *fname,
+ enum mailbox_list_file_type type,
+ struct stat *st_r,
+ enum mailbox_info_flags *flags_r)
+{
+ memset(st_r, 0, sizeof(*st_r));
+ *flags_r = 0;
+
+ switch (type) {
+ case MAILBOX_LIST_FILE_TYPE_DIR:
+ case MAILBOX_LIST_FILE_TYPE_FILE:
+ case MAILBOX_LIST_FILE_TYPE_OTHER:
+ break;
+ case MAILBOX_LIST_FILE_TYPE_UNKNOWN:
+ case MAILBOX_LIST_FILE_TYPE_SYMLINK:
+ /* need to check with stat() to be sure */
+ if (!list->mail_set->maildir_stat_dirs &&
+ strcmp(list->name, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0 &&
+ strncmp(fname, ".nfs", 4) != 0) {
+ /* just assume it's a valid mailbox */
+ return 1;
+ }
+
+ if (!maildir_get_type(dir, fname, &type, st_r, flags_r))
+ return 0;
+ break;
+ }
+
+ switch (type) {
+ case MAILBOX_LIST_FILE_TYPE_DIR:
+ if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
+ *flags_r |= MAILBOX_NOSELECT;
+ return 0;
+ }
+ break;
+ case MAILBOX_LIST_FILE_TYPE_FILE:
+ if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0) {
+ *flags_r |= MAILBOX_NOSELECT;
+ return 0;
+ }
+ break;
+ case MAILBOX_LIST_FILE_TYPE_OTHER:
+ *flags_r |= MAILBOX_NOSELECT;
+ return 0;
+
+ case MAILBOX_LIST_FILE_TYPE_UNKNOWN:
+ case MAILBOX_LIST_FILE_TYPE_SYMLINK:
+ i_unreached();
+ }
+ *flags_r |= MAILBOX_SELECT;
+ return 1;
+}
+
+static bool maildir_delete_trash_dir(struct maildir_list_iterate_context *ctx,
+ const char *fname)
+{
+ const char *path;
+ struct stat st;
+
+ if (fname[1] != ctx->prefix_char || ctx->prefix_char == '\0' ||
+ strcmp(fname+2, MAILBOX_LIST_MAILDIR_TRASH_DIR_NAME) != 0)
+ return FALSE;
+
+ /* this directory is in the middle of being deleted, or the process
+ trying to delete it had died. delete it ourself if it's been there
+ longer than one hour. */
+ path = t_strdup_printf("%s/%s", ctx->dir, fname);
+ if (stat(path, &st) == 0 &&
+ st.st_mtime < ioloop_time - 3600)
+ (void)unlink_directory(path, TRUE);
+
+ return TRUE;
+}
+
static int
maildir_fill_readdir(struct maildir_list_iterate_context *ctx,
struct imap_match_glob *glob, bool update_only)
{
- struct mail_namespace *ns = ctx->ctx.list->ns;
+ struct mailbox_list *list = ctx->ctx.list;
+ struct mail_namespace *ns = list->ns;
DIR *dirp;
struct dirent *d;
const char *mailbox_name;
enum imap_match_result match;
struct mailbox_node *node;
bool created, virtual_names;
- char prefix_char;
+ struct stat st;
int ret;
dirp = opendir(ctx->dir);
if (dirp == NULL) {
if (errno == EACCES) {
- mailbox_list_set_critical(ctx->ctx.list, "%s",
+ mailbox_list_set_critical(list, "%s",
mail_error_eacces_msg("opendir", ctx->dir));
} else if (errno != ENOENT) {
- mailbox_list_set_critical(ctx->ctx.list,
+ mailbox_list_set_critical(list,
"opendir(%s) failed: %m", ctx->dir);
return -1;
}
}
virtual_names = (ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0;
- prefix_char =
- strcmp(ctx->ctx.list->name, MAILBOX_LIST_NAME_IMAPDIR) != 0 ?
- ctx->ctx.list->hierarchy_sep : '\0';
mailbox = t_str_new(MAILBOX_LIST_NAME_MAX_LENGTH);
while ((d = readdir(dirp)) != NULL) {
const char *fname = d->d_name;
- if (fname[0] == prefix_char)
+ if (fname[0] == ctx->prefix_char)
mailbox_name = fname + 1;
else {
- if (prefix_char != '\0' || fname[0] == '.')
+ if (ctx->prefix_char != '\0' || fname[0] == '.')
continue;
mailbox_name = fname;
}
continue;
/* check if this is an actual mailbox */
- flags = 0;
+ if (maildir_delete_trash_dir(ctx, fname))
+ continue;
+
T_BEGIN {
- ret = ctx->ctx.list->v.
- iter_is_mailbox(&ctx->ctx, ctx->dir, fname,
- mailbox_name,
- mailbox_list_get_file_type(d), &flags);
+ ret = list->v.get_mailbox_flags(list, ctx->dir, fname,
+ mailbox_list_get_file_type(d), &st, &flags);
} T_END;
if (ret <= 0) {
if (ret < 0)
}
if (closedir(dirp) < 0) {
- mailbox_list_set_critical(ctx->ctx.list,
- "readdir(%s) failed: %m", ctx->dir);
+ mailbox_list_set_critical(list, "readdir(%s) failed: %m",
+ ctx->dir);
return -1;
}
return 0;
else {
/* make sure INBOX is listed */
- mailbox_name = !virtual_names ? "INBOX" :
- mail_namespace_get_vname(ns, mailbox, "INBOX");
- return maildir_fill_inbox(ctx, mailbox_name, glob, update_only);
+ return maildir_fill_inbox(ctx, glob, update_only);
}
}
ctx->pool = pool;
ctx->tree_ctx = mailbox_tree_init(sep);
ctx->info.ns = _list->ns;
+ ctx->prefix_char = strcmp(_list->name, MAILBOX_LIST_NAME_IMAPDIR) == 0 ?
+ '\0' : _list->hierarchy_sep;
glob = imap_match_init_multiple(pool, patterns, TRUE, sep);
maildir_list_iter_init,
maildir_list_iter_next,
maildir_list_iter_deinit,
- NULL,
+ maildir_list_get_mailbox_flags,
NULL,
maildir_list_set_subscribed,
maildir_list_create_mailbox_dir,
maildir_list_iter_init,
maildir_list_iter_next,
maildir_list_iter_deinit,
- NULL,
+ maildir_list_get_mailbox_flags,
NULL,
maildir_list_set_subscribed,
maildir_list_create_mailbox_dir,
const struct mailbox_info *
maildir_list_iter_next(struct mailbox_list_iterate_context *ctx);
+int maildir_list_get_mailbox_flags(struct mailbox_list *list,
+ const char *dir, const char *fname,
+ enum mailbox_list_file_type type,
+ struct stat *st_r,
+ enum mailbox_info_flags *flags);
+
#endif
DEF(SET_BOOL, mailbox_list_index_disable),
DEF(SET_BOOL, mail_debug),
DEF(SET_BOOL, mail_full_filesystem_access),
+ DEF(SET_BOOL, maildir_stat_dirs),
DEF(SET_ENUM, lock_method),
DEF(SET_STR, pop3_uidl_format),
.mailbox_list_index_disable = FALSE,
.mail_debug = FALSE,
.mail_full_filesystem_access = FALSE,
+ .maildir_stat_dirs = FALSE,
.lock_method = "fcntl:flock:dotlock",
.pop3_uidl_format = "%08Xu%08Xv"
};
bool mailbox_list_index_disable;
bool mail_debug;
bool mail_full_filesystem_access;
+ bool maildir_stat_dirs;
const char *lock_method;
const char *pop3_uidl_format;
#define MAILBOX_LOG_FILE_NAME "dovecot.mailbox.log"
enum mailbox_log_record_type;
+struct stat;
struct dirent;
struct imap_match_glob;
struct mailbox_tree_context;
+#define MAILBOX_INFO_FLAGS_FINISHED(flags) \
+ (((flags) & (MAILBOX_SELECT | MAILBOX_NOSELECT | \
+ MAILBOX_NONEXISTENT)) != 0)
+
+
struct mailbox_list_vfuncs {
struct mailbox_list *(*alloc)(void);
void (*deinit)(struct mailbox_list *list);
(*iter_next)(struct mailbox_list_iterate_context *ctx);
int (*iter_deinit)(struct mailbox_list_iterate_context *ctx);
- /* Returns -1 if error, 0 if it's not a valid mailbox, 1 if it is.
- flags may be updated (especially the children flags). */
- int (*iter_is_mailbox)(struct mailbox_list_iterate_context *ctx,
- const char *dir, const char *fname,
- const char *mailbox_name,
- enum mailbox_list_file_type type,
- enum mailbox_info_flags *flags_r);
- /* Returns TRUE if dir/name points to mailbox's internal directory.
+ int (*get_mailbox_flags)(struct mailbox_list *list,
+ const char *dir, const char *fname,
+ enum mailbox_list_file_type type,
+ struct stat *st_r,
+ enum mailbox_info_flags *flags_r);
+ /* Returns TRUE if name is mailbox's internal file/directory.
If it does, mailbox deletion assumes it can safely delete it. */
- bool (*is_mailbox_dir)(struct mailbox_list *list, const char *dir,
- const char *name);
+ bool (*is_internal_name)(struct mailbox_list *list, const char *name);
int (*set_subscribed)(struct mailbox_list *list,
const char *name, bool set);
int mailbox_list_mailbox(struct mailbox_list *list, const char *name,
enum mailbox_info_flags *flags_r)
{
- struct mailbox_list_iterate_context ctx;
- const char *path;
-
- memset(&ctx, 0, sizeof(ctx));
- ctx.list = list;
+ const char *path, *fname;
+ struct stat st;
- *flags_r = 0;
path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
- return list->v.iter_is_mailbox == NULL ? 0 :
- list->v.iter_is_mailbox(&ctx, path, "", "",
- MAILBOX_LIST_FILE_TYPE_UNKNOWN,
- flags_r);
+ fname = strrchr(path, '/');
+ if (fname == NULL) {
+ fname = path;
+ path = "/";
+ } else {
+ path = t_strdup_until(path, fname);
+ fname++;
+ }
+ return list->v.get_mailbox_flags(list, path, fname,
+ MAILBOX_LIST_FILE_TYPE_UNKNOWN,
+ &st, flags_r);
}
static bool mailbox_list_init_changelog(struct mailbox_list *list)
MAILBOX_CHILD_SUBSCRIBED = 0x100,
/* Internally used by lib-storage */
+ MAILBOX_SELECT = 0x20000000,
MAILBOX_MATCHED = 0x40000000
};
}
static int
-virtual_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx
- ATTR_UNUSED,
- const char *dir, const char *fname,
- const char *mailbox_name ATTR_UNUSED,
- enum mailbox_list_file_type type,
- enum mailbox_info_flags *flags)
+virtual_list_get_mailbox_flags(struct mailbox_list *list,
+ const char *dir, const char *fname,
+ enum mailbox_list_file_type type,
+ struct stat *st_r,
+ enum mailbox_info_flags *flags)
{
- const char *path, *maildir_path;
- struct stat st;
- int ret = 1;
-
- /* try to avoid stat() with these checks */
- if (type != MAILBOX_LIST_FILE_TYPE_DIR &&
- type != MAILBOX_LIST_FILE_TYPE_SYMLINK &&
- type != MAILBOX_LIST_FILE_TYPE_UNKNOWN) {
- /* it's a file */
- *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
- return 0;
- }
+ struct virtual_mailbox_list *mlist = VIRTUAL_LIST_CONTEXT(list);
+ struct stat st2;
+ const char *virtual_path;
+ int ret;
- /* need to stat() then */
- path = t_strconcat(dir, "/", fname, NULL);
- if (stat(path, &st) == 0) {
- if (!S_ISDIR(st.st_mode)) {
- /* non-directory */
- *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
- ret = 0;
- } else if (st.st_nlink == 2) {
- /* no subdirectories */
- *flags |= MAILBOX_NOCHILDREN;
- } else if (*ctx->list->set.maildir_name != '\0') {
- /* non-default configuration: we have one directory
- containing the mailboxes. if there are 3 links,
- either this is a selectable mailbox without children
- or non-selectable mailbox with children */
- if (st.st_nlink > 3)
- *flags |= MAILBOX_CHILDREN;
- } else {
- /* default configuration: all subdirectories are
- child mailboxes. */
- if (st.st_nlink > 2)
- *flags |= MAILBOX_CHILDREN;
- }
- } else {
- /* non-selectable. probably either access denied, or symlink
- destination not found. don't bother logging errors. */
+ ret = mlist->module_ctx.super.
+ get_mailbox_flags(list, dir, fname, type, st_r, flags);
+ if (ret <= 0 || MAILBOX_INFO_FLAGS_FINISHED(*flags))
+ return ret;
+
+ /* see if it's a selectable mailbox */
+ virtual_path = t_strconcat(dir, "/", fname, "/"VIRTUAL_CONFIG_FNAME,
+ NULL);
+ if (stat(virtual_path, &st2) < 0)
*flags |= MAILBOX_NOSELECT;
- }
- if ((*flags & MAILBOX_NOSELECT) == 0) {
- /* make sure it's a selectable mailbox */
- maildir_path = t_strconcat(path, "/"VIRTUAL_CONFIG_FNAME, NULL);
- if (stat(maildir_path, &st) < 0)
- *flags |= MAILBOX_NOSELECT;
- }
return ret;
}
+static void virtual_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
+ struct mailbox_list *list)
+{
+ struct virtual_mailbox_list *mlist;
+
+ mlist = p_new(list->pool, struct virtual_mailbox_list, 1);
+ mlist->module_ctx.super = list->v;
+
+ list->ns->flags |= NAMESPACE_FLAG_NOQUOTA;
+ list->v.get_mailbox_flags = virtual_list_get_mailbox_flags;
+
+ MODULE_CONTEXT_SET(list, virtual_mailbox_list_module, mlist);
+}
+
static int virtual_backend_uidmap_cmp(const uint32_t *uid,
const struct virtual_backend_uidmap *map)
{
return index_storage_is_inconsistent(box);
}
-static void virtual_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
- struct mailbox_list *list)
-{
- struct virtual_mailbox_list *mlist;
-
- mlist = p_new(list->pool, struct virtual_mailbox_list, 1);
- mlist->module_ctx.super = list->v;
-
- list->ns->flags |= NAMESPACE_FLAG_NOQUOTA;
- list->v.iter_is_mailbox = virtual_list_iter_is_mailbox;
-
- MODULE_CONTEXT_SET(list, virtual_mailbox_list_module, mlist);
-}
-
struct mail_storage virtual_storage = {
.name = VIRTUAL_STORAGE_NAME,
.class_flags = 0,