]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Changed mailbox_list.iter_is_mailbox() API.
authorTimo Sirainen <tss@iki.fi>
Mon, 15 Feb 2010 00:03:42 +0000 (02:03 +0200)
committerTimo Sirainen <tss@iki.fi>
Mon, 15 Feb 2010 00:03:42 +0000 (02:03 +0200)
--HG--
branch : HEAD

25 files changed:
src/lib-storage/index/cydir/cydir-storage.c
src/lib-storage/index/dbox-common/dbox-storage.c
src/lib-storage/index/dbox-common/dbox-storage.h
src/lib-storage/index/dbox-multi/mdbox-storage.c
src/lib-storage/index/dbox-single/sdbox-storage.c
src/lib-storage/index/maildir/maildir-settings.c
src/lib-storage/index/maildir/maildir-settings.h
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/mbox/mbox-storage.c
src/lib-storage/index/raw/raw-storage.c
src/lib-storage/list/Makefile.am
src/lib-storage/list/mailbox-list-delete.c
src/lib-storage/list/mailbox-list-fs-flags.c [new file with mode: 0644]
src/lib-storage/list/mailbox-list-fs-iter.c
src/lib-storage/list/mailbox-list-fs.c
src/lib-storage/list/mailbox-list-fs.h
src/lib-storage/list/mailbox-list-maildir-iter.c
src/lib-storage/list/mailbox-list-maildir.c
src/lib-storage/list/mailbox-list-maildir.h
src/lib-storage/mail-storage-settings.c
src/lib-storage/mail-storage-settings.h
src/lib-storage/mailbox-list-private.h
src/lib-storage/mailbox-list.c
src/lib-storage/mailbox-list.h
src/plugins/virtual/virtual-storage.c

index 7492b86326ba9b083a99d5dfc363cbeb4c006348..367f41684eef67116a96c57b21a5d6c993d54be7 100644 (file)
@@ -116,66 +116,6 @@ static void cydir_notify_changes(struct mailbox *box)
                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,
@@ -185,7 +125,7 @@ struct mail_storage cydir_storage = {
                cydir_storage_alloc,
                NULL,
                NULL,
-               cydir_storage_add_list,
+               NULL,
                cydir_storage_get_list_settings,
                NULL,
                cydir_mailbox_alloc,
index 569853a32d74997a85359774fba88374c37ca67d..1b10d48c988aef717d192afe26ad7f444e4e28d0 100644 (file)
@@ -139,70 +139,3 @@ int dbox_mailbox_create(struct mailbox *box,
                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;
-}
index 145c13964b4042bd86acf17642f3849668e807dd..c599b274b6a604fb195db54e8a0a5080fc9f370c 100644 (file)
@@ -49,10 +49,5 @@ void dbox_notify_changes(struct mailbox *box);
 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
index 3db6943ec84af0aff45f96a4a605c151ab09cb7f..8a13635635fcb142021f2f74e87ade5dabcb1d2c 100644 (file)
 #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;
@@ -313,18 +303,6 @@ static int mdbox_mailbox_delete(struct mailbox *box)
        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,
@@ -334,7 +312,7 @@ struct mail_storage mdbox_storage = {
                mdbox_storage_alloc,
                mdbox_storage_create,
                mdbox_storage_destroy,
-               dbox_storage_add_list,
+               NULL,
                dbox_storage_get_list_settings,
                NULL,
                mdbox_mailbox_alloc,
index ffd319c562a3ea5cf475bfc4c2e25866a29b1ca3..4ea1a896b716606a1a37d4c51202931a40e04d9b 100644 (file)
@@ -8,20 +8,10 @@
 #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;
@@ -203,18 +193,6 @@ dbox_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
        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,
@@ -224,7 +202,7 @@ struct mail_storage dbox_storage = {
                sdbox_storage_alloc,
                NULL,
                NULL,
-               sdbox_storage_add_list,
+               NULL,
                dbox_storage_get_list_settings,
                NULL,
                sdbox_mailbox_alloc,
index ee66618000edd473731bac393f406b56091cf019..2064681cb02254a4fd86a44f8edefbab4f23b720 100644 (file)
@@ -12,7 +12,6 @@
        { 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),
@@ -21,7 +20,6 @@ static const struct setting_define maildir_setting_defines[] = {
 };
 
 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
index e74f0615f5be74e32508207c78477af1738fee98..47bf33b962102e2b8dcf9a57d28b00caa3a0f131 100644 (file)
@@ -2,7 +2,6 @@
 #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;
index 3b02bb61e1e954ae1c9dd7a545f92cfbc71ce698..cfa9d2261e98d8e7d0899f2c9266819bc732c83b 100644 (file)
@@ -4,10 +4,8 @@
 #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"
@@ -31,52 +29,6 @@ static MODULE_CONTEXT_DEFINE_INIT(maildir_mailbox_list_module,
                                  &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;
@@ -128,7 +80,7 @@ static void maildir_storage_get_list_settings(const struct mail_namespace *ns,
        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) {
@@ -533,181 +485,63 @@ static void maildir_notify_changes(struct mailbox *box)
 }
 
 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)
@@ -720,28 +554,6 @@ 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,
index f022715a9c0cfdc920a77902d97aa7887f3701d4..6e9adf6c0373f4d59c1b20cef52796f5fde66607 100644 (file)
@@ -583,111 +583,17 @@ static void mbox_notify_changes(struct mailbox *box)
 }
 
 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,
@@ -704,9 +610,7 @@ 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);
 }
