From 4ac2d38239cea8090154e17faefd77de5a71d882 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Fri, 21 Nov 2008 17:03:27 +0200 Subject: [PATCH] Added list=children option for namespaces. --HG-- branch : HEAD --- src/imap/cmd-list.c | 26 ++++++++++--- src/imap/cmd-subscribe.c | 3 +- src/lib-storage/index/shared/shared-list.c | 38 ++++++++++++++++++- src/lib-storage/index/shared/shared-storage.c | 3 +- src/lib-storage/mail-namespace.c | 27 ++++++++----- src/lib-storage/mail-namespace.h | 6 ++- src/master/mail-process.c | 6 ++- src/master/master-settings.c | 11 +++++- src/master/master-settings.h | 2 +- 9 files changed, 96 insertions(+), 26 deletions(-) diff --git a/src/imap/cmd-list.c b/src/imap/cmd-list.c index 4e7027c8cc..7555d75296 100644 --- a/src/imap/cmd-list.c +++ b/src/imap/cmd-list.c @@ -222,7 +222,7 @@ list_namespace_send_prefix(struct cmd_list_context *ctx, bool have_children) enum mailbox_info_flags flags; const char *name; string_t *str; - + ctx->cur_ns_send_prefix = FALSE; /* see if we already listed this as a valid mailbox in another @@ -257,6 +257,19 @@ list_namespace_send_prefix(struct cmd_list_context *ctx, bool have_children) } } + if ((ctx->ns->flags & NAMESPACE_FLAG_LIST_CHILDREN) != 0) { + if (have_children) { + /* children are going to be listed. */ + return; + } + if ((flags & MAILBOX_CHILDREN) == 0) { + /* namespace has no children. don't show it. */ + return; + } + /* namespace has children but they don't match the list + pattern. the prefix itself matches though, so show it. */ + } + name = ctx->cur_ns_skip_trailing_sep ? t_strndup(ctx->ns->prefix, len-1) : ctx->ns->prefix; @@ -504,8 +517,10 @@ list_want_send_prefix(struct cmd_list_context *ctx, const char *pattern) if ((ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) return FALSE; - /* send the prefix if namespace is listable.. */ - if ((ctx->ns->flags & NAMESPACE_FLAG_LIST) != 0) + /* send the prefix if namespace is listable. if children are listable + we may or may not need to send it. */ + if ((ctx->ns->flags & (NAMESPACE_FLAG_LIST_PREFIX | + NAMESPACE_FLAG_LIST_CHILDREN)) != 0) return TRUE; /* ..or if pattern is exactly the same as namespace prefix. @@ -550,7 +565,8 @@ list_namespace_match_pattern(struct cmd_list_context *ctx, bool inboxcase, } /* hidden and non-listable namespaces are invisible to wildcards */ - if ((ns->flags & NAMESPACE_FLAG_LIST) == 0 && + if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX | + NAMESPACE_FLAG_LIST_CHILDREN)) == 0 && list_pattern_has_wildcards(cur_pattern)) return FALSE; @@ -623,7 +639,7 @@ static void list_namespace_init(struct cmd_list_context *ctx) /* it's possible that the namespace prefix matched, even though its children didn't */ if (ctx->cur_ns_send_prefix) - list_namespace_send_prefix(ctx, TRUE); + list_namespace_send_prefix(ctx, FALSE); return; } /* we should still list INBOX */ diff --git a/src/imap/cmd-subscribe.c b/src/imap/cmd-subscribe.c index 1f4c5a57cf..12af3b1496 100644 --- a/src/imap/cmd-subscribe.c +++ b/src/imap/cmd-subscribe.c @@ -10,7 +10,8 @@ static bool have_listable_namespace_prefix(struct mail_namespace *ns, unsigned int name_len = strlen(name); for (; ns != NULL; ns = ns->next) { - if ((ns->flags & NAMESPACE_FLAG_LIST) == 0) + if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX | + NAMESPACE_FLAG_LIST_CHILDREN)) == 0) continue; if (ns->prefix_len <= name_len) diff --git a/src/lib-storage/index/shared/shared-list.c b/src/lib-storage/index/shared/shared-list.c index a6dca952ba..d8ae599918 100644 --- a/src/lib-storage/index/shared/shared-list.c +++ b/src/lib-storage/index/shared/shared-list.c @@ -1,12 +1,16 @@ /* Copyright (c) 2008 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "imap-match.h" #include "mailbox-list-private.h" #include "index-storage.h" #include "shared-storage.h" struct shared_mailbox_list_iterate_context { struct mailbox_list_iterate_context ctx; + struct mail_namespace *cur_ns; + struct imap_match_glob *glob; + struct mailbox_info info; }; extern struct mailbox_list shared_mailbox_list; @@ -149,8 +153,11 @@ shared_list_iter_init(struct mailbox_list *list, const char *const *patterns, ctx = i_new(struct shared_mailbox_list_iterate_context, 1); ctx->ctx.list = list; ctx->ctx.flags = flags; - - /* FIXME */ + ctx->cur_ns = list->ns->user->namespaces; + ctx->info.ns = list->ns; + ctx->info.flags = MAILBOX_NONEXISTENT; + ctx->glob = imap_match_init_multiple(default_pool, patterns, + FALSE, list->ns->sep); return &ctx->ctx; } @@ -159,7 +166,34 @@ shared_list_iter_next(struct mailbox_list_iterate_context *_ctx) { struct shared_mailbox_list_iterate_context *ctx = (struct shared_mailbox_list_iterate_context *)_ctx; + struct mail_namespace *ns = ctx->cur_ns; + + for (; ns != NULL; ns = ns->next) { + if (ns->type != NAMESPACE_SHARED || + (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) + continue; + if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX | + NAMESPACE_FLAG_LIST_CHILDREN)) == 0) + continue; + + if (ns->prefix_len < ctx->info.ns->prefix_len || + strncmp(ns->prefix, ctx->info.ns->prefix, + ctx->info.ns->prefix_len) != 0) + continue; + + /* visible and listable namespace under ourself, see if the + prefix matches without the trailing separator */ + i_assert(ns->prefix_len > 0); + ctx->info.name = t_strndup(ns->prefix, ns->prefix_len - 1); + if ((_ctx->flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) == 0) + ctx->info.name += ctx->info.ns->prefix_len; + if (imap_match(ctx->glob, ctx->info.name) == IMAP_MATCH_YES) { + ctx->cur_ns = ns->next; + return &ctx->info; + } + } + ctx->cur_ns = NULL; return NULL; } diff --git a/src/lib-storage/index/shared/shared-storage.c b/src/lib-storage/index/shared/shared-storage.c index 055abcec91..9fe1e5d829 100644 --- a/src/lib-storage/index/shared/shared-storage.c +++ b/src/lib-storage/index/shared/shared-storage.c @@ -269,7 +269,7 @@ int shared_storage_get_namespace(struct mail_storage *_storage, ns->type = NAMESPACE_SHARED; ns->user = user; ns->prefix = i_strdup(str_c(prefix)); - ns->flags = NAMESPACE_FLAG_LIST | NAMESPACE_FLAG_HIDDEN | + ns->flags = NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_HIDDEN | NAMESPACE_FLAG_AUTOCREATED; ns->sep = _storage->ns->sep; @@ -285,6 +285,7 @@ int shared_storage_get_namespace(struct mail_storage *_storage, return -1; } mail_user_add_namespace(user, ns); + _storage->ns->flags |= NAMESPACE_FLAG_USABLE; *_name = mail_namespace_fix_sep(ns, name); *ns_r = ns; diff --git a/src/lib-storage/mail-namespace.c b/src/lib-storage/mail-namespace.c index ee77626eda..00f91ac4f9 100644 --- a/src/lib-storage/mail-namespace.c +++ b/src/lib-storage/mail-namespace.c @@ -39,19 +39,24 @@ namespace_add_env(const char *data, unsigned int num, enum file_lock_method lock_method) { struct mail_namespace *ns; - const char *sep, *type, *prefix, *driver, *error; + const char *sep, *type, *prefix, *driver, *error, *list; ns = i_new(struct mail_namespace, 1); sep = getenv(t_strdup_printf("NAMESPACE_%u_SEP", num)); type = getenv(t_strdup_printf("NAMESPACE_%u_TYPE", num)); prefix = getenv(t_strdup_printf("NAMESPACE_%u_PREFIX", num)); + list = getenv(t_strdup_printf("NAMESPACE_%u_LIST", num)); if (getenv(t_strdup_printf("NAMESPACE_%u_INBOX", num)) != NULL) ns->flags |= NAMESPACE_FLAG_INBOX; if (getenv(t_strdup_printf("NAMESPACE_%u_HIDDEN", num)) != NULL) ns->flags |= NAMESPACE_FLAG_HIDDEN; - if (getenv(t_strdup_printf("NAMESPACE_%u_LIST", num)) != NULL) - ns->flags |= NAMESPACE_FLAG_LIST; + if (list != NULL) { + if (strcmp(list, "children") == 0) + ns->flags |= NAMESPACE_FLAG_LIST_CHILDREN; + else + ns->flags |= NAMESPACE_FLAG_LIST_PREFIX; + } if (getenv(t_strdup_printf("NAMESPACE_%u_SUBSCRIPTIONS", num)) != NULL) ns->flags |= NAMESPACE_FLAG_SUBSCRIPTIONS; @@ -76,7 +81,7 @@ namespace_add_env(const char *data, unsigned int num, type == NULL ? "" : type, prefix, sep == NULL ? "" : sep, (ns->flags & NAMESPACE_FLAG_INBOX) ? "yes" : "no", (ns->flags & NAMESPACE_FLAG_HIDDEN) ? "yes" : "no", - (ns->flags & NAMESPACE_FLAG_LIST) ? "yes" : "no", + list, (ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) ? "yes" : "no"); } @@ -88,6 +93,7 @@ namespace_add_env(const char *data, unsigned int num, if (ns->type == NAMESPACE_SHARED && strchr(ns->prefix, '%') != NULL) { /* dynamic shared namespace */ + ns->flags |= NAMESPACE_FLAG_INTERNAL; driver = "shared"; } else { driver = NULL; @@ -124,14 +130,15 @@ static bool namespaces_check(struct mail_namespace *namespaces) private_ns_count++; } if (*ns->prefix != '\0' && - (ns->flags & NAMESPACE_FLAG_LIST) != 0 && + (ns->flags & NAMESPACE_FLAG_LIST_PREFIX) != 0 && ns->prefix[strlen(ns->prefix)-1] != ns->sep) { i_error("namespace configuration error: " "list=yes requires prefix=%s " "to end with separator", ns->prefix); return FALSE; } - if ((ns->flags & NAMESPACE_FLAG_LIST) != 0) { + if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX | + NAMESPACE_FLAG_LIST_CHILDREN)) != 0) { if (list_sep == '\0') list_sep = ns->sep; else if (list_sep != ns->sep) { @@ -142,7 +149,7 @@ static bool namespaces_check(struct mail_namespace *namespaces) } } if (*ns->prefix == '\0' && - (ns->flags & NAMESPACE_FLAG_LIST) == 0) { + (ns->flags & NAMESPACE_FLAG_LIST_PREFIX) == 0) { i_error("namespace configuration error: " "Empty prefix requires list=yes"); return FALSE; @@ -236,7 +243,7 @@ int mail_namespaces_init(struct mail_user *user) ns = i_new(struct mail_namespace, 1); ns->type = NAMESPACE_PRIVATE; - ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST | + ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_SUBSCRIPTIONS; ns->prefix = i_strdup(""); ns->user = user; @@ -270,7 +277,7 @@ mail_namespaces_init_empty(struct mail_user *user) ns = i_new(struct mail_namespace, 1); ns->user = user; ns->prefix = i_strdup(""); - ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST | + ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_SUBSCRIPTIONS; user->namespaces = ns; return ns; @@ -342,7 +349,7 @@ const char *mail_namespace_get_vname(struct mail_namespace *ns, string_t *dest, char mail_namespace_get_root_sep(const struct mail_namespace *namespaces) { - while ((namespaces->flags & NAMESPACE_FLAG_LIST) == 0) + while ((namespaces->flags & NAMESPACE_FLAG_LIST_PREFIX) == 0) namespaces = namespaces->next; return namespaces->sep; } diff --git a/src/lib-storage/mail-namespace.h b/src/lib-storage/mail-namespace.h index ac24a3e73a..e039c3e1c0 100644 --- a/src/lib-storage/mail-namespace.h +++ b/src/lib-storage/mail-namespace.h @@ -14,8 +14,10 @@ enum namespace_flags { NAMESPACE_FLAG_INBOX = 0x01, /* Namespace is visible only by explicitly using its full prefix */ NAMESPACE_FLAG_HIDDEN = 0x02, - /* Namespace is visible with LIST */ - NAMESPACE_FLAG_LIST = 0x04, + /* Namespace prefix is visible with LIST */ + NAMESPACE_FLAG_LIST_PREFIX = 0x04, + /* Namespace prefix isn't visible with LIST, but child mailboxes are */ + NAMESPACE_FLAG_LIST_CHILDREN = 0x08, /* Namespace uses its own subscriptions. */ NAMESPACE_FLAG_SUBSCRIPTIONS = 0x10, diff --git a/src/master/mail-process.c b/src/master/mail-process.c index b6558b2340..7e4c8a5c24 100644 --- a/src/master/mail-process.c +++ b/src/master/mail-process.c @@ -279,8 +279,10 @@ env_put_namespace(struct namespace_settings *ns, const char *default_location, env_put(t_strdup_printf("NAMESPACE_%u_INBOX=1", i)); if (ns->hidden) env_put(t_strdup_printf("NAMESPACE_%u_HIDDEN=1", i)); - if (ns->list) - env_put(t_strdup_printf("NAMESPACE_%u_LIST=1", i)); + if (strcmp(ns->list, "no") != 0) { + env_put(t_strdup_printf("NAMESPACE_%u_LIST=%s", + i, ns->list)); + } if (ns->subscriptions) env_put(t_strdup_printf("NAMESPACE_%u_SUBSCRIPTIONS=1", i)); diff --git a/src/master/master-settings.c b/src/master/master-settings.c index 0a4593d516..a7c592a92d 100644 --- a/src/master/master-settings.c +++ b/src/master/master-settings.c @@ -160,7 +160,7 @@ static struct setting_def namespace_setting_defs[] = { DEF_STR(location), DEF_BOOL(inbox), DEF_BOOL(hidden), - DEF_BOOL(list), + DEF_STR(list), DEF_BOOL(subscriptions), { 0, NULL, 0 } @@ -362,7 +362,7 @@ struct namespace_settings default_namespace_settings = { MEMBER(inbox) FALSE, MEMBER(hidden) FALSE, - MEMBER(list) TRUE, + MEMBER(list) "yes", MEMBER(subscriptions) TRUE }; @@ -502,6 +502,13 @@ static bool namespace_settings_verify(struct namespace_settings *ns) name); return FALSE; } + if (strcmp(ns->list, "yes") != 0 && + strcmp(ns->list, "no") != 0 && + strcmp(ns->list, "children") != 0) { + i_error("Namespace '%s': Invalid list value: %s", + name, ns->list); + return FALSE; + } return TRUE; } diff --git a/src/master/master-settings.h b/src/master/master-settings.h index c055d352ab..fd76a7a76a 100644 --- a/src/master/master-settings.h +++ b/src/master/master-settings.h @@ -243,7 +243,7 @@ struct namespace_settings { bool inbox; bool hidden; - bool list; + const char *list; bool subscriptions; }; -- 2.47.3