--- /dev/null
+/* 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;
+}
#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>
#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 *);
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;
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;