dovecot: If storage backend doesn't return children flags, scan ...
dovecot at dovecot.org
dovecot at dovecot.org
Thu Nov 15 08:15:47 EET 2007
details: http://hg.dovecot.org/dovecot/rev/b2bcfe178a30
changeset: 6805:b2bcfe178a30
user: Timo Sirainen <tss at iki.fi>
date: Thu Nov 15 08:14:51 2007 +0200
description:
If storage backend doesn't return children flags, scan them ourself.
diffstat:
1 file changed, 159 insertions(+), 73 deletions(-)
src/lib-storage/list/mailbox-list-fs-iter.c | 232 ++++++++++++++++++---------
diffs (truncated from 317 to 300 lines):
diff -r ed4e708951de -r b2bcfe178a30 src/lib-storage/list/mailbox-list-fs-iter.c
--- a/src/lib-storage/list/mailbox-list-fs-iter.c Thu Nov 15 07:14:41 2007 +0200
+++ b/src/lib-storage/list/mailbox-list-fs-iter.c Thu Nov 15 08:14:51 2007 +0200
@@ -19,8 +19,13 @@ struct list_dir_context {
DIR *dirp;
char *real_path, *virtual_path;
+ const struct dirent *next_dirent;
+ struct mailbox_info info;
+
unsigned int pattern_pos;
struct dirent dirent;
+
+ unsigned int delayed_send:1;
};
struct fs_list_iterate_context {
@@ -110,6 +115,9 @@ pattern_has_wildcard_at(struct fs_list_i
if (ret == 0)
return FALSE;
+ if (pattern[pos] == '\0')
+ return TRUE;
+
for (; pattern[pos] != '\0' && pattern[pos] != ctx->sep; pos++) {
if (pattern[pos] == '%' || pattern[pos] == '*')
return TRUE;
@@ -339,15 +347,114 @@ static struct mailbox_info *fs_list_inbo
return &ctx->info;
}
+static bool
+list_file_inbox(struct fs_list_iterate_context *ctx, const char *fname)
+{
+ const char *real_path, *inbox_path;
+
+ real_path = t_strconcat(ctx->dir->real_path, "/", fname, NULL);
+ if (ctx->inbox_listed) {
+ /* already listed the INBOX */
+ return FALSE;
+ }
+
+ inbox_path = mailbox_list_get_path(ctx->ctx.list, "INBOX",
+ MAILBOX_LIST_PATH_TYPE_DIR);
+ if (strcmp(real_path, inbox_path) == 0 &&
+ (ctx->info.flags & MAILBOX_NOINFERIORS) != 0) {
+ /* delay listing in case there's a INBOX/ directory */
+ ctx->inbox_found = TRUE;
+ ctx->inbox_flags = ctx->info.flags;
+ return FALSE;
+ }
+ if (strcmp(fname, "INBOX") != 0 ||
+ (ctx->info.flags & MAILBOX_NOINFERIORS) != 0) {
+ /* duplicate INBOX, can't show this */
+ return FALSE;
+ }
+
+ /* INBOX/ directory. show the INBOX list now */
+ if ((ctx->ctx.list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0) {
+ /* this directory is the INBOX */
+ } else if (!ctx->inbox_found) {
+ enum mailbox_info_flags dir_flags = ctx->info.flags;
+
+ (void)fs_list_inbox(ctx);
+ ctx->info.flags &= ~(MAILBOX_NOINFERIORS |
+ MAILBOX_NOCHILDREN);
+ ctx->info.flags |= dir_flags;
+ ctx->inbox_found = TRUE;
+ } else {
+ ctx->info.flags &= ~MAILBOX_NOSELECT;
+ ctx->info.flags |= ctx->inbox_flags;
+ }
+ ctx->inbox_listed = TRUE;
+ return TRUE;
+}
+
+static int
+list_file_subdir(struct fs_list_iterate_context *ctx,
+ enum imap_match_result match, const char *list_path,
+ const char *fname)
+{
+ struct list_dir_context *dir;
+ DIR *dirp;
+ enum imap_match_result match2;
+ const char *vpath, *real_path;
+ bool scan_subdir, delayed_send = FALSE;
+ int ret;
+
+ vpath = t_strdup_printf("%s%c", list_path, ctx->sep);
+ match2 = imap_match(ctx->glob, vpath);
+
+ if (match == IMAP_MATCH_YES)
+ ctx->info.name = p_strdup(ctx->info_pool, list_path);
+ else if (match2 == IMAP_MATCH_YES)
+ ctx->info.name = p_strdup(ctx->info_pool, vpath);
+ else
+ ctx->info.name = NULL;
+
+ scan_subdir = (match2 & (IMAP_MATCH_YES | IMAP_MATCH_CHILDREN)) != 0;
+ if ((match == IMAP_MATCH_YES || scan_subdir) &&
+ (ctx->ctx.flags & MAILBOX_LIST_ITER_RETURN_CHILDREN) != 0 &&
+ (ctx->info.flags & (MAILBOX_CHILDREN | MAILBOX_NOCHILDREN)) == 0) {
+ scan_subdir = TRUE;
+ delayed_send = TRUE;
+ }
+
+ if (scan_subdir) {
+ real_path = t_strconcat(ctx->dir->real_path, "/", fname, NULL);
+ ret = list_opendir(ctx, real_path, vpath, &dirp);
+ } else {
+ ret = 0;
+ }
+ if (ret > 0) {
+ dir = i_new(struct list_dir_context, 1);
+ dir->dirp = dirp;
+ dir->real_path = i_strdup(real_path);
+ dir->virtual_path =
+ i_strdup_printf("%s%c", list_path, ctx->sep);
+
+ dir->prev = ctx->dir;
+ ctx->dir = dir;
+
+ if (delayed_send) {
+ dir->delayed_send = TRUE;
+ dir->info = ctx->info;
+ return 0;
+ }
+ } else if (ret < 0)
+ return -1;
+ return match == IMAP_MATCH_YES || match2 == IMAP_MATCH_YES;
+}
+
static int
list_file(struct fs_list_iterate_context *ctx, const struct dirent *d)
{
struct mail_namespace *ns = ctx->ctx.list->ns;
const char *fname = d->d_name;
- struct list_dir_context *dir;
- const char *list_path, *real_path, *vpath, *inbox_path;
- DIR *dirp;
- enum imap_match_result match, match2;
+ const char *list_path;
+ enum imap_match_result match;
int ret;
/* skip . and .. */
@@ -359,8 +466,14 @@ list_file(struct fs_list_iterate_context
/* check the pattern */
list_path = t_strconcat(ctx->dir->virtual_path, fname, NULL);
match = imap_match(ctx->glob, list_path);
- if (match != IMAP_MATCH_YES && (match & IMAP_MATCH_CHILDREN) == 0)
- return 0;
+ if (match != IMAP_MATCH_YES && (match & IMAP_MATCH_CHILDREN) == 0 &&
+ !ctx->dir->delayed_send)
+ return 0;
+
+ if (strcmp(fname, ctx->ctx.list->set.maildir_name) == 0) {
+ /* mail storage's internal directory */
+ return 0;
+ }
/* get the info.flags using callback */
ctx->info.flags = 0;
@@ -371,78 +484,34 @@ list_file(struct fs_list_iterate_context
if (ret <= 0)
return ret;
+ if (ctx->dir->delayed_send) {
+ /* send the parent directory first, then handle this
+ file again if needed */
+ ctx->dir->delayed_send = FALSE;
+ if (match == IMAP_MATCH_YES ||
+ (match & IMAP_MATCH_CHILDREN) != 0)
+ ctx->dir->next_dirent = d;
+ ctx->info = ctx->dir->info;
+ ctx->info.flags |= MAILBOX_CHILDREN;
+ return 1;
+ }
+
ctx->info.flags |= fs_list_get_subscription_flags(ctx, list_path);
/* make sure we give only one correct INBOX */
- real_path = t_strconcat(ctx->dir->real_path, "/", fname, NULL);
if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0 &&
strcasecmp(list_path, "INBOX") == 0) {
- if (ctx->inbox_listed) {
- /* already listed the INBOX */
+ if (!list_file_inbox(ctx, fname))
return 0;
- }
-
- inbox_path = mailbox_list_get_path(ctx->ctx.list, "INBOX",
- MAILBOX_LIST_PATH_TYPE_DIR);
- if (strcmp(real_path, inbox_path) == 0) {
- /* delay listing in case there's a INBOX/ directory */
- ctx->inbox_found = TRUE;
- ctx->inbox_flags = ctx->info.flags;
- return 0;
- }
- if (strcmp(fname, "INBOX") != 0 ||
- (ctx->info.flags & MAILBOX_NOINFERIORS) != 0) {
- /* duplicate INBOX, can't show this */
- return 0;
- }
-
- /* INBOX/ directory. show the INBOX list now */
- if (!ctx->inbox_found) {
- enum mailbox_info_flags dir_flags = ctx->info.flags;
-
- (void)fs_list_inbox(ctx);
- ctx->info.flags &= ~(MAILBOX_NOINFERIORS |
- MAILBOX_NOCHILDREN);
- ctx->info.flags |= dir_flags;
- ctx->inbox_found = TRUE;
- } else {
- ctx->info.flags &= ~MAILBOX_NOSELECT;
- ctx->info.flags |= ctx->inbox_flags;
- }
- ctx->inbox_listed = TRUE;
- }
-
- if ((ctx->info.flags & MAILBOX_NOINFERIORS) == 0) {
- /* subdirectory. scan inside it. */
- vpath = t_strdup_printf("%s%c", list_path, ctx->sep);
- match2 = imap_match(ctx->glob, vpath);
-
- if (match == IMAP_MATCH_YES)
- ctx->info.name = p_strdup(ctx->info_pool, list_path);
- else if (match2 == IMAP_MATCH_YES)
- ctx->info.name = p_strdup(ctx->info_pool, vpath);
- else
- ctx->info.name = NULL;
-
- ret = (match2 & (IMAP_MATCH_YES | IMAP_MATCH_CHILDREN)) == 0 ?
- 0 : list_opendir(ctx, real_path, vpath, &dirp);
- if (ret > 0) {
- dir = i_new(struct list_dir_context, 1);
- dir->dirp = dirp;
- dir->real_path = i_strdup(real_path);
- dir->virtual_path =
- i_strdup_printf("%s%c", list_path, ctx->sep);
-
- dir->prev = ctx->dir;
- ctx->dir = dir;
- } else if (ret < 0)
- return -1;
- return match == IMAP_MATCH_YES || match2 == IMAP_MATCH_YES;
- } else if (match == IMAP_MATCH_YES) {
+ }
+
+ if ((ctx->info.flags & MAILBOX_NOINFERIORS) == 0)
+ return list_file_subdir(ctx, match, list_path, fname);
+
+ if (match == IMAP_MATCH_YES) {
ctx->info.name = p_strdup(ctx->info_pool, list_path);
return 1;
}
-
return 0;
}
@@ -480,7 +549,8 @@ fs_list_subs(struct fs_list_iterate_cont
return &ctx->info;
}
-static struct dirent *fs_list_dir_next(struct fs_list_iterate_context *ctx)
+static const struct dirent *
+fs_list_dir_next(struct fs_list_iterate_context *ctx)
{
struct list_dir_context *dir = ctx->dir;
char *const *patterns;
@@ -489,8 +559,14 @@ static struct dirent *fs_list_dir_next(s
struct stat st;
int ret;
- if (dir->dirp != NULL)
+ if (dir->dirp != NULL) {
+ if (dir->next_dirent != NULL) {
+ const struct dirent *ret = dir->next_dirent;
+ dir->next_dirent = NULL;
+ return ret;
+ }
return readdir(dir->dirp);
+ }
t_push();
for (;;) {
@@ -549,10 +625,11 @@ fs_list_next(struct fs_list_iterate_cont
fs_list_next(struct fs_list_iterate_context *ctx)
{
struct list_dir_context *dir;
- struct dirent *d;
+ const struct dirent *d;
int ret;
- p_clear(ctx->info_pool);
+ if (ctx->dir == NULL || !ctx->dir->delayed_send)
+ p_clear(ctx->info_pool);
while (ctx->dir != NULL) {
More information about the dovecot-cvs
mailing list