changeset 22110:786b4dcee7e5

lib-storage: Don't list duplicate autocreated mailboxes' parents
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 29 May 2017 15:30:36 +0300
parents 7e438ab023c1
children 973a978ed497
files src/lib-storage/list/mailbox-list-iter-private.h src/lib-storage/list/mailbox-list-iter.c
diffstat 2 files changed, 32 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/list/mailbox-list-iter-private.h	Mon May 29 13:53:17 2017 +0300
+++ b/src/lib-storage/list/mailbox-list-iter-private.h	Mon May 29 15:30:36 2017 +0300
@@ -17,6 +17,7 @@
 	ARRAY(struct autocreate_box) boxes;
 	ARRAY_TYPE(mailbox_settings) box_sets;
 	ARRAY_TYPE(mailbox_settings) all_ns_box_sets;
+	HASH_TABLE(char *, char *) duplicate_vnames;
 	bool listing_autoboxes:1;
 };
 
--- a/src/lib-storage/list/mailbox-list-iter.c	Mon May 29 13:53:17 2017 +0300
+++ b/src/lib-storage/list/mailbox-list-iter.c	Mon May 29 15:30:36 2017 +0300
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "array.h"
+#include "hash.h"
 #include "imap-match.h"
 #include "mail-storage.h"
 #include "mailbox-tree.h"
@@ -114,6 +115,8 @@
 
 	actx = p_new(ctx->pool, struct mailbox_list_autocreate_iterate_context, 1);
 	ctx->autocreate_ctx = actx;
+	hash_table_create(&actx->duplicate_vnames, ctx->pool, 0,
+			  str_hash, strcmp);
 
 	/* build the list of mailboxes we need to consider as existing */
 	p_array_init(&actx->boxes, ctx->pool, 16);
@@ -817,12 +820,25 @@
 	match = autocreate_box_match(&actx->box_sets, ctx->list->ns,
 				     info->vname, FALSE, &idx);
 
-	if (!actx->listing_autoboxes &&
-	    (match & AUTOCREATE_MATCH_RESULT_YES) != 0) {
-		/* we have an exact match in the list.
-		   don't list it at the end. */
-		array_delete(&actx->boxes, idx, 1);
-		array_delete(&actx->box_sets, idx, 1);
+	if (!actx->listing_autoboxes) {
+		if ((match & AUTOCREATE_MATCH_RESULT_YES) != 0) {
+			/* we have an exact match in the list.
+			   don't list it at the end. */
+			array_delete(&actx->boxes, idx, 1);
+			array_delete(&actx->box_sets, idx, 1);
+		}
+		if ((match & AUTOCREATE_MATCH_RESULT_CHILDREN) != 0 &&
+		    hash_table_lookup(actx->duplicate_vnames, info->vname) == NULL) {
+			/* Prevent autocreate-iteration from adding this
+			   mailbox as a duplicate. For example we're listing %
+			   and we're here because "foo" was found. However,
+			   there's also "foo/bar" with auto=create. We're
+			   telling here to the autocreate iteration code that
+			   "foo" was already found and it doesn't need to add
+			   it again. */
+			char *vname = p_strdup(ctx->pool, info->vname);
+			hash_table_insert(actx->duplicate_vnames, vname, vname);
+		}
 	}
 
 	if ((match & AUTOCREATE_MATCH_RESULT_CHILDREN) != 0) {
@@ -918,6 +934,7 @@
 		enum mailbox_info_flags old_flags = actx->new_info.flags;
 		char sep = mail_namespace_get_sep(ctx->list->ns);
 		const char *p;
+		char *vname;
 
 		/* e.g. autocreate=foo/bar and we're listing % */
 		actx->new_info.flags = MAILBOX_NONEXISTENT |
@@ -932,12 +949,16 @@
 		do {
 			p = strrchr(actx->new_info.vname, sep);
 			i_assert(p != NULL);
-			actx->new_info.vname =
+			actx->new_info.vname = vname =
 				p_strdup_until(ctx->pool,
 					       actx->new_info.vname, p);
 			match = imap_match(ctx->glob, actx->new_info.vname);
 		} while (match != IMAP_MATCH_YES);
-		return TRUE;
+
+		if (hash_table_lookup(actx->duplicate_vnames, vname) == NULL) {
+			hash_table_insert(actx->duplicate_vnames, vname, vname);
+			return TRUE;
+		}
 	}
 	return FALSE;
 }
@@ -1030,6 +1051,8 @@
 
 	if (ctx == &mailbox_list_iter_failed)
 		return -1;
+	if (ctx->autocreate_ctx != NULL)
+		hash_table_destroy(&ctx->autocreate_ctx->duplicate_vnames);
 	return ctx->list->v.iter_deinit(ctx);
 }