dovecot-1.2: acl LIST: Mailboxes without LOOKUP right are now li...
dovecot at dovecot.org
dovecot at dovecot.org
Wed Nov 19 18:19:17 EET 2008
details: http://hg.dovecot.org/dovecot-1.2/rev/33dc554bd33f
changeset: 8445:33dc554bd33f
user: Timo Sirainen <tss at iki.fi>
date: Wed Nov 19 18:19:13 2008 +0200
description:
acl LIST: Mailboxes without LOOKUP right are now listed as non-existent if they have visible children.
diffstat:
1 file changed, 102 insertions(+), 40 deletions(-)
src/plugins/acl/acl-mailbox-list.c | 142 +++++++++++++++++++++++++-----------
diffs (234 lines):
diff -r e3c8fd174378 -r 33dc554bd33f src/plugins/acl/acl-mailbox-list.c
--- a/src/plugins/acl/acl-mailbox-list.c Wed Nov 19 17:11:18 2008 +0200
+++ b/src/plugins/acl/acl-mailbox-list.c Wed Nov 19 18:19:13 2008 +0200
@@ -29,6 +29,10 @@ struct acl_mailbox_list_iterate_context
struct mailbox_tree_context *lookup_boxes;
struct mailbox_info info;
+
+ struct imap_match_glob *glob;
+ char sep;
+ unsigned int simple_star_glob:1;
};
static MODULE_CONTEXT_DEFINE_INIT(acl_mailbox_list_module,
@@ -57,8 +61,7 @@ acl_mailbox_list_have_right(struct mailb
}
static void
-acl_mailbox_try_list_fast(struct acl_mailbox_list_iterate_context *ctx,
- const char *const *patterns)
+acl_mailbox_try_list_fast(struct acl_mailbox_list_iterate_context *ctx)
{
struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(ctx->ctx.list);
struct acl_backend *backend = alist->rights.backend;
@@ -68,8 +71,7 @@ acl_mailbox_try_list_fast(struct acl_mai
struct mail_namespace *ns = ctx->ctx.list->ns;
struct mailbox_list_iter_update_context update_ctx;
const char *name;
- string_t *vname;
- char sep;
+ string_t *vname = NULL;
int ret;
if ((ctx->ctx.flags & (MAILBOX_LIST_ITER_RAW_LIST |
@@ -84,20 +86,14 @@ acl_mailbox_try_list_fast(struct acl_mai
return;
/* no LOOKUP right by default, we can optimize this */
- if ((ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0) {
- sep = ns->sep;
+ if ((ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0)
vname = t_str_new(256);
- } else {
- sep = ns->real_sep;
- vname = NULL;
- }
memset(&update_ctx, 0, sizeof(update_ctx));
update_ctx.iter_ctx = &ctx->ctx;
- update_ctx.glob = imap_match_init_multiple(pool_datastack_create(),
- patterns, TRUE, sep);
+ update_ctx.glob = ctx->glob;
update_ctx.match_parents = TRUE;
- update_ctx.tree_ctx = mailbox_tree_init(sep);
+ update_ctx.tree_ctx = mailbox_tree_init(ctx->sep);
nonowner_list_ctx = acl_backend_nonowner_lookups_iter_init(backend);
while ((ret = acl_backend_nonowner_lookups_iter_next(nonowner_list_ctx,
@@ -121,10 +117,29 @@ acl_mailbox_list_iter_init(struct mailbo
{
struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(list);
struct acl_mailbox_list_iterate_context *ctx;
+ const char *p;
+ unsigned int i;
+ bool inboxcase;
ctx = i_new(struct acl_mailbox_list_iterate_context, 1);
ctx->ctx.list = list;
ctx->ctx.flags = flags;
+
+ inboxcase = (list->ns->flags & NAMESPACE_FLAG_INBOX) != 0;
+ ctx->sep = (ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0 ?
+ list->ns->sep : list->ns->real_sep;
+ ctx->glob = imap_match_init_multiple(default_pool, patterns,
+ inboxcase, ctx->sep);
+ /* see if all patterns have only a single '*' and it's at the end.
+ we can use it to do some optimizations. */
+ ctx->simple_star_glob = TRUE;
+ for (i = 0; patterns[i] != NULL; i++) {
+ p = strchr(patterns[i], '*');
+ if (p == NULL || p[1] != '\0') {
+ ctx->simple_star_glob = FALSE;
+ break;
+ }
+ }
if (list->ns->type == NAMESPACE_SHARED &&
(list->ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
@@ -138,7 +153,7 @@ acl_mailbox_list_iter_init(struct mailbo
list of mailboxes that have even potential to be visible. If we
couldn't get such a list, we'll go through all mailboxes. */
T_BEGIN {
- acl_mailbox_try_list_fast(ctx, patterns);
+ acl_mailbox_try_list_fast(ctx);
} T_END;
ctx->super_ctx = alist->module_ctx.super.
iter_init(list, patterns, flags);
@@ -180,9 +195,63 @@ acl_mailbox_list_iter_get_name(struct ma
return mail_namespace_fix_sep(ns, name);
}
+static bool
+iter_is_listing_all_children(struct acl_mailbox_list_iterate_context *ctx)
+{
+ const char *child;
+
+ /* If all patterns (with '.' separator) are in "name*", "name.*" or
+ "%.*" style format, simple_star_glob=TRUE and we can easily test
+ this by simply checking if name/child mailbox matches. */
+ child = t_strdup_printf("%s%cx", ctx->info.name, ctx->sep);
+ return ctx->simple_star_glob &&
+ imap_match(ctx->glob, child) == IMAP_MATCH_YES;
+}
+
+static bool
+iter_mailbox_has_visible_children(struct acl_mailbox_list_iterate_context *ctx)
+{
+ struct mailbox_list_iterate_context *iter;
+ const struct mailbox_info *info;
+ enum mailbox_list_iter_flags flags;
+ const char *pattern;
+ bool ret = FALSE;
+
+ /* do we have child mailboxes with LOOKUP right that don't match
+ the list pattern? */
+ if (ctx->lookup_boxes != NULL) {
+ /* we have a list of mailboxes with LOOKUP rights. before
+ starting the slow list iteration, check check first
+ if there even are any children with LOOKUP rights. */
+ struct mailbox_node *node;
+
+ node = mailbox_tree_lookup(ctx->lookup_boxes, ctx->info.name);
+ i_assert(node != NULL);
+ if (node->children == NULL)
+ return FALSE;
+ }
+
+ pattern = t_strdup_printf("%s%c*", ctx->info.name, ctx->sep);
+ flags = (ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) |
+ MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
+ iter = mailbox_list_iter_init(ctx->ctx.list, pattern, flags);
+ while ((info = mailbox_list_iter_next(iter)) != NULL) {
+ if (imap_match(ctx->glob, info->name) == IMAP_MATCH_YES) {
+ /* at least one child matches also the original list
+ patterns. we don't need to show this mailbox. */
+ ret = FALSE;
+ break;
+ }
+ ret = TRUE;
+ }
+ (void)mailbox_list_iter_deinit(&iter);
+ return ret;
+}
+
static int
acl_mailbox_list_info_is_visible(struct acl_mailbox_list_iterate_context *ctx)
{
+#define PRESERVE_MAILBOX_FLAGS (MAILBOX_SUBSCRIBED | MAILBOX_CHILD_SUBSCRIBED)
struct mailbox_info *info = &ctx->info;
const char *acl_name;
int ret;
@@ -200,9 +269,23 @@ acl_mailbox_list_info_is_visible(struct
return ret;
/* no permission to see this mailbox */
- if ((info->flags & MAILBOX_SUBSCRIBED) != 0) {
- /* it's subscribed, show it as non-existent */
- info->flags = MAILBOX_NONEXISTENT | MAILBOX_SUBSCRIBED;
+ if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
+ /* we're listing subscribed mailboxes. this one or its child
+ is subscribed, so we'll need to list it. but since we don't
+ have LOOKUP right, we'll need to show it as nonexistent. */
+ i_assert((info->flags & PRESERVE_MAILBOX_FLAGS) != 0);
+ info->flags = MAILBOX_NONEXISTENT |
+ (info->flags & PRESERVE_MAILBOX_FLAGS);
+ return 1;
+ }
+
+ if (!iter_is_listing_all_children(ctx) &&
+ iter_mailbox_has_visible_children(ctx)) {
+ /* no child mailboxes match the list pattern(s), but mailbox
+ has visible children. we'll need to show this as
+ non-existent. */
+ info->flags = MAILBOX_NONEXISTENT |
+ (info->flags & PRESERVE_MAILBOX_FLAGS);
return 1;
}
return 0;
@@ -233,27 +316,6 @@ acl_mailbox_list_iter_next(struct mailbo
}
static int
-acl_mailbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
- const char *dir, const char *fname,
- const char *mailbox_name,
- enum mailbox_list_file_type type,
- enum mailbox_info_flags *flags_r)
-{
- struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(ctx->list);
- int ret;
-
- ret = alist->module_ctx.super.iter_is_mailbox(ctx, dir, fname,
- mailbox_name,
- type, flags_r);
- if (ret <= 0 || (ctx->flags & MAILBOX_LIST_ITER_RAW_LIST) != 0)
- return ret;
-
- mailbox_name = acl_mailbox_list_iter_get_name(ctx, mailbox_name);
- return acl_mailbox_list_have_right(ctx->list, mailbox_name,
- ACL_STORAGE_RIGHT_LOOKUP, NULL);
-}
-
-static int
acl_mailbox_list_iter_deinit(struct mailbox_list_iterate_context *_ctx)
{
struct acl_mailbox_list_iterate_context *ctx =
@@ -265,7 +327,8 @@ acl_mailbox_list_iter_deinit(struct mail
ret = -1;
if (ctx->lookup_boxes != NULL)
mailbox_tree_deinit(&ctx->lookup_boxes);
-
+ if (ctx->glob != NULL)
+ imap_match_deinit(&ctx->glob);
i_free(ctx);
return ret;
}
@@ -442,7 +505,6 @@ void acl_mailbox_list_created(struct mai
list->v.iter_init = acl_mailbox_list_iter_init;
list->v.iter_next = acl_mailbox_list_iter_next;
list->v.iter_deinit = acl_mailbox_list_iter_deinit;
- list->v.iter_is_mailbox = acl_mailbox_list_iter_is_mailbox;
list->v.get_mailbox_name_status = acl_get_mailbox_name_status;
list->v.delete_mailbox = acl_mailbox_list_delete;
list->v.rename_mailbox = acl_mailbox_list_rename;
More information about the dovecot-cvs
mailing list