]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added list=children option for namespaces.
authorTimo Sirainen <tss@iki.fi>
Fri, 21 Nov 2008 15:03:27 +0000 (17:03 +0200)
committerTimo Sirainen <tss@iki.fi>
Fri, 21 Nov 2008 15:03:27 +0000 (17:03 +0200)
--HG--
branch : HEAD

src/imap/cmd-list.c
src/imap/cmd-subscribe.c
src/lib-storage/index/shared/shared-list.c
src/lib-storage/index/shared/shared-storage.c
src/lib-storage/mail-namespace.c
src/lib-storage/mail-namespace.h
src/master/mail-process.c
src/master/master-settings.c
src/master/master-settings.h

index 4e7027c8ccf50ab06835d5ce585279acf3288480..7555d75296a4bbdec109037cc0845ba4e84696a9 100644 (file)
@@ -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 */
index 1f4c5a57cf938c84e10a3e8e9c46551484477110..12af3b149686d468d1332995d464961373d6454a 100644 (file)
@@ -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)
index a6dca952ba6634348360954b978b1084e82c5f7c..d8ae59991840181d911e51b1f17bd8c65f0c2cec 100644 (file)
@@ -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;
 }
 
index 055abcec9120e0570e0e4dac77924d127c29227a..9fe1e5d8293298f6551da9353e335487e18e8c91 100644 (file)
@@ -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;
index ee77626eda14be990f1cdb20f269896095c337b3..00f91ac4f9ae7f49523b59c5b8a77bd4eacb7721 100644 (file)
@@ -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;
 }
index ac24a3e73a8cca6e5188fa038d5f79d533ab2830..e039c3e1c0385fe11beedbf272231bb99a32b79c 100644 (file)
@@ -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,
 
index b6558b2340ff3ab01eed7b534b9cdbaaa614a61d..7e4c8a5c242c02f1996a74fea75a8349b6ff2a77 100644 (file)
@@ -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));
index 0a4593d516ff36ac78c29e71ad9573bd124e5b45..a7c592a92dc6351929ee350babe9bb811edcde4f 100644 (file)
@@ -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;
 }
index c055d352abff65763d89956acb0b39b97912c8f0..fd76a7a76acb7b5dd2cd4792c006212f26a21d45 100644 (file)
@@ -243,7 +243,7 @@ struct namespace_settings {
 
        bool inbox;
        bool hidden;
-       bool list;
+       const char *list;
        bool subscriptions;
 };