dovecot: Added support for multiple mailbox list patterns.
dovecot at dovecot.org
dovecot at dovecot.org
Sun Jul 15 05:33:47 EEST 2007
details: http://hg.dovecot.org/dovecot/rev/cc1f4688a988
changeset: 6007:cc1f4688a988
user: Timo Sirainen <tss at iki.fi>
date: Sun Jul 15 05:33:43 2007 +0300
description:
Added support for multiple mailbox list patterns.
diffstat:
12 files changed, 506 insertions(+), 313 deletions(-)
src/imap/cmd-list.c | 314 ++++++++++++--------
src/lib-imap/imap-match.c | 331 ++++++++++++++--------
src/lib-imap/imap-match.h | 16 -
src/lib-storage/list/index-mailbox-list.c | 17 -
src/lib-storage/list/mailbox-list-fs-iter.c | 53 ++-
src/lib-storage/list/mailbox-list-fs.h | 2
src/lib-storage/list/mailbox-list-maildir-iter.c | 29 -
src/lib-storage/list/mailbox-list-maildir.h | 2
src/lib-storage/mailbox-list-private.h | 3
src/lib-storage/mailbox-list.c | 19 +
src/lib-storage/mailbox-list.h | 8
src/plugins/acl/acl-mailbox-list.c | 25 -
diffs (truncated from 1302 to 300 lines):
diff -r 9da1ec15340d -r cc1f4688a988 src/imap/cmd-list.c
--- a/src/imap/cmd-list.c Sun Jul 15 02:45:25 2007 +0300
+++ b/src/imap/cmd-list.c Sun Jul 15 05:33:43 2007 +0300
@@ -12,7 +12,7 @@ struct cmd_list_context {
struct cmd_list_context {
struct client_command_context *cmd;
const char *ref;
- const char *pattern;
+ const char *const *patterns;
enum mailbox_list_flags list_flags;
struct mail_namespace *ns;
@@ -403,17 +403,12 @@ skip_namespace_prefix(const char **prefi
}
static bool
-skip_namespace_prefix_refpattern(struct cmd_list_context *ctx,
- const char **cur_ns_prefix_p,
- const char **cur_ref_p,
- const char **cur_pattern_p)
+skip_namespace_prefix_ref(struct cmd_list_context *ctx,
+ const char **cur_ns_prefix_p,
+ const char **cur_ref_p)
{
const char *cur_ns_prefix = *cur_ns_prefix_p;
const char *cur_ref = *cur_ref_p;
- const char *cur_pattern = *cur_pattern_p;
-
- if (*ctx->ns->prefix == '\0')
- return TRUE;
if (*cur_ref != '\0') {
/* reference argument given. skip namespace prefix using it.
@@ -434,33 +429,46 @@ skip_namespace_prefix_refpattern(struct
}
}
- if (*cur_ns_prefix != '\0') {
- /* skip namespace prefix using pattern */
- const char *old_ns_prefix = cur_ns_prefix;
- const char *old_pattern = cur_pattern;
-
- i_assert(*cur_ref == '\0');
-
- skip_namespace_prefix(&cur_ns_prefix, &cur_pattern,
- cur_ref == ctx->ref, ctx->ns->sep);
-
- if (*cur_pattern == '\0' && *cur_ns_prefix == '\0') {
- /* trying to list the namespace prefix itself. */
- cur_ns_prefix = old_ns_prefix;
- cur_pattern = old_pattern;
- }
- }
-
*cur_ns_prefix_p = cur_ns_prefix;
*cur_ref_p = cur_ref;
+ return TRUE;
+}
+
+static void
+skip_namespace_prefix_pattern(struct cmd_list_context *ctx,
+ const char **cur_ns_prefix_p,
+ const char *cur_ref, const char **cur_pattern_p)
+{
+ const char *cur_ns_prefix = *cur_ns_prefix_p;
+ const char *cur_pattern = *cur_pattern_p;
+ const char *old_ns_prefix = cur_ns_prefix;
+ const char *old_pattern = cur_pattern;
+
+ if (*cur_ns_prefix == '\0')
+ return;
+
+ /* skip namespace prefix using pattern */
+ i_assert(*cur_ref == '\0');
+
+ skip_namespace_prefix(&cur_ns_prefix, &cur_pattern,
+ cur_ref == ctx->ref, ctx->ns->sep);
+
+ if (*cur_pattern == '\0' && *cur_ns_prefix == '\0') {
+ /* trying to list the namespace prefix itself. */
+ cur_ns_prefix = old_ns_prefix;
+ cur_pattern = old_pattern;
+ }
+
+ *cur_ns_prefix_p = cur_ns_prefix;
*cur_pattern_p = cur_pattern;
- return TRUE;
}
static enum imap_match_result
list_use_inboxcase(struct cmd_list_context *ctx)
{
struct imap_match_glob *inbox_glob;
+ const char *const *pat;
+ enum imap_match_result match, ret;
if (*ctx->ns->prefix != '\0' &&
(ctx->ns->flags & NAMESPACE_FLAG_INBOX) == 0)
@@ -468,10 +476,22 @@ list_use_inboxcase(struct cmd_list_conte
/* if the original reference and pattern combined produces something
that matches INBOX, the INBOX casing is on. */
- inbox_glob = imap_match_init(ctx->cmd->pool,
- t_strconcat(ctx->ref, ctx->pattern, NULL),
- TRUE, ctx->ns->sep);
- return imap_match(inbox_glob, "INBOX");
+ ret = IMAP_MATCH_NO;
+ for (pat = ctx->patterns; *pat != NULL; pat++) {
+ t_push();
+ inbox_glob =
+ imap_match_init(pool_datastack_create(),
+ t_strconcat(ctx->ref, *pat, NULL),
+ TRUE, ctx->ns->sep);
+ match = imap_match(inbox_glob, "INBOX");
+ t_pop();
+
+ if (match == IMAP_MATCH_YES)
+ return IMAP_MATCH_YES;
+ if ((match & IMAP_MATCH_PARENT) != 0)
+ ret = IMAP_MATCH_PARENT;
+ }
+ return ret;
}
static void
@@ -509,19 +529,95 @@ skip_pattern_wildcard_prefix(const char
*cur_pattern_p = cur_pattern;
}
+static bool
+list_namespace_init_pattern(struct cmd_list_context *ctx, bool inboxcase,
+ const char *cur_ref, const char *cur_ns_prefix,
+ const char **cur_pattern_p, bool *want_glob_r)
+{
+ struct mail_namespace *ns = ctx->ns;
+ struct imap_match_glob *pat_glob;
+ const char *cur_pattern = *cur_pattern_p;
+ enum imap_match_result match;
+ size_t len;
+
+ skip_namespace_prefix_pattern(ctx, &cur_ns_prefix,
+ cur_ref, &cur_pattern);
+ if (*cur_ns_prefix == '\0') {
+ *want_glob_r = FALSE;
+ *cur_pattern_p = cur_pattern;
+ return TRUE;
+ }
+
+ /* namespace prefix still wasn't completely skipped over.
+ for example cur_ns_prefix=INBOX/, pattern=%/% or pattern=IN%.
+ Check that pattern matches namespace prefix. */
+ i_assert(*cur_ref == '\0');
+
+ /* drop the trailing separator in namespace prefix.
+ don't do it if we're listing only the prefix itself
+ (LIST "" foo/ needs to return "foo/" entry) */
+ len = strlen(cur_ns_prefix);
+ if (cur_ns_prefix[len-1] == ns->sep &&
+ strcmp(cur_pattern, cur_ns_prefix) != 0) {
+ ctx->cur_ns_skip_trailing_sep = TRUE;
+ cur_ns_prefix = t_strndup(cur_ns_prefix, len-1);
+ }
+
+ /* hidden and non-listable namespaces are invisible to wildcards */
+ if ((ns->flags & NAMESPACE_FLAG_LIST) == 0 &&
+ list_pattern_has_wildcards(cur_pattern))
+ return FALSE;
+
+ /* check if this namespace prefix matches the current pattern */
+ pat_glob = imap_match_init(pool_datastack_create(), *cur_pattern_p,
+ inboxcase, ns->sep);
+ match = imap_match(pat_glob, cur_ns_prefix);
+ if ((match & (IMAP_MATCH_YES | IMAP_MATCH_CHILDREN)) == 0)
+ return FALSE;
+
+ if (match == IMAP_MATCH_YES && (ns->flags & NAMESPACE_FLAG_LIST) != 0 &&
+ (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) {
+ /* the namespace prefix itself matches too. send it. */
+ ctx->cur_ns_send_prefix = TRUE;
+ }
+
+ /* We have now verified that the pattern matches the namespace prefix,
+ so we'll just have to skip over as many hierarchies from pattern as
+ there exists in namespace prefix. */
+ skip_pattern_wildcard_prefix(cur_ns_prefix, ns->sep, &cur_pattern);
+
+ if (*cur_pattern == '\0' && ctx->cur_ns_match_inbox) {
+ /* ns_prefix="INBOX/" and we wanted to list "%".
+ This is an optimization to avoid doing an empty
+ listing followed by another INBOX listing later. */
+ cur_pattern = "INBOX";
+ *want_glob_r = FALSE;
+ } else if (*cur_pattern != '*' || strcmp(*cur_pattern_p, "*") == 0) {
+ /* a) we don't have '*' in pattern
+ b) we want to display everything
+
+ we don't need to do separate filtering ourself */
+ *want_glob_r = FALSE;
+ } else {
+ *want_glob_r = TRUE;
+ }
+
+ *cur_pattern_p = cur_pattern;
+ return TRUE;
+}
+
static void list_namespace_init(struct cmd_list_context *ctx)
{
struct mail_namespace *ns = ctx->ns;
- const char *cur_ns_prefix, *cur_ref, *cur_pattern;
- enum imap_match_result match;
+ const char *cur_ns_prefix, *cur_ref, *const *pat, *pattern;
enum imap_match_result inbox_match;
- size_t len;
+ ARRAY_DEFINE(used_patterns, const char *);
+ bool inboxcase, want_glob = FALSE, want_any_glob = FALSE;
cur_ns_prefix = ns->prefix;
cur_ref = ctx->ref;
- cur_pattern = ctx->pattern;
-
- if ((ctx->ns->flags & NAMESPACE_FLAG_HIDDEN) != 0 &&
+
+ if ((ns->flags & NAMESPACE_FLAG_HIDDEN) != 0 &&
(ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
/* ignore hidden namespaces */
return;
@@ -532,85 +628,42 @@ static void list_namespace_init(struct c
if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0)
ctx->seen_inbox_namespace = TRUE;
- if (!skip_namespace_prefix_refpattern(ctx, &cur_ns_prefix,
- &cur_ref, &cur_pattern))
- return;
+ if (*cur_ns_prefix != '\0') {
+ /* namespace has a prefix. see if we can skip over it. */
+ if (!skip_namespace_prefix_ref(ctx, &cur_ns_prefix, &cur_ref))
+ return;
+ }
inbox_match = list_use_inboxcase(ctx);
ctx->cur_ns_match_inbox = inbox_match == IMAP_MATCH_YES;
-
- ctx->glob = imap_match_init(ctx->cmd->pool, ctx->pattern,
- (inbox_match == IMAP_MATCH_YES ||
- inbox_match == IMAP_MATCH_PARENT) &&
- cur_pattern == ctx->pattern, ns->sep);
-
- if (*cur_ns_prefix != '\0') {
- /* namespace prefix still wasn't completely skipped over.
- for example cur_ns_prefix=INBOX/, pattern=%/% or pattern=IN%.
- Check that pattern matches namespace prefix. */
- i_assert(*cur_ref == '\0');
-
- /* drop the trailing separator in namespace prefix.
- don't do it if we're listing only the prefix itself
- (LIST "" foo/ needs to return "foo/" entry) */
- len = strlen(cur_ns_prefix);
- if (cur_ns_prefix[len-1] == ns->sep &&
- strcmp(cur_pattern, cur_ns_prefix) != 0) {
- ctx->cur_ns_skip_trailing_sep = TRUE;
- cur_ns_prefix = t_strndup(cur_ns_prefix, len-1);
- }
-
- /* hidden and non-listable namespaces should still be seen
- without wildcards. */
- match = ((ns->flags & NAMESPACE_FLAG_LIST) == 0 &&
- list_pattern_has_wildcards(cur_pattern)) ?
- IMAP_MATCH_NO : imap_match(ctx->glob, cur_ns_prefix);
- if (match != IMAP_MATCH_YES && match != IMAP_MATCH_CHILDREN)
- return;
-
- if (match == IMAP_MATCH_YES &&
- (ns->flags & NAMESPACE_FLAG_LIST) != 0 &&
- (ctx->list_flags &
- MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0)
- ctx->cur_ns_send_prefix = TRUE;
- }
-
-
- if (*cur_ns_prefix != '\0') {
- /* We didn't skip over the whole namespace prefix. For example
- cur_ns_prefix=INBOX/ and pattern=%/% or IN*.
-
- We have already verified that the pattern matches the
- namespace prefix, so we'll just have to skip over as many
- hierarchies from pattern as there exists in namespace
- prefix. */
- i_assert(*cur_ref == '\0');
- skip_pattern_wildcard_prefix(cur_ns_prefix, ns->sep,
- &cur_pattern);
-
- if (*cur_pattern == '\0' && ctx->cur_ns_match_inbox) {
- /* ns_prefix="INBOX/" and we wanted to list "%".
- This is an optimization to avoid doing an empty
- listing followed by another INBOX listing later. */
- cur_pattern = "INBOX";
- }
- }
-
More information about the dovecot-cvs
mailing list