changeset 22387:6cbca06276e6

lib-storage: Hide and rmdir \NoSelect leaf mailboxes with NO-NOSELECT If the leaf is successfully rmdir()ed, rmdir() also its parents. This doesn't work perfectly with if there are multiple levels of \NoSelect mailboxes. For example with "a/b/c" the listing will already have returned "a" and "a/b" before it reaches the "a/b/c" code, which will rmdir all of them, but it's a bit too late at that point. It's too much work to fix though, and the situation will be fixed on the next list anyway.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Tue, 25 Jul 2017 20:53:18 +0300
parents 1534de106851
children df373becc66c
files src/lib-storage/list/mailbox-list-delete.c src/lib-storage/list/mailbox-list-delete.h src/lib-storage/list/mailbox-list-fs-iter.c src/lib-storage/list/mailbox-list-index-iter.c src/lib-storage/list/mailbox-list-iter-private.h
diffstat 5 files changed, 58 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/list/mailbox-list-delete.c	Tue Jul 25 16:10:51 2017 +0300
+++ b/src/lib-storage/list/mailbox-list-delete.c	Tue Jul 25 20:53:18 2017 +0300
@@ -320,6 +320,24 @@
 	}
 }
 
+void mailbox_list_delete_mailbox_until_root(struct mailbox_list *list,
+					    const char *storage_name)
+{
+	enum mailbox_list_path_type types[] = {
+		MAILBOX_LIST_PATH_TYPE_DIR,
+		MAILBOX_LIST_PATH_TYPE_ALT_DIR,
+		MAILBOX_LIST_PATH_TYPE_CONTROL,
+		MAILBOX_LIST_PATH_TYPE_INDEX,
+		MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE,
+	};
+	const char *path;
+
+	for (unsigned int i = 0; i < N_ELEMENTS(types); i++) {
+		if (mailbox_list_get_path(list, storage_name, types[i], &path) > 0)
+			mailbox_list_delete_until_root(list, path, types[i]);
+	}
+}
+
 static int mailbox_list_try_delete(struct mailbox_list *list, const char *name,
 				   enum mailbox_list_path_type type)
 {
@@ -463,4 +481,3 @@
 	}
 	return -1;
 }
-
--- a/src/lib-storage/list/mailbox-list-delete.h	Tue Jul 25 16:10:51 2017 +0300
+++ b/src/lib-storage/list/mailbox-list-delete.h	Tue Jul 25 20:53:18 2017 +0300
@@ -65,6 +65,9 @@
    The root isn't rmdir()ed. */
 void mailbox_list_delete_until_root(struct mailbox_list *list, const char *path,
 				    enum mailbox_list_path_type type);
+/* Call mailbox_list_delete_until_root() for all the paths of the mailbox. */
+void mailbox_list_delete_mailbox_until_root(struct mailbox_list *list,
+					    const char *storage_name);
 /* Wrapper to unlink_directory(UNLINK_DIRECTORY_FLAG_RMDIR). If it fails due
    to ELOOP, try to unlink() the path instead. */
 int mailbox_list_delete_trash(const char *path);
--- a/src/lib-storage/list/mailbox-list-fs-iter.c	Tue Jul 25 16:10:51 2017 +0300
+++ b/src/lib-storage/list/mailbox-list-fs-iter.c	Tue Jul 25 20:53:18 2017 +0300
@@ -9,6 +9,7 @@
 #include "mail-storage.h"
 #include "mailbox-tree.h"
 #include "mailbox-list-subscriptions.h"
+#include "mailbox-list-iter-private.h"
 #include "mailbox-list-fs.h"
 
 #include <stdio.h>
@@ -741,6 +742,8 @@
 		   doesn't */
 		return 0;
 	}
+	if (mailbox_list_iter_try_delete_noselect(&ctx->ctx, &ctx->info, storage_name))
+		return 0;
 	return 1;
 }
 
--- a/src/lib-storage/list/mailbox-list-index-iter.c	Tue Jul 25 16:10:51 2017 +0300
+++ b/src/lib-storage/list/mailbox-list-index-iter.c	Tue Jul 25 20:53:18 2017 +0300
@@ -5,6 +5,7 @@
 #include "imap-match.h"
 #include "mail-storage.h"
 #include "mailbox-list-subscriptions.h"
+#include "mailbox-list-iter-private.h"
 #include "mailbox-list-index.h"
 
 static bool iter_use_index(struct mailbox_list *list,
@@ -174,8 +175,21 @@
 		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;
+			/* If this is a) \NoSelect leaf, b) not LAYOUT=index
+			   and c) NO-NOSELECT is set, try to rmdir the leaf
+			   directores from filesystem. (With LAYOUT=index the
+			   \NoSelect mailboxes aren't on the filesystem.) */
+			if (ilist->has_backing_store &&
+			    mailbox_list_iter_try_delete_noselect(_ctx, &ctx->info,
+								  str_c(ctx->path))) {
+				/* Deleted \NoSelect leaf. Refresh the index
+				   later on so it gets removed from the index
+				   as well. */
+				mailbox_list_index_refresh_later(_ctx->list);
+			} else {
+				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
--- a/src/lib-storage/list/mailbox-list-iter-private.h	Tue Jul 25 16:10:51 2017 +0300
+++ b/src/lib-storage/list/mailbox-list-iter-private.h	Tue Jul 25 20:53:18 2017 +0300
@@ -1,7 +1,9 @@
 #ifndef MAILBOX_LIST_ITER_PRIVATE_H
 #define MAILBOX_LIST_ITER_PRIVATE_H
 
+#include "mailbox-list-private.h"
 #include "mailbox-list-iter.h"
+#include "mailbox-list-delete.h"
 
 struct autocreate_box {
 	const char *name;
@@ -21,4 +23,20 @@
 	bool listing_autoboxes:1;
 };
 
+static inline bool
+mailbox_list_iter_try_delete_noselect(struct mailbox_list_iterate_context *ctx,
+				      const struct mailbox_info *info,
+				      const char *storage_name)
+{
+	if ((info->flags & (MAILBOX_NOSELECT|MAILBOX_NOCHILDREN)) ==
+	    (MAILBOX_NOSELECT|MAILBOX_NOCHILDREN) &&
+	    ctx->list->set.no_noselect) {
+		/* Try to rmdir() all \NoSelect mailbox leafs and
+		   afterwards their parents. */
+		mailbox_list_delete_mailbox_until_root(ctx->list, storage_name);
+		return TRUE;
+	}
+	return FALSE;
+}
+
 #endif