mailbox-list-index-iter.c revision d186a2391d98a3efa3fe1078879ef2798e169c29
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce/* Copyright (c) 2006-2017 Dovecot authors, see the included COPYING file */
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce#include "lib.h"
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce#include "str.h"
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce#include "imap-match.h"
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce#include "mail-storage.h"
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce#include "mailbox-list-subscriptions.h"
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce#include "mailbox-list-index.h"
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorcestatic bool iter_use_index(struct mailbox_list *list,
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce enum mailbox_list_iter_flags flags)
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce{
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list);
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce /* for now we don't use indexes when listing subscriptions,
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce because it needs to list also the nonexistent subscribed
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce mailboxes, which don't exist in the index. */
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce return FALSE;
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce }
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce if ((flags & MAILBOX_LIST_ITER_RAW_LIST) != 0 &&
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce ilist->has_backing_store) {
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce /* no indexing wanted with raw lists */
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce return FALSE;
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce }
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce if (mailbox_list_index_refresh(list) < 0 &&
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce ilist->has_backing_store) {
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce /* refresh failed */
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce return FALSE;
ab967283b710dfa05d11ee5b30c7ac916486ceecSimo Sorce }
c6872e79e8496fd075e20aec0343ade99cca725cSimo Sorce return TRUE;
c6872e79e8496fd075e20aec0343ade99cca725cSimo Sorce}
c6872e79e8496fd075e20aec0343ade99cca725cSimo Sorce
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozekstruct mailbox_list_iterate_context *
22a21e910fd216ec1468fe769dcc29f1621a52a4Ondrej Kosmailbox_list_index_iter_init(struct mailbox_list *list,
ab967283b710dfa05d11ee5b30c7ac916486ceecSimo Sorce const char *const *patterns,
ab967283b710dfa05d11ee5b30c7ac916486ceecSimo Sorce enum mailbox_list_iter_flags flags)
ab967283b710dfa05d11ee5b30c7ac916486ceecSimo Sorce{
c6872e79e8496fd075e20aec0343ade99cca725cSimo Sorce struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list);
233a3c6c48972b177e60d6ef4cecfacd3cf31659Simo Sorce struct mailbox_list_index_iterate_context *ctx;
c6872e79e8496fd075e20aec0343ade99cca725cSimo Sorce pool_t pool;
c6872e79e8496fd075e20aec0343ade99cca725cSimo Sorce char ns_sep = mail_namespace_get_sep(list->ns);
233a3c6c48972b177e60d6ef4cecfacd3cf31659Simo Sorce
233a3c6c48972b177e60d6ef4cecfacd3cf31659Simo Sorce pool = pool_alloconly_create("mailbox list index iter", 2048);
7c69221077c780e62f6c536e78675f2dc1c131bcMichal Zidek ctx = p_new(pool, struct mailbox_list_index_iterate_context, 1);
7c69221077c780e62f6c536e78675f2dc1c131bcMichal Zidek ctx->ctx.pool = pool;
7c69221077c780e62f6c536e78675f2dc1c131bcMichal Zidek ctx->ctx.list = list;
aa7202c8ae677becd6c91d6a27a607fe0f3995eePavel Březina ctx->ctx.flags = flags;
f9961e5f82e0ef474d6492371bfdf9e74e208a99Pavel Březina ctx->ctx.glob = imap_match_init_multiple(pool, patterns, TRUE, ns_sep);
f9961e5f82e0ef474d6492371bfdf9e74e208a99Pavel Březina array_create(&ctx->ctx.module_contexts, pool, sizeof(void *), 5);
e5f455afbc2d149527bfd08f4e89903a3a8da17aPavel Březina ctx->info_pool = pool_alloconly_create("mailbox list index iter info", 128);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (!iter_use_index(list, flags)) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* no indexing */
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek ctx->backend_ctx = ilist->module_ctx.super.
dcc6877aa2e2dd63a9dc9c411a9c58feaeb36b9aStephen Gallagher iter_init(list, patterns, flags);
bc30ce9b7d588a17e58012e699986f0d6898b791Pavel Březina mailbox_list_iter_init_autocreate(ctx->backend_ctx);
b5ee224324b0158641d9b110f81d2bc6eddddc13Pavel Reichl } else {
2a96981a0ac781d01e5bba473409ed2bdf4cd4e0Jakub Hrozek /* listing mailboxes from index */
e81deec535d11912b87954c81a1edd768c1386c9Jakub Hrozek ctx->info.ns = list->ns;
4dd38025efda88f123eac672f87d3cda12f050c8Jakub Hrozek ctx->path = str_new(pool, 128);
4dd38025efda88f123eac672f87d3cda12f050c8Jakub Hrozek ctx->next_node = ilist->mailbox_tree;
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek ctx->mailbox_pool = ilist->mailbox_pool;
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek pool_ref(ctx->mailbox_pool);
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley }
1319e71fd1680ca4864afe0b1aca2b8c8e4a1ee4Stef Walter return &ctx->ctx;
0c1d65998907930678da2d091789446f2c344d5dJakub Hrozek}
a2ea3f5d9ef9f17efbb61e942c2bc6cff7d1ebf2Jakub Hrozek
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozekstatic void
8394eddba54b5d3e3fda868145e3751247bdbdb2Michal Zidekmailbox_list_index_update_info(struct mailbox_list_index_iterate_context *ctx)
5a5c5cdeb92f4012fc75fd717bfea06598f68f12Pavel Reichl{
804df4040eb142f82a44c019c7a55b5ce524583cMichal Zidek struct mailbox_list_index_node *node = ctx->next_node;
7650ded4ffa87fcf7ce5adf00920fecf89cffcf5Michal Zidek struct mailbox *box;
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce p_clear(ctx->info_pool);
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce str_truncate(ctx->path, ctx->parent_len);
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce /* the root directory may have an empty name. in that case we'll still
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce want to insert the separator, so check for non-NULL parent rather
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce than non-empty path. */
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce if (node->parent != NULL) {
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce str_append_c(ctx->path,
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce mailbox_list_get_hierarchy_sep(ctx->ctx.list));
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce }
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce str_append(ctx->path, node->name);
ctx->info.vname = mailbox_list_get_vname(ctx->ctx.list, str_c(ctx->path));
ctx->info.vname = p_strdup(ctx->info_pool, ctx->info.vname);
ctx->info.flags = 0;
if ((node->flags & MAILBOX_LIST_INDEX_FLAG_NONEXISTENT) != 0)
ctx->info.flags |= MAILBOX_NONEXISTENT;
else if ((node->flags & MAILBOX_LIST_INDEX_FLAG_NOSELECT) != 0)
ctx->info.flags |= MAILBOX_NOSELECT;
if ((node->flags & MAILBOX_LIST_INDEX_FLAG_NOINFERIORS) != 0)
ctx->info.flags |= MAILBOX_NOINFERIORS;
ctx->info.flags |= node->children != NULL ?
MAILBOX_CHILDREN : MAILBOX_NOCHILDREN;
if ((ctx->ctx.flags & (MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
MAILBOX_LIST_ITER_RETURN_SUBSCRIBED)) != 0) {
mailbox_list_set_subscription_flags(ctx->ctx.list,
ctx->info.vname,
&ctx->info.flags);
}
if ((ctx->ctx.flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0) {
box = mailbox_alloc(ctx->ctx.list, ctx->info.vname, 0);
mailbox_list_index_status_set_info_flags(box, node->uid,
&ctx->info.flags);
mailbox_free(&box);
}
}
static void
mailbox_list_index_update_next(struct mailbox_list_index_iterate_context *ctx,
bool follow_children)
{
struct mailbox_list_index_node *node = ctx->next_node;
if (node->children != NULL && follow_children) {
ctx->parent_len = str_len(ctx->path);
ctx->next_node = node->children;
} else {
while (node->next == NULL) {
node = node->parent;
if (node != NULL) {
ctx->parent_len -= strlen(node->name);
if (node->parent != NULL)
ctx->parent_len--;
}
if (node == NULL) {
/* last one */
ctx->next_node = NULL;
return;
}
}
ctx->next_node = node->next;
}
}
static bool
iter_subscriptions_ok(struct mailbox_list_index_iterate_context *ctx)
{
if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0)
return TRUE;
if ((ctx->info.flags & MAILBOX_SUBSCRIBED) != 0)
return TRUE;
if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH) != 0 &&
(ctx->info.flags & MAILBOX_CHILD_SUBSCRIBED) != 0)
return TRUE;
return FALSE;
}
const struct mailbox_info *
mailbox_list_index_iter_next(struct mailbox_list_iterate_context *_ctx)
{
struct mailbox_list_index_iterate_context *ctx =
(struct mailbox_list_index_iterate_context *)_ctx;
struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(_ctx->list);
bool follow_children;
enum imap_match_result match;
if (ctx->backend_ctx != NULL) {
/* index isn't being used */
return mailbox_list_iter_autocreate_filter(ctx->backend_ctx,
ilist->module_ctx.super.iter_next(ctx->backend_ctx));
}
/* listing mailboxes from index */
while (ctx->next_node != NULL) {
mailbox_list_index_update_info(ctx);
match = imap_match(_ctx->glob, ctx->info.vname);
follow_children = (match & (IMAP_MATCH_YES |
IMAP_MATCH_CHILDREN)) != 0;
if (match == IMAP_MATCH_YES && iter_subscriptions_ok(ctx)) {
mailbox_list_index_update_next(ctx, TRUE);
return &ctx->info;
} else if ((_ctx->flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0 &&
(ctx->info.flags & MAILBOX_CHILD_SUBSCRIBED) == 0) {
/* listing only subscriptions, but there are no
subscribed children. */
follow_children = FALSE;
}
mailbox_list_index_update_next(ctx, follow_children);
}
return mailbox_list_iter_default_next(_ctx);
}
int mailbox_list_index_iter_deinit(struct mailbox_list_iterate_context *_ctx)
{
struct mailbox_list_index_iterate_context *ctx =
(struct mailbox_list_index_iterate_context *)_ctx;
struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(_ctx->list);
int ret = ctx->failed ? -1 : 0;
if (ctx->backend_ctx != NULL)
ret = ilist->module_ctx.super.iter_deinit(ctx->backend_ctx);
else
pool_unref(&ctx->mailbox_pool);
pool_unref(&ctx->info_pool);
pool_unref(&_ctx->pool);
return ret;
}