changeset 12666:0af45e821da1

imapc: Mailbox listing code works now perfectly.
author Timo Sirainen <tss@iki.fi>
date Sat, 12 Feb 2011 06:06:32 +0200
parents 440a1a3660ba
children ceab4f233bff
files src/lib-storage/index/imapc/Makefile.am src/lib-storage/index/imapc/imapc-list.c src/lib-storage/index/imapc/imapc-list.h
diffstat 3 files changed, 148 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- 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 = \
--- 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;
 }
 
--- 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);