index 6bba98968061887a56608deaa8f353dc78caf391..101ca45cbb624dba1408c01478ef92671ce4dd67 100644 (file)
@@ -109,54 +109,6 @@ static void raw_notify_changes(struct mailbox *box ATTR_UNUSED)
 {
 }
 
-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 |
@@ -167,7 +119,7 @@ struct mail_storage raw_storage = {
                raw_storage_alloc,
                NULL,
                NULL,
-               raw_storage_add_list,
+               NULL,
                raw_storage_get_list_settings,
                NULL,
                raw_mailbox_alloc,
index a646539a154b31092fa617d342f913e1f8e2899a..2cbbcd2ef1093cc1d317a6ef1c47b64f69b9ef03 100644 (file)
@@ -13,6 +13,7 @@ libstorage_list_la_SOURCES = \
        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 \
index c9fcb4085881f71b7f7a99ebb6ed60d412bd2f9e..07fb5b94b056fa34243298e073b28ca745c57c18 100644 (file)
@@ -150,10 +150,10 @@ int mailbox_list_delete_mailbox_nonrecursive(struct mailbox_list *list,
                                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) {
diff --git a/src/lib-storage/list/mailbox-list-fs-flags.c b/src/lib-storage/list/mailbox-list-fs-flags.c
new file mode 100644 (file)
index 0000000..67df324
--- /dev/null
@@ -0,0 +1,208 @@
+/* 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;
+}
index 32a327afaf5366ac38c5ebed4defa74ae12e6604..8f509b70590ea53888ce1aa7895e4b522fbccf2c 100644 (file)
@@ -2,7 +2,6 @@
 
 #include "lib.h"
 #include "array.h"
-#include "unlink-directory.h"
 #include "imap-match.h"
 #include "mailbox-tree.h"
 #include "mailbox-list-subscriptions.h"
@@ -408,17 +407,10 @@ static void inbox_flags_set(struct fs_list_iterate_context *ctx)
 
 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");
@@ -544,8 +536,9 @@ list_file(struct fs_list_iterate_context *ctx,
 {
        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 .. */
@@ -566,11 +559,19 @@ list_file(struct fs_list_iterate_context *ctx,
                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;
 
@@ -618,6 +619,7 @@ fs_list_subs(struct fs_list_iterate_context *ctx)
        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)
@@ -635,11 +637,9 @@ fs_list_subs(struct fs_list_iterate_context *ctx)
        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;
index 922c9afa5a268693f4ebe486edcaa6d9639b1bae..5c328577efef819628e614771a19803ae991320c 100644 (file)
@@ -52,9 +52,7 @@ static bool fs_list_is_valid_common(const char *name, size_t *len_r)
 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 == '~')
@@ -63,38 +61,37 @@ fs_list_is_valid_common_nonfs(struct mailbox_list *list, const char *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
@@ -237,12 +234,25 @@ fs_list_get_mailbox_name_status(struct mailbox_list *_list, const char *name,
 {
        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) {
@@ -625,7 +635,7 @@ struct mailbox_list fs_mailbox_list = {
                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,
index e089b2fbf8ed8920e4c306515d53a8c3b2882723..5724747245714dcdc726f0941dfa4f26316e33d6 100644 (file)
@@ -24,4 +24,10 @@ int fs_list_iter_deinit(struct mailbox_list_iterate_context *ctx);
 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
index dd4c157470cb73ce2139d751bf0447770802ba48..076b7738584ea27519396a43d4b3c5c737fe6e6a 100644 (file)
@@ -2,18 +2,22 @@
 
 #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;
@@ -117,7 +121,7 @@ static void maildir_set_children(struct maildir_list_iterate_context *ctx,
 
 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;
@@ -136,9 +140,7 @@ maildir_fill_inbox(struct maildir_list_iterate_context *ctx,
        } 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)
@@ -147,14 +149,14 @@ maildir_fill_inbox(struct maildir_list_iterate_context *ctx,
 
        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;
@@ -162,11 +164,120 @@ maildir_fill_inbox(struct maildir_list_iterate_context *ctx,
        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;
@@ -175,16 +286,16 @@ maildir_fill_readdir(struct maildir_list_iterate_context *ctx,
        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;
                }
@@ -192,18 +303,15 @@ maildir_fill_readdir(struct maildir_list_iterate_context *ctx,
        }
 
        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;
                }
@@ -228,12 +336,12 @@ maildir_fill_readdir(struct maildir_list_iterate_context *ctx,
                        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)
@@ -276,8 +384,8 @@ maildir_fill_readdir(struct maildir_list_iterate_context *ctx,
        }
 
        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;
        }
 
@@ -285,9 +393,7 @@ maildir_fill_readdir(struct maildir_list_iterate_context *ctx,
                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);
        }
 }
 
@@ -311,6 +417,8 @@ maildir_list_iter_init(struct mailbox_list *_list, const char *const *patterns,
        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);
 
index 8ae113502c59f71b2a837227558cfa603ba18f7c..3744cd61473948db2d874d615e29976672ef95b6 100644 (file)
@@ -630,7 +630,7 @@ struct mailbox_list maildir_mailbox_list = {
                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,
@@ -662,7 +662,7 @@ struct mailbox_list imapdir_mailbox_list = {
                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,
index f6bb39a2cbe75cbbd26345bcdaa145f9ef439328..cefb48f1404997d650f21738991397ae8086c6d6 100644 (file)
@@ -24,4 +24,10 @@ int maildir_list_iter_deinit(struct mailbox_list_iterate_context *ctx);
 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
index af1331c0e3888b12b8c5a9bff3ef9d0be8a5b3bd..a9772c872550c059c79b2713efcd3d6579cf2a52 100644 (file)
@@ -37,6 +37,7 @@ static const struct setting_define mail_storage_setting_defines[] = {
        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),
 
@@ -59,6 +60,7 @@ const struct mail_storage_settings mail_storage_default_settings = {
        .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"
 };
index e4df6c3893505e4c70b8b3257daac66860d3560b..cd207eb7c0859c8be333b889f5d9121cf0c89c47 100644 (file)
@@ -24,6 +24,7 @@ struct mail_storage_settings {
        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;
 
index b4d5575accc5b577e5b04322cf5edcb608840f3f..165bcf0512bb625ffab099bb1f8da1138166e5fa 100644 (file)
 #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);
@@ -47,17 +53,14 @@ struct mailbox_list_vfuncs {
                (*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);
index 3465b53ce38ca70381bdbb8ea535d6bf806d2b20..a54f78b644f6e185c30b34a4b3b1e8fc6cbf72ee 100644 (file)
@@ -663,18 +663,21 @@ int mailbox_list_iter_deinit(struct mailbox_list_iterate_context **_ctx)
 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)
index ba98442ef870e01bc32cbd2a004f74a9d715741e..41f3197fb816d8decd65ba321b055f507ef58758 100644 (file)
@@ -41,6 +41,7 @@ enum mailbox_info_flags {
        MAILBOX_CHILD_SUBSCRIBED        = 0x100,
 
        /* Internally used by lib-storage */
+       MAILBOX_SELECT                  = 0x20000000,
        MAILBOX_MATCHED                 = 0x40000000
 };
 
index 00066cde4efd0973d2ba6a2d128e6d660c79853f..60a92b5c4925f6a0e40d7a6dc11e97341de99ce7 100644 (file)
@@ -304,63 +304,44 @@ static void virtual_notify_changes(struct mailbox *box ATTR_UNUSED)
 }
 
 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)
 {
@@ -440,20 +421,6 @@ static bool virtual_is_inconsistent(struct mailbox *box)
        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,