changeset 22709:86939499f531

LAYOUT=fs: Fix listing prefix/INBOX Removed some confusing special case code that didn't seem to work very well. Implemented this now properly so that prefix/INBOX is listed as \NoSelect mailbox whenever it has children. It's not actually possible to differentiate between INBOX and prefix/INBOX in the storage for a inbox=yes namespace, because they both are converted into the same storage_name=INBOX.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Thu, 14 Dec 2017 01:36:50 +0200
parents fe21125a7ba8
children 3214091454e6
files src/lib-storage/list/mailbox-list-fs-iter.c
diffstat 1 files changed, 25 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/list/mailbox-list-fs-iter.c	Thu Dec 14 01:34:25 2017 +0200
+++ b/src/lib-storage/list/mailbox-list-fs-iter.c	Thu Dec 14 01:36:50 2017 +0200
@@ -51,7 +51,7 @@
 
 	unsigned int inbox_found:1;
 	unsigned int inbox_has_children:1;
-	unsigned int list_inbox_inbox:1;
+	unsigned int listed_prefix_inbox:1;
 };
 
 static int
@@ -181,6 +181,14 @@
 	}
 
 	match = imap_match(ctx->ctx.glob, vname);
+	if (strcmp(d->d_name, "INBOX") == 0 && strcmp(vname, "INBOX") == 0 &&
+	    ctx->ctx.list->ns->prefix_len > 0) {
+		/* The glob was matched only against "INBOX", but this
+		   directory may hold also prefix/INBOX. Just assume here
+		   that it matches and verify later whether it was needed
+		   or not. */
+		match = IMAP_MATCH_YES;
+	}
 
 	if ((dir->info_flags & (MAILBOX_CHILDREN | MAILBOX_NOCHILDREN |
 				MAILBOX_NOINFERIORS)) == 0 &&
@@ -559,11 +567,8 @@
 	return ret;
 }
 
-static void inbox_flags_set(struct fs_list_iterate_context *ctx,
-			    enum imap_match_result child_dir_match)
+static void inbox_flags_set(struct fs_list_iterate_context *ctx)
 {
-	struct mail_namespace *ns = ctx->ctx.list->ns;
-
 	/* INBOX is always selectable */
 	ctx->info.flags &= ~(MAILBOX_NOSELECT | MAILBOX_NONEXISTENT);
 
@@ -571,25 +576,6 @@
 		ctx->info.flags &= ~(MAILBOX_CHILDREN|MAILBOX_NOCHILDREN);
 		ctx->info.flags |= MAILBOX_NOINFERIORS;
 	}
-	if (*ns->prefix != '\0' &&
-	    (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
-		/* we're listing INBOX for a namespace with a prefix.
-		   if there are children for the INBOX, they're returned under
-		   the mailbox prefix, not under the INBOX itself. For example
-		   with INBOX = /var/inbox/%u/Maildir, root = ~/Maildir:
-		   ~/Maildir/INBOX/foo/ shows up as <prefix>/INBOX/foo and
-		   INBOX can't directly have any children. */
-		if (ns->prefix_len == 6 &&
-		    strncasecmp(ns->prefix, "INBOX", ns->prefix_len-1) == 0 &&
-		    (ctx->info.flags & MAILBOX_CHILDREN) != 0 &&
-		    (child_dir_match & IMAP_MATCH_CHILDREN) != 0) {
-			/* except, INBOX/ prefix is once again a special case.
-			   we're now listing both the namespace prefix and the
-			   INBOX. we're now doing a LIST INBOX/%, so we'll need
-			   to create a fake \NoSelect INBOX/INBOX */
-			ctx->list_inbox_inbox = TRUE;
-		}
-	}
 }
 
 static const char *
@@ -616,7 +602,7 @@
 	    (ctx->info.flags & MAILBOX_NONEXISTENT) != 0)
 		return FALSE;
 
-	inbox_flags_set(ctx, 0);
+	inbox_flags_set(ctx);
 	if (ctx->inbox_has_children)
 		ctx->info.flags |= MAILBOX_CHILDREN;
 	else {
@@ -660,7 +646,14 @@
 
 	match = imap_match(ctx->ctx.glob, ctx->info.vname);
 
-	child_dir_name = t_strdup_printf("%s%c", ctx->info.vname, ctx->sep);
+	if (strcmp(ctx->info.vname, "INBOX") == 0 &&
+	    ctx->ctx.list->ns->prefix_len > 0) {
+		/* INBOX's children are matched as prefix/INBOX */
+		child_dir_name = t_strdup_printf("%sINBOX", ns->prefix);
+	} else {
+		child_dir_name =
+			t_strdup_printf("%s%c", ctx->info.vname, ctx->sep);
+	}
 	child_dir_match = imap_match(ctx->ctx.glob, child_dir_name);
 	if (child_dir_match == IMAP_MATCH_YES)
 		child_dir_match |= IMAP_MATCH_CHILDREN;
@@ -711,7 +704,9 @@
 			}
 			return 0;
 		}
-		inbox_flags_set(ctx, child_dir_match);
+		if (subdir != NULL)
+			ctx->inbox_has_children = TRUE;
+		inbox_flags_set(ctx);
 		ctx->info.vname = "INBOX"; /* always return uppercased */
 		ctx->inbox_found = TRUE;
 	} else if (strcmp(storage_name, "INBOX") == 0 &&
@@ -777,12 +772,13 @@
 			fs_list_next_root(ctx);
 	}
 
-	if (ctx->list_inbox_inbox) {
+	if (ctx->inbox_has_children && ctx->ctx.list->ns->prefix_len > 0 &&
+	    !ctx->listed_prefix_inbox) {
 		ctx->info.flags = MAILBOX_CHILDREN | MAILBOX_NOSELECT;
 		ctx->info.vname =
 			p_strconcat(ctx->info_pool,
 				    ctx->ctx.list->ns->prefix, "INBOX", NULL);
-		ctx->list_inbox_inbox = FALSE;
+		ctx->listed_prefix_inbox = TRUE;
 		if (imap_match(ctx->ctx.glob, ctx->info.vname) == IMAP_MATCH_YES)
 			return 1;
 	}