summaryrefslogtreecommitdiffstats
path: root/src/doveadm/doveadm-mailbox-list-iter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/doveadm/doveadm-mailbox-list-iter.c')
-rw-r--r--src/doveadm/doveadm-mailbox-list-iter.c195
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;
+}