Mercurial > dovecot > core-2.2
changeset 13791:37c2348b67f5
lib-storage: Moved mailbox list iteration functions to a separate file.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 02 Dec 2011 14:23:47 +0200 |
parents | 6591f7783d55 |
children | b48fb6a08389 |
files | src/lib-storage/Makefile.am src/lib-storage/mailbox-list-iter.c src/lib-storage/mailbox-list.c |
diffstat | 3 files changed, 399 insertions(+), 398 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/Makefile.am Fri Dec 02 13:12:16 2011 +0200 +++ b/src/lib-storage/Makefile.am Fri Dec 02 14:23:47 2011 +0200 @@ -40,6 +40,7 @@ mailbox-header.c \ mailbox-keywords.c \ mailbox-list.c \ + mailbox-list-iter.c \ mailbox-search-result.c \ mailbox-tree.c \ mailbox-uidvalidity.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/mailbox-list-iter.c Fri Dec 02 14:23:47 2011 +0200 @@ -0,0 +1,396 @@ +/* Copyright (c) 2006-2011 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "imap-match.h" +#include "mailbox-tree.h" +#include "mailbox-list-private.h" + +struct ns_list_iterate_context { + struct mailbox_list_iterate_context ctx; + struct mailbox_list_iterate_context *backend_ctx; + struct mail_namespace *namespaces; + pool_t pool; + const char **patterns, **patterns_ns_match; + enum namespace_type type_mask; +}; + +struct mailbox_list_iterate_context * +mailbox_list_iter_init(struct mailbox_list *list, const char *pattern, + enum mailbox_list_iter_flags flags) +{ + const char *patterns[2]; + + patterns[0] = pattern; + patterns[1] = NULL; + return mailbox_list_iter_init_multiple(list, patterns, flags); +} + +static int mailbox_list_subscriptions_refresh(struct mailbox_list *list) +{ + struct mail_namespace *ns = list->ns; + + if ((ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0) { + /* no subscriptions in this namespace. find where they are. */ + ns = mail_namespace_find_subscribable(ns->user->namespaces, + ns->prefix); + if (ns == NULL) { + /* no subscriptions */ + return 0; + } + } + return ns->list->v.subscriptions_refresh(ns->list, list); +} + +struct mailbox_list_iterate_context * +mailbox_list_iter_init_multiple(struct mailbox_list *list, + const char *const *patterns, + enum mailbox_list_iter_flags flags) +{ + struct mailbox_list_iterate_context *ctx; + int ret = 0; + + i_assert(*patterns != NULL); + + if ((flags & (MAILBOX_LIST_ITER_SELECT_SUBSCRIBED | + MAILBOX_LIST_ITER_RETURN_SUBSCRIBED)) != 0) + ret = mailbox_list_subscriptions_refresh(list); + + ctx = list->v.iter_init(list, patterns, flags); + if (ret < 0) + ctx->failed = TRUE; + return ctx; +} + +static bool +ns_match_simple(struct ns_list_iterate_context *ctx, struct mail_namespace *ns) +{ + if ((ctx->type_mask & ns->type) == 0) + return FALSE; + + if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SKIP_ALIASES) != 0) { + if (ns->alias_for != NULL) + return FALSE; + } + return TRUE; +} + +static bool +ns_match_inbox(struct mail_namespace *ns, const char *pattern) +{ + struct imap_match_glob *glob; + + if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0) + return FALSE; + + glob = imap_match_init(pool_datastack_create(), pattern, + TRUE, mail_namespace_get_sep(ns)); + return imap_match(glob, "INBOX") == IMAP_MATCH_YES; +} + +static bool +ns_match_next(struct ns_list_iterate_context *ctx, struct mail_namespace *ns, + const char *pattern) +{ + struct imap_match_glob *glob; + enum imap_match_result result; + const char *prefix_without_sep; + unsigned int len; + + len = ns->prefix_len; + if (len > 0 && ns->prefix[len-1] == mail_namespace_get_sep(ns)) + len--; + + if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX | + NAMESPACE_FLAG_LIST_CHILDREN)) == 0) { + /* non-listable namespace matches only with exact prefix */ + if (strncmp(ns->prefix, pattern, ns->prefix_len) != 0) + return FALSE; + } + + prefix_without_sep = t_strndup(ns->prefix, len); + if (*prefix_without_sep == '\0') + result = IMAP_MATCH_CHILDREN; + else { + glob = imap_match_init(pool_datastack_create(), pattern, + TRUE, mail_namespace_get_sep(ns)); + result = imap_match(glob, prefix_without_sep); + } + + if ((ctx->ctx.flags & MAILBOX_LIST_ITER_STAR_WITHIN_NS) == 0) { + switch (result) { + case IMAP_MATCH_YES: + case IMAP_MATCH_CHILDREN: + return TRUE; + case IMAP_MATCH_NO: + case IMAP_MATCH_PARENT: + break; + } + return FALSE; + } + + switch (result) { + case IMAP_MATCH_YES: + /* allow matching prefix only when it's done without + wildcards */ + if (strcmp(prefix_without_sep, pattern) == 0) + return TRUE; + break; + case IMAP_MATCH_CHILDREN: { + /* allow this only if there isn't another namespace + with longer prefix that matches this pattern + (namespaces are sorted by prefix length) */ + struct mail_namespace *tmp; + + T_BEGIN { + for (tmp = ns->next; tmp != NULL; tmp = tmp->next) { + if (ns_match_simple(ctx, tmp) && + ns_match_next(ctx, tmp, pattern)) + break; + } + } T_END; + if (tmp == NULL) + return TRUE; + break; + } + case IMAP_MATCH_NO: + case IMAP_MATCH_PARENT: + break; + } + return FALSE; +} + +static bool +ns_match(struct ns_list_iterate_context *ctx, struct mail_namespace *ns) +{ + unsigned int i; + + if (!ns_match_simple(ctx, ns)) + return FALSE; + + /* filter out namespaces whose prefix doesn't match. this same code + handles both with and without STAR_WITHIN_NS, so the "without" case + is slower than necessary, but this shouldn't matter much */ + T_BEGIN { + for (i = 0; ctx->patterns_ns_match[i] != NULL; i++) { + if (ns_match_inbox(ns, ctx->patterns_ns_match[i])) + break; + if (ns_match_next(ctx, ns, ctx->patterns_ns_match[i])) + break; + } + } T_END; + + return ctx->patterns_ns_match[i] != NULL; +} + +static struct mail_namespace * +ns_next(struct ns_list_iterate_context *ctx, struct mail_namespace *ns) +{ + for (; ns != NULL; ns = ns->next) { + if (ns_match(ctx, ns)) + break; + } + return ns; +} + +static const struct mailbox_info * +mailbox_list_ns_iter_next(struct mailbox_list_iterate_context *_ctx) +{ + struct ns_list_iterate_context *ctx = + (struct ns_list_iterate_context *)_ctx; + const struct mailbox_info *info; + + info = ctx->backend_ctx == NULL ? NULL : + mailbox_list_iter_next(ctx->backend_ctx); + if (info == NULL && ctx->namespaces != NULL) { + /* go to the next namespace */ + if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0) + _ctx->failed = TRUE; + ctx->ctx.list->ns = ctx->namespaces; + ctx->backend_ctx = + mailbox_list_iter_init_multiple(ctx->namespaces->list, + ctx->patterns, + _ctx->flags); + ctx->namespaces = ns_next(ctx, ctx->namespaces->next); + return mailbox_list_ns_iter_next(_ctx); + } + return info; +} + +static int +mailbox_list_ns_iter_deinit(struct mailbox_list_iterate_context *_ctx) +{ + struct ns_list_iterate_context *ctx = + (struct ns_list_iterate_context *)_ctx; + int ret; + + if (ctx->backend_ctx != NULL) { + if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0) + _ctx->failed = TRUE; + } + ret = _ctx->failed ? -1 : 0; + pool_unref(&ctx->pool); + return ret; +} + +static const char ** +dup_patterns_without_stars(pool_t pool, const char *const *patterns, + unsigned int count) +{ + const char **dup; + unsigned int i; + + dup = p_new(pool, const char *, count + 1); + for (i = 0; i < count; i++) { + char *p = p_strdup(pool, patterns[i]); + dup[i] = p; + + for (; *p != '\0'; p++) { + if (*p == '*') + *p = '%'; + } + } + return dup; +} + +struct mailbox_list_iterate_context * +mailbox_list_iter_init_namespaces(struct mail_namespace *namespaces, + const char *const *patterns, + enum namespace_type type_mask, + enum mailbox_list_iter_flags flags) +{ + struct ns_list_iterate_context *ctx; + unsigned int i, count; + pool_t pool; + + i_assert(namespaces != NULL); + + pool = pool_alloconly_create("mailbox list namespaces", 1024); + ctx = p_new(pool, struct ns_list_iterate_context, 1); + ctx->pool = pool; + ctx->type_mask = type_mask; + ctx->ctx.flags = flags; + ctx->ctx.list = p_new(pool, struct mailbox_list, 1); + ctx->ctx.list->v.iter_next = mailbox_list_ns_iter_next; + ctx->ctx.list->v.iter_deinit = mailbox_list_ns_iter_deinit; + + count = str_array_length(patterns); + ctx->patterns = p_new(pool, const char *, count + 1); + for (i = 0; i < count; i++) + ctx->patterns[i] = p_strdup(pool, patterns[i]); + + if ((flags & MAILBOX_LIST_ITER_STAR_WITHIN_NS) != 0) { + /* create copies of patterns with '*' wildcard changed to '%' */ + ctx->patterns_ns_match = + dup_patterns_without_stars(pool, ctx->patterns, count); + } else { + ctx->patterns_ns_match = ctx->patterns; + } + + namespaces = ns_next(ctx, namespaces); + ctx->ctx.list->ns = namespaces; + if (namespaces != NULL) { + ctx->backend_ctx = + mailbox_list_iter_init_multiple(namespaces->list, + patterns, flags); + ctx->namespaces = ns_next(ctx, namespaces->next); + } + return &ctx->ctx; +} + +const struct mailbox_info * +mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx) +{ + const struct mailbox_info *info; + + info = ctx->list->v.iter_next(ctx); + if (info != NULL) + ctx->list->ns->flags |= NAMESPACE_FLAG_USABLE; + return info; +} + +int mailbox_list_iter_deinit(struct mailbox_list_iterate_context **_ctx) +{ + struct mailbox_list_iterate_context *ctx = *_ctx; + + *_ctx = NULL; + + return ctx->list->v.iter_deinit(ctx); +} + +static void node_fix_parents(struct mailbox_node *node) +{ + /* If we happened to create any of the parents, we need to mark them + nonexistent. */ + node = node->parent; + for (; node != NULL; node = node->parent) { + if ((node->flags & MAILBOX_MATCHED) == 0) + node->flags |= MAILBOX_NONEXISTENT; + } +} + +static void +mailbox_list_iter_update_real(struct mailbox_list_iter_update_context *ctx, + const char *name) +{ + struct mail_namespace *ns = ctx->iter_ctx->list->ns; + struct mailbox_node *node; + enum mailbox_info_flags create_flags, always_flags; + enum imap_match_result match; + const char *p; + bool created, add_matched; + + create_flags = MAILBOX_NOCHILDREN; + always_flags = ctx->leaf_flags; + add_matched = TRUE; + + for (;;) { + created = FALSE; + match = imap_match(ctx->glob, name); + if (match == IMAP_MATCH_YES) { + node = ctx->update_only ? + mailbox_tree_lookup(ctx->tree_ctx, name) : + mailbox_tree_get(ctx->tree_ctx, name, &created); + if (created) { + node->flags = create_flags; + if (create_flags != 0) + node_fix_parents(node); + } + if (node != NULL) { + if (!ctx->update_only && add_matched) + node->flags |= MAILBOX_MATCHED; + node->flags |= always_flags; + } + /* We don't want to show the parent mailboxes unless + something else matches them, but if they are matched + we want to show them having child subscriptions */ + add_matched = FALSE; + } else { + if ((match & IMAP_MATCH_PARENT) == 0) + break; + /* We've a (possibly) non-subscribed parent mailbox + which has a subscribed child mailbox. Make sure we + return the parent mailbox. */ + } + + if (!ctx->match_parents) + break; + + /* see if parent matches */ + p = strrchr(name, mail_namespace_get_sep(ns)); + if (p == NULL) + break; + + name = t_strdup_until(name, p); + create_flags |= MAILBOX_NONEXISTENT; + create_flags &= ~MAILBOX_NOCHILDREN; + always_flags = MAILBOX_CHILDREN | ctx->parent_flags; + } +} + +void mailbox_list_iter_update(struct mailbox_list_iter_update_context *ctx, + const char *name) +{ + T_BEGIN { + mailbox_list_iter_update_real(ctx, name); + } T_END; +}
--- a/src/lib-storage/mailbox-list.c Fri Dec 02 13:12:16 2011 +0200 +++ b/src/lib-storage/mailbox-list.c Fri Dec 02 14:23:47 2011 +0200 @@ -8,19 +8,13 @@ #include "sha1.h" #include "hash.h" #include "home-expand.h" -#include "close-keep-errno.h" -#include "eacces-error.h" -#include "read-full.h" -#include "write-full.h" -#include "safe-mkstemp.h" -#include "unlink-directory.h" #include "unichar.h" #include "settings-parser.h" -#include "imap-match.h" #include "imap-utf7.h" #include "mailbox-log.h" #include "mailbox-tree.h" -#include "mail-storage-private.h" +#include "mail-storage.h" +#include "mail-storage-hooks.h" #include "mailbox-list-private.h" #include <time.h> @@ -37,15 +31,6 @@ #define MAILBOX_MAX_HIERARCHY_LEVELS 20 #define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 200 -struct ns_list_iterate_context { - struct mailbox_list_iterate_context ctx; - struct mailbox_list_iterate_context *backend_ctx; - struct mail_namespace *namespaces; - pool_t pool; - const char **patterns, **patterns_ns_match; - enum namespace_type type_mask; -}; - struct mailbox_list_module_register mailbox_list_module_register = { 0 }; static ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *); @@ -971,309 +956,6 @@ return pattern; } -struct mailbox_list_iterate_context * -mailbox_list_iter_init(struct mailbox_list *list, const char *pattern, - enum mailbox_list_iter_flags flags) -{ - const char *patterns[2]; - - patterns[0] = pattern; - patterns[1] = NULL; - return mailbox_list_iter_init_multiple(list, patterns, flags); -} - -static int mailbox_list_subscriptions_refresh(struct mailbox_list *list) -{ - struct mail_namespace *ns = list->ns; - - if ((ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0) { - /* no subscriptions in this namespace. find where they are. */ - ns = mail_namespace_find_subscribable(ns->user->namespaces, - ns->prefix); - if (ns == NULL) { - /* no subscriptions */ - return 0; - } - } - return ns->list->v.subscriptions_refresh(ns->list, list); -} - -struct mailbox_list_iterate_context * -mailbox_list_iter_init_multiple(struct mailbox_list *list, - const char *const *patterns, - enum mailbox_list_iter_flags flags) -{ - struct mailbox_list_iterate_context *ctx; - int ret = 0; - - i_assert(*patterns != NULL); - - if ((flags & (MAILBOX_LIST_ITER_SELECT_SUBSCRIBED | - MAILBOX_LIST_ITER_RETURN_SUBSCRIBED)) != 0) - ret = mailbox_list_subscriptions_refresh(list); - - ctx = list->v.iter_init(list, patterns, flags); - if (ret < 0) - ctx->failed = TRUE; - return ctx; -} - -static bool -ns_match_simple(struct ns_list_iterate_context *ctx, struct mail_namespace *ns) -{ - if ((ctx->type_mask & ns->type) == 0) - return FALSE; - - if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SKIP_ALIASES) != 0) { - if (ns->alias_for != NULL) - return FALSE; - } - return TRUE; -} - -static bool -ns_match_inbox(struct mail_namespace *ns, const char *pattern) -{ - struct imap_match_glob *glob; - - if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0) - return FALSE; - - glob = imap_match_init(pool_datastack_create(), pattern, - TRUE, mail_namespace_get_sep(ns)); - return imap_match(glob, "INBOX") == IMAP_MATCH_YES; -} - -static bool -ns_match_next(struct ns_list_iterate_context *ctx, struct mail_namespace *ns, - const char *pattern) -{ - struct imap_match_glob *glob; - enum imap_match_result result; - const char *prefix_without_sep; - unsigned int len; - - len = ns->prefix_len; - if (len > 0 && ns->prefix[len-1] == mail_namespace_get_sep(ns)) - len--; - - if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX | - NAMESPACE_FLAG_LIST_CHILDREN)) == 0) { - /* non-listable namespace matches only with exact prefix */ - if (strncmp(ns->prefix, pattern, ns->prefix_len) != 0) - return FALSE; - } - - prefix_without_sep = t_strndup(ns->prefix, len); - if (*prefix_without_sep == '\0') - result = IMAP_MATCH_CHILDREN; - else { - glob = imap_match_init(pool_datastack_create(), pattern, - TRUE, mail_namespace_get_sep(ns)); - result = imap_match(glob, prefix_without_sep); - } - - if ((ctx->ctx.flags & MAILBOX_LIST_ITER_STAR_WITHIN_NS) == 0) { - switch (result) { - case IMAP_MATCH_YES: - case IMAP_MATCH_CHILDREN: - return TRUE; - case IMAP_MATCH_NO: - case IMAP_MATCH_PARENT: - break; - } - return FALSE; - } - - switch (result) { - case IMAP_MATCH_YES: - /* allow matching prefix only when it's done without - wildcards */ - if (strcmp(prefix_without_sep, pattern) == 0) - return TRUE; - break; - case IMAP_MATCH_CHILDREN: { - /* allow this only if there isn't another namespace - with longer prefix that matches this pattern - (namespaces are sorted by prefix length) */ - struct mail_namespace *tmp; - - T_BEGIN { - for (tmp = ns->next; tmp != NULL; tmp = tmp->next) { - if (ns_match_simple(ctx, tmp) && - ns_match_next(ctx, tmp, pattern)) - break; - } - } T_END; - if (tmp == NULL) - return TRUE; - break; - } - case IMAP_MATCH_NO: - case IMAP_MATCH_PARENT: - break; - } - return FALSE; -} - -static bool -ns_match(struct ns_list_iterate_context *ctx, struct mail_namespace *ns) -{ - unsigned int i; - - if (!ns_match_simple(ctx, ns)) - return FALSE; - - /* filter out namespaces whose prefix doesn't match. this same code - handles both with and without STAR_WITHIN_NS, so the "without" case - is slower than necessary, but this shouldn't matter much */ - T_BEGIN { - for (i = 0; ctx->patterns_ns_match[i] != NULL; i++) { - if (ns_match_inbox(ns, ctx->patterns_ns_match[i])) - break; - if (ns_match_next(ctx, ns, ctx->patterns_ns_match[i])) - break; - } - } T_END; - - return ctx->patterns_ns_match[i] != NULL; -} - -static struct mail_namespace * -ns_next(struct ns_list_iterate_context *ctx, struct mail_namespace *ns) -{ - for (; ns != NULL; ns = ns->next) { - if (ns_match(ctx, ns)) - break; - } - return ns; -} - -static const struct mailbox_info * -mailbox_list_ns_iter_next(struct mailbox_list_iterate_context *_ctx) -{ - struct ns_list_iterate_context *ctx = - (struct ns_list_iterate_context *)_ctx; - const struct mailbox_info *info; - - info = ctx->backend_ctx == NULL ? NULL : - mailbox_list_iter_next(ctx->backend_ctx); - if (info == NULL && ctx->namespaces != NULL) { - /* go to the next namespace */ - if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0) - _ctx->failed = TRUE; - ctx->ctx.list->ns = ctx->namespaces; - ctx->backend_ctx = - mailbox_list_iter_init_multiple(ctx->namespaces->list, - ctx->patterns, - _ctx->flags); - ctx->namespaces = ns_next(ctx, ctx->namespaces->next); - return mailbox_list_ns_iter_next(_ctx); - } - return info; -} - -static int -mailbox_list_ns_iter_deinit(struct mailbox_list_iterate_context *_ctx) -{ - struct ns_list_iterate_context *ctx = - (struct ns_list_iterate_context *)_ctx; - int ret; - - if (ctx->backend_ctx != NULL) { - if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0) - _ctx->failed = TRUE; - } - ret = _ctx->failed ? -1 : 0; - pool_unref(&ctx->pool); - return ret; -} - -static const char ** -dup_patterns_without_stars(pool_t pool, const char *const *patterns, - unsigned int count) -{ - const char **dup; - unsigned int i; - - dup = p_new(pool, const char *, count + 1); - for (i = 0; i < count; i++) { - char *p = p_strdup(pool, patterns[i]); - dup[i] = p; - - for (; *p != '\0'; p++) { - if (*p == '*') - *p = '%'; - } - } - return dup; -} - -struct mailbox_list_iterate_context * -mailbox_list_iter_init_namespaces(struct mail_namespace *namespaces, - const char *const *patterns, - enum namespace_type type_mask, - enum mailbox_list_iter_flags flags) -{ - struct ns_list_iterate_context *ctx; - unsigned int i, count; - pool_t pool; - - i_assert(namespaces != NULL); - - pool = pool_alloconly_create("mailbox list namespaces", 1024); - ctx = p_new(pool, struct ns_list_iterate_context, 1); - ctx->pool = pool; - ctx->type_mask = type_mask; - ctx->ctx.flags = flags; - ctx->ctx.list = p_new(pool, struct mailbox_list, 1); - ctx->ctx.list->v.iter_next = mailbox_list_ns_iter_next; - ctx->ctx.list->v.iter_deinit = mailbox_list_ns_iter_deinit; - - count = str_array_length(patterns); - ctx->patterns = p_new(pool, const char *, count + 1); - for (i = 0; i < count; i++) - ctx->patterns[i] = p_strdup(pool, patterns[i]); - - if ((flags & MAILBOX_LIST_ITER_STAR_WITHIN_NS) != 0) { - /* create copies of patterns with '*' wildcard changed to '%' */ - ctx->patterns_ns_match = - dup_patterns_without_stars(pool, ctx->patterns, count); - } else { - ctx->patterns_ns_match = ctx->patterns; - } - - namespaces = ns_next(ctx, namespaces); - ctx->ctx.list->ns = namespaces; - if (namespaces != NULL) { - ctx->backend_ctx = - mailbox_list_iter_init_multiple(namespaces->list, - patterns, flags); - ctx->namespaces = ns_next(ctx, namespaces->next); - } - return &ctx->ctx; -} - -const struct mailbox_info * -mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx) -{ - const struct mailbox_info *info; - - info = ctx->list->v.iter_next(ctx); - if (info != NULL) - ctx->list->ns->flags |= NAMESPACE_FLAG_USABLE; - return info; -} - -int mailbox_list_iter_deinit(struct mailbox_list_iterate_context **_ctx) -{ - struct mailbox_list_iterate_context *ctx = *_ctx; - - *_ctx = NULL; - - return ctx->list->v.iter_deinit(ctx); -} - int mailbox_has_children(struct mailbox_list *list, const char *name) { struct mailbox_list_iterate_context *iter; @@ -1508,84 +1190,6 @@ list->changelog_timestamp = stamp; } -static void node_fix_parents(struct mailbox_node *node) -{ - /* If we happened to create any of the parents, we need to mark them - nonexistent. */ - node = node->parent; - for (; node != NULL; node = node->parent) { - if ((node->flags & MAILBOX_MATCHED) == 0) - node->flags |= MAILBOX_NONEXISTENT; - } -} - -static void -mailbox_list_iter_update_real(struct mailbox_list_iter_update_context *ctx, - const char *name) -{ - struct mail_namespace *ns = ctx->iter_ctx->list->ns; - struct mailbox_node *node; - enum mailbox_info_flags create_flags, always_flags; - enum imap_match_result match; - const char *p; - bool created, add_matched; - - create_flags = MAILBOX_NOCHILDREN; - always_flags = ctx->leaf_flags; - add_matched = TRUE; - - for (;;) { - created = FALSE; - match = imap_match(ctx->glob, name); - if (match == IMAP_MATCH_YES) { - node = ctx->update_only ? - mailbox_tree_lookup(ctx->tree_ctx, name) : - mailbox_tree_get(ctx->tree_ctx, name, &created); - if (created) { - node->flags = create_flags; - if (create_flags != 0) - node_fix_parents(node); - } - if (node != NULL) { - if (!ctx->update_only && add_matched) - node->flags |= MAILBOX_MATCHED; - node->flags |= always_flags; - } - /* We don't want to show the parent mailboxes unless - something else matches them, but if they are matched - we want to show them having child subscriptions */ - add_matched = FALSE; - } else { - if ((match & IMAP_MATCH_PARENT) == 0) - break; - /* We've a (possibly) non-subscribed parent mailbox - which has a subscribed child mailbox. Make sure we - return the parent mailbox. */ - } - - if (!ctx->match_parents) - break; - - /* see if parent matches */ - p = strrchr(name, mail_namespace_get_sep(ns)); - if (p == NULL) - break; - - name = t_strdup_until(name, p); - create_flags |= MAILBOX_NONEXISTENT; - create_flags &= ~MAILBOX_NOCHILDREN; - always_flags = MAILBOX_CHILDREN | ctx->parent_flags; - } -} - -void mailbox_list_iter_update(struct mailbox_list_iter_update_context *ctx, - const char *name) -{ - T_BEGIN { - mailbox_list_iter_update_real(ctx, name); - } T_END; -} - bool mailbox_list_name_is_too_large(const char *name, char sep) { unsigned int levels = 1, level_len = 0;