diff options
Diffstat (limited to 'src/doveadm/doveadm-mailbox-list-iter.c')
-rw-r--r-- | src/doveadm/doveadm-mailbox-list-iter.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/doveadm/doveadm-mailbox-list-iter.c b/src/doveadm/doveadm-mailbox-list-iter.c new file mode 100644 index 0000000..c77398c --- /dev/null +++ b/src/doveadm/doveadm-mailbox-list-iter.c @@ -0,0 +1,195 @@ +/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "str.h" +#include "mail-search.h" +#include "mail-namespace.h" +#include "mailbox-list.h" +#include "doveadm-mail.h" +#include "doveadm-mailbox-list-iter.h" + +struct doveadm_mailbox_list_iter { + struct mail_user *user; + struct doveadm_mail_cmd_context *ctx; + struct mail_search_args *search_args; + enum mailbox_list_iter_flags iter_flags; + + struct mailbox_list_iterate_context *iter; + + struct mailbox_info info; + ARRAY_TYPE(const_string) patterns; + unsigned int pattern_idx; + + bool only_selectable; +}; + +static bool +search_args_get_mailbox_patterns(const struct mail_search_arg *args, + ARRAY_TYPE(const_string) *patterns, + bool *have_guid, bool *have_wildcards) +{ + const struct mail_search_arg *subargs; + + for (; args != NULL; args = args->next) { + switch (args->type) { + case SEARCH_OR: + /* we don't currently try to optimize OR. */ + break; + case SEARCH_SUB: + case SEARCH_INTHREAD: + subargs = args->value.subargs; + for (; subargs != NULL; subargs = subargs->next) { + if (!search_args_get_mailbox_patterns(subargs, + patterns, have_guid, + have_wildcards)) + return FALSE; + } + break; + case SEARCH_MAILBOX_GLOB: + *have_wildcards = TRUE; + /* fall through */ + case SEARCH_MAILBOX: + if (args->match_not) { + array_clear(patterns); + return FALSE; + } + array_push_back(patterns, &args->value.str); + break; + case SEARCH_MAILBOX_GUID: + *have_guid = TRUE; + break; + default: + break; + } + } + return TRUE; +} + +static struct doveadm_mailbox_list_iter * +doveadm_mailbox_list_iter_init_nsmask(struct doveadm_mail_cmd_context *ctx, + struct mail_user *user, + struct mail_search_args *search_args, + enum mailbox_list_iter_flags iter_flags, + enum mail_namespace_type ns_mask) +{ + static const char *all_pattern = "*"; + struct doveadm_mailbox_list_iter *iter; + bool have_guid = FALSE, have_wildcards = FALSE; + + iter = i_new(struct doveadm_mailbox_list_iter, 1); + iter->ctx = ctx; + iter->search_args = search_args; + iter->user = user; + i_array_init(&iter->patterns, 16); + (void)search_args_get_mailbox_patterns(search_args->args, + &iter->patterns, + &have_guid, &have_wildcards); + + if (array_count(&iter->patterns) == 0) { + iter_flags |= MAILBOX_LIST_ITER_SKIP_ALIASES; + if (have_guid) { + ns_mask |= MAIL_NAMESPACE_TYPE_SHARED | + MAIL_NAMESPACE_TYPE_PUBLIC; + } + array_push_back(&iter->patterns, &all_pattern); + } else if (have_wildcards) { + iter_flags |= MAILBOX_LIST_ITER_STAR_WITHIN_NS; + ns_mask |= MAIL_NAMESPACE_TYPE_SHARED | + MAIL_NAMESPACE_TYPE_PUBLIC; + } else { + /* just return the listed mailboxes without actually + iterating through. this also allows accessing mailboxes + without lookup ACL right */ + return iter; + } + array_append_zero(&iter->patterns); + + iter->only_selectable = TRUE; + iter->iter_flags = iter_flags; + iter->iter = mailbox_list_iter_init_namespaces(user->namespaces, + array_front(&iter->patterns), + ns_mask, iter_flags); + return iter; +} + +struct doveadm_mailbox_list_iter * +doveadm_mailbox_list_iter_init(struct doveadm_mail_cmd_context *ctx, + struct mail_user *user, + struct mail_search_args *search_args, + enum mailbox_list_iter_flags iter_flags) +{ + enum mail_namespace_type ns_mask = MAIL_NAMESPACE_TYPE_PRIVATE; + + return doveadm_mailbox_list_iter_init_nsmask(ctx, user, search_args, + iter_flags, ns_mask); +} + +struct doveadm_mailbox_list_iter * +doveadm_mailbox_list_iter_full_init(struct doveadm_mail_cmd_context *ctx, + struct mail_user *user, + struct mail_search_args *search_args, + enum mailbox_list_iter_flags iter_flags) +{ + enum mail_namespace_type ns_mask = MAIL_NAMESPACE_TYPE_MASK_ALL; + struct doveadm_mailbox_list_iter *iter; + + iter = doveadm_mailbox_list_iter_init_nsmask(ctx, user, search_args, + iter_flags, ns_mask); + iter->only_selectable = FALSE; + return iter; +} + +int doveadm_mailbox_list_iter_deinit(struct doveadm_mailbox_list_iter **_iter) +{ + struct doveadm_mailbox_list_iter *iter = *_iter; + enum mail_error error; + int ret; + + *_iter = NULL; + + if (iter->iter == NULL) + ret = 0; + else if ((ret = mailbox_list_iter_deinit(&iter->iter)) < 0) { + i_error("Listing mailboxes failed: %s", + mailbox_list_get_last_internal_error(iter->user->namespaces->list, &error)); + doveadm_mail_failed_error(iter->ctx, error); + } + array_free(&iter->patterns); + i_free(iter); + return ret; +} + +const struct mailbox_info * +doveadm_mailbox_list_iter_next(struct doveadm_mailbox_list_iter *iter) +{ + const struct mailbox_info *info; + const char *const *patterns; + unsigned int count; + + while (iter->iter == NULL) { + patterns = array_get(&iter->patterns, &count); + if (iter->pattern_idx == count) + return NULL; + + iter->info.vname = patterns[iter->pattern_idx++]; + iter->info.ns = mail_namespace_find(iter->user->namespaces, + iter->info.vname); + return &iter->info; + } + + while ((info = mailbox_list_iter_next(iter->iter)) != NULL) { + char sep = mail_namespace_get_sep(info->ns); + + if ((info->flags & (MAILBOX_NOSELECT | + MAILBOX_NONEXISTENT)) != 0) { + if (iter->only_selectable) + continue; + } + + if (mail_search_args_match_mailbox(iter->search_args, + info->vname, sep)) + break; + } + return info; +} |