# HG changeset patch # User Timo Sirainen # Date 1297483592 -7200 # Node ID 0af45e821da1d78fff88f9dd9e28dc66e405d3b6 # Parent 440a1a3660ba04b8ea853bfb54211d418f630fa2 imapc: Mailbox listing code works now perfectly. diff -r 440a1a3660ba -r 0af45e821da1 src/lib-storage/index/imapc/Makefile.am --- a/src/lib-storage/index/imapc/Makefile.am Sat Feb 12 06:05:40 2011 +0200 +++ b/src/lib-storage/index/imapc/Makefile.am Sat Feb 12 06:06:32 2011 +0200 @@ -10,6 +10,7 @@ -I$(top_srcdir)/src/lib-imap \ -I$(top_srcdir)/src/lib-index \ -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/lib-storage/list \ -I$(top_srcdir)/src/lib-storage/index libstorage_imapc_la_SOURCES = \ diff -r 440a1a3660ba -r 0af45e821da1 src/lib-storage/index/imapc/imapc-list.c --- a/src/lib-storage/index/imapc/imapc-list.c Sat Feb 12 06:05:40 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-list.c Sat Feb 12 06:06:32 2011 +0200 @@ -4,15 +4,16 @@ #include "imap-arg.h" #include "imap-match.h" #include "mailbox-tree.h" +#include "mailbox-list-subscriptions.h" #include "imapc-client.h" #include "imapc-storage.h" #include "imapc-list.h" struct imapc_mailbox_list_iterate_context { struct mailbox_list_iterate_context ctx; + struct mailbox_tree_context *tree; struct mailbox_tree_iterate_context *iter; struct mailbox_info info; - bool failed; }; extern struct mailbox_list imapc_mailbox_list; @@ -35,8 +36,8 @@ if (list->mailboxes != NULL) mailbox_tree_deinit(&list->mailboxes); - if (list->subscriptions != NULL) - mailbox_tree_deinit(&list->subscriptions); + if (list->tmp_subscriptions != NULL) + mailbox_tree_deinit(&list->tmp_subscriptions); pool_unref(&list->list.pool); } @@ -107,9 +108,11 @@ /* we can't handle NIL separator yet */ list->sep = sep == NULL ? '/' : sep[0]; - return; + if (list->mailboxes != NULL) + mailbox_tree_set_separator(list->mailboxes, list->sep); + } else { + (void)imapc_list_update_tree(list->mailboxes, args); } - (void)imapc_list_update_tree(list->mailboxes, args); } static void imapc_untagged_lsub(const struct imapc_untagged_reply *reply, @@ -123,7 +126,9 @@ /* we haven't asked for the separator yet */ return; } - node = imapc_list_update_tree(list->subscriptions, args); + node = imapc_list_update_tree(list->tmp_subscriptions != NULL ? + list->tmp_subscriptions : + list->list.subscriptions, args); if (node != NULL) node->flags |= MAILBOX_SUBSCRIBED; } @@ -136,32 +141,6 @@ imapc_untagged_lsub); } -static int imapc_list_refresh(struct imapc_mailbox_list *list, - enum mailbox_list_iter_flags flags) -{ - struct imapc_simple_context ctx; - - ctx.storage = list->storage; - if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) { - imapc_client_cmdf(list->storage->client, - imapc_list_simple_callback, &ctx, - "LIST \"\" *"); - if (list->mailboxes != NULL) - mailbox_tree_deinit(&list->mailboxes); - list->mailboxes = mailbox_tree_init(list->sep); - } else { - imapc_client_cmdf(list->storage->client, - imapc_list_simple_callback, &ctx, - "LSUB \"\" *"); - if (list->subscriptions != NULL) - mailbox_tree_deinit(&list->subscriptions); - list->subscriptions = mailbox_tree_init(list->sep); - } - - imapc_client_run(list->storage->client); - return ctx.ret; -} - static bool imapc_is_valid_pattern(struct mailbox_list *list ATTR_UNUSED, const char *pattern ATTR_UNUSED) @@ -227,14 +206,79 @@ return t_strconcat(ref, pattern, NULL); } +static int imapc_list_refresh(struct imapc_mailbox_list *list) +{ + struct imapc_simple_context ctx; + + if (list->refreshed_mailboxes) + return 0; + + if (list->sep == '\0') + (void)mailbox_list_get_hierarchy_sep(&list->list); + + ctx.storage = list->storage; + imapc_client_cmdf(list->storage->client, + imapc_list_simple_callback, &ctx, "LIST \"\" *"); + if (list->mailboxes != NULL) + mailbox_tree_deinit(&list->mailboxes); + list->mailboxes = mailbox_tree_init(list->sep); + + imapc_client_run(list->storage->client); + + if (ctx.ret == 0) + list->refreshed_mailboxes = TRUE; + return ctx.ret; +} + +static void +imapc_list_build_match_tree(struct imapc_mailbox_list_iterate_context *ctx) +{ + struct imapc_mailbox_list *list = + (struct imapc_mailbox_list *)ctx->ctx.list; + struct mailbox_list_iter_update_context update_ctx; + struct mailbox_tree_iterate_context *iter; + struct mailbox_node *node; + const char *name; + + memset(&update_ctx, 0, sizeof(update_ctx)); + update_ctx.iter_ctx = &ctx->ctx; + update_ctx.tree_ctx = ctx->tree; + update_ctx.glob = ctx->ctx.glob; + update_ctx.match_parents = TRUE; + + iter = mailbox_tree_iterate_init(list->mailboxes, NULL, 0); + while ((node = mailbox_tree_iterate_next(iter, &name)) != NULL) { + update_ctx.leaf_flags = node->flags; + mailbox_list_iter_update(&update_ctx, name); + } + mailbox_tree_iterate_deinit(&iter); +} + static struct mailbox_list_iterate_context * imapc_list_iter_init(struct mailbox_list *_list, const char *const *patterns, enum mailbox_list_iter_flags flags) { struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list; + struct mailbox_list_iterate_context *_ctx; struct imapc_mailbox_list_iterate_context *ctx; - struct mailbox_tree_context *tree; char sep; + int ret = 0; + + if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0 || + (flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0) + ret = imapc_list_refresh(list); + + list->iter_count++; + + if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) { + /* we're listing only subscriptions. just use the cached + subscriptions list. */ + _ctx = mailbox_list_subscriptions_iter_init(_list, patterns, + flags); + if (ret < 0) + _ctx->failed = TRUE; + return _ctx; + } sep = mailbox_list_get_hierarchy_sep(_list); @@ -246,13 +290,12 @@ array_create(&ctx->ctx.module_contexts, default_pool, sizeof(void *), 5); ctx->info.ns = _list->ns; - if (imapc_list_refresh(list, flags) < 0) - ctx->failed = TRUE; - else { - tree = (flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0 ? - list->subscriptions : list->mailboxes; - ctx->iter = mailbox_tree_iterate_init(tree, NULL, 0); - } + + ctx->tree = mailbox_tree_init(sep); + imapc_list_build_match_tree(ctx); + ctx->iter = mailbox_tree_iterate_init(ctx->tree, NULL, 0); + if (ret < 0) + ctx->ctx.failed = TRUE; return &ctx->ctx; } @@ -264,42 +307,80 @@ struct mailbox_node *node; const char *name; - if (ctx->failed) + if (_ctx->failed) return NULL; - while ((node = mailbox_tree_iterate_next(ctx->iter, &name)) != NULL) { - if (imap_match(ctx->ctx.glob, name) == IMAP_MATCH_YES) { - ctx->info.flags &= ~(MAILBOX_CHILDREN | - MAILBOX_NOCHILDREN); - if (node->children == NULL) - ctx->info.flags |= MAILBOX_NOCHILDREN; - else - ctx->info.flags |= MAILBOX_CHILDREN; - ctx->info.name = name; - return &ctx->info; - } - } - return NULL; + if ((_ctx->flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) + return mailbox_list_subscriptions_iter_next(_ctx); + + node = mailbox_tree_iterate_next(ctx->iter, &name); + if (node == NULL) + return NULL; + + ctx->info.name = name; + ctx->info.flags = node->flags; + return &ctx->info; } static int imapc_list_iter_deinit(struct mailbox_list_iterate_context *_ctx) { struct imapc_mailbox_list_iterate_context *ctx = (struct imapc_mailbox_list_iterate_context *)_ctx; - int ret = ctx->failed ? -1 : 0; + struct imapc_mailbox_list *list = + (struct imapc_mailbox_list *)_ctx->list; + int ret = _ctx->failed ? -1 : 0; + + i_assert(list->iter_count > 0); - if (ctx->iter != NULL) - mailbox_tree_iterate_deinit(&ctx->iter); - imap_match_deinit(&ctx->ctx.glob); - array_free(&ctx->ctx.module_contexts); + if (--list->iter_count == 0) { + list->refreshed_mailboxes = FALSE; + list->refreshed_subscriptions = FALSE; + } + + if ((_ctx->flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) + return mailbox_list_subscriptions_iter_deinit(_ctx); + + mailbox_tree_iterate_deinit(&ctx->iter); + mailbox_tree_deinit(&ctx->tree); + imap_match_deinit(&_ctx->glob); + array_free(&_ctx->module_contexts); i_free(ctx); return ret; } static int -imapc_list_subscriptions_refresh(struct mailbox_list *_src_list ATTR_UNUSED, - struct mailbox_list *_dest_list ATTR_UNUSED) +imapc_list_subscriptions_refresh(struct mailbox_list *_src_list, + struct mailbox_list *dest_list) { + struct imapc_mailbox_list *src_list = + (struct imapc_mailbox_list *)_src_list; + struct imapc_simple_context ctx; + + i_assert(src_list->tmp_subscriptions == NULL); + + if (src_list->refreshed_subscriptions) + return 0; + + if (src_list->sep == '\0') + (void)mailbox_list_get_hierarchy_sep(_src_list); + + src_list->tmp_subscriptions = mailbox_tree_init(src_list->sep); + + ctx.storage = src_list->storage; + imapc_client_cmdf(src_list->storage->client, + imapc_list_simple_callback, &ctx, + "LSUB \"\" *"); + imapc_client_run(src_list->storage->client); + + /* replace subscriptions tree in destination */ + mailbox_tree_set_separator(src_list->tmp_subscriptions, + mailbox_list_get_hierarchy_sep(dest_list)); + if (dest_list->subscriptions != NULL) + mailbox_tree_deinit(&dest_list->subscriptions); + dest_list->subscriptions = src_list->tmp_subscriptions; + src_list->tmp_subscriptions = NULL; + + src_list->refreshed_subscriptions = TRUE; return 0; } diff -r 440a1a3660ba -r 0af45e821da1 src/lib-storage/index/imapc/imapc-list.h --- a/src/lib-storage/index/imapc/imapc-list.h Sat Feb 12 06:05:40 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-list.h Sat Feb 12 06:06:32 2011 +0200 @@ -11,12 +11,16 @@ struct mailbox_list list; struct imapc_storage *storage; - struct mailbox_tree_context *mailboxes, *subscriptions; + struct mailbox_tree_context *mailboxes, *tmp_subscriptions; char sep; + unsigned int iter_count; + /* we've returned wrong separator. all mailbox list operations must fail from now on. */ unsigned int broken:1; + unsigned int refreshed_subscriptions:1; + unsigned int refreshed_mailboxes:1; }; void imapc_list_register_callbacks(struct imapc_mailbox_list *list);