dovecot: Handle listing flags correctly for all namespace prefixes.
dovecot at dovecot.org
dovecot at dovecot.org
Wed Jun 27 20:21:05 EEST 2007
details: http://hg.dovecot.org/dovecot/rev/e0b451e0c190
changeset: 5811:e0b451e0c190
user: Timo Sirainen <tss at iki.fi>
date: Wed Jun 27 20:21:00 2007 +0300
description:
Handle listing flags correctly for all namespace prefixes.
diffstat:
1 file changed, 185 insertions(+), 78 deletions(-)
src/imap/cmd-list.c | 263 +++++++++++++++++++++++++++++++++++----------------
diffs (truncated from 446 to 300 lines):
diff -r f56a71347378 -r e0b451e0c190 src/imap/cmd-list.c
--- a/src/imap/cmd-list.c Wed Jun 27 20:19:49 2007 +0300
+++ b/src/imap/cmd-list.c Wed Jun 27 20:21:00 2007 +0300
@@ -1,6 +1,7 @@
-/* Copyright (C) 2002-2004 Timo Sirainen */
+/* Copyright (C) 2002-2007 Timo Sirainen */
#include "common.h"
+#include "array.h"
#include "str.h"
#include "strescape.h"
#include "imap-quote.h"
@@ -14,6 +15,7 @@ enum {
};
struct cmd_list_context {
+ struct client_command_context *cmd;
const char *ref;
const char *mask;
enum mailbox_list_flags list_flags;
@@ -22,9 +24,14 @@ struct cmd_list_context {
struct mailbox_list_iterate_context *list_iter;
struct imap_match_glob *glob;
+ ARRAY_DEFINE(ns_prefixes_listed, struct mail_namespace *);
+
unsigned int lsub:1;
unsigned int inbox_found:1;
- unsigned int match_inbox:1;
+ unsigned int seen_inbox_namespace:1;
+ unsigned int cur_ns_match_inbox:1;
+ unsigned int cur_ns_send_prefix:1;
+ unsigned int cur_ns_skip_trailing_sep:1;
};
static void
@@ -48,10 +55,12 @@ mailbox_flags2str(string_t *str, enum ma
str_append(str, "\\NonExistent ");
if ((flags & MAILBOX_CHILDREN) != 0)
str_append(str, "\\HasChildren ");
- if ((flags & MAILBOX_NOCHILDREN) != 0)
- str_append(str, "\\HasNoChildren ");
- if ((flags & MAILBOX_NOINFERIORS) != 0)
- str_append(str, "\\NoInferiors ");
+ else {
+ if ((flags & MAILBOX_NOCHILDREN) != 0)
+ str_append(str, "\\HasNoChildren ");
+ if ((flags & MAILBOX_NOINFERIORS) != 0)
+ str_append(str, "\\NoInferiors ");
+ }
if ((flags & MAILBOX_MARKED) != 0)
str_append(str, "\\Marked ");
if ((flags & MAILBOX_UNMARKED) != 0)
@@ -90,19 +99,102 @@ parse_list_flags(struct client_command_c
return TRUE;
}
+static enum mailbox_info_flags
+list_get_inbox_flags(struct cmd_list_context *ctx)
+{
+ struct mail_namespace *ns;
+ struct mailbox_list_iterate_context *list_iter;
+ const struct mailbox_info *info;
+ enum mailbox_info_flags flags = MAILBOX_UNMARKED;
+
+ if (ctx->seen_inbox_namespace &&
+ (ctx->ns->flags & NAMESPACE_FLAG_INBOX) == 0) {
+ /* INBOX doesn't exist. use the default INBOX flags */
+ return flags;
+ }
+
+ /* find the INBOX flags */
+ ns = mail_namespace_find_inbox(ctx->cmd->client->namespaces);
+ list_iter = mailbox_list_iter_init(ns->list, "INBOX", 0);
+ info = mailbox_list_iter_next(list_iter);
+ if (info != NULL) {
+ i_assert(strcasecmp(info->name, "INBOX") == 0);
+ flags = info->flags;
+ }
+ (void)mailbox_list_iter_deinit(&list_iter);
+ return flags;
+}
+
+static bool list_namespace_has_children(struct cmd_list_context *ctx)
+{
+ struct mailbox_list_iterate_context *list_iter;
+ const struct mailbox_info *info;
+ bool ret = FALSE;
+
+ list_iter = mailbox_list_iter_init(ctx->ns->list, "%",
+ MAILBOX_LIST_ITER_FAST_FLAGS);
+ info = mailbox_list_iter_next(list_iter);
+ if (info != NULL)
+ ret = TRUE;
+ if (mailbox_list_iter_deinit(&list_iter) < 0) {
+ /* safer to answer TRUE in error conditions */
+ ret = TRUE;
+ }
+ return ret;
+}
+
static void
-list_namespace_inbox(struct client *client, struct cmd_list_context *ctx)
-{
- const char *str;
-
- if (!ctx->inbox_found && ctx->match_inbox &&
- (ctx->ns->flags & NAMESPACE_FLAG_INBOX) != 0 &&
- (ctx->list_flags & MAILBOX_LIST_ITER_SUBSCRIBED) == 0) {
- /* INBOX always exists */
- str = t_strdup_printf("* LIST (\\Unmarked) \"%s\" \"INBOX\"",
- ctx->ns->sep_str);
- client_send_line(client, str);
- }
+list_namespace_send_prefix(struct cmd_list_context *ctx, bool have_children)
+{
+ struct mail_namespace *const *listed;
+ unsigned int i, count, len;
+ 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
+ namespace */
+ listed = array_get(&ctx->ns_prefixes_listed, &count);
+ for (i = 0; i < count; i++) {
+ if (listed[i] == ctx->ns)
+ return;
+ }
+
+ len = strlen(ctx->ns->prefix);
+ if (len == 6 && strncasecmp(ctx->ns->prefix, "INBOX", len-1) == 0 &&
+ ctx->ns->prefix[len-1] == ctx->ns->sep) {
+ /* INBOX namespace needs to be handled specially. */
+ if (ctx->inbox_found) {
+ /* we're just now going to send it */
+ return;
+ }
+
+ ctx->inbox_found = TRUE;
+ flags = list_get_inbox_flags(ctx);
+ } else {
+ flags = MAILBOX_NONEXISTENT;
+ }
+
+ if ((flags & MAILBOX_CHILDREN) == 0) {
+ if (have_children || list_namespace_has_children(ctx)) {
+ flags |= MAILBOX_CHILDREN;
+ flags &= ~MAILBOX_NOCHILDREN;
+ } else {
+ flags |= MAILBOX_NOCHILDREN;
+ }
+ }
+
+ str = t_str_new(128);
+ str_append(str, "* LIST (");
+ mailbox_flags2str(str, flags, ctx->list_flags);
+ str_printfa(str, ") \"%s\" ", ctx->ns->sep_str);
+
+ name = ctx->cur_ns_skip_trailing_sep ?
+ t_strndup(ctx->ns->prefix, len-1) : ctx->ns->prefix;
+ imap_quote_append_string(str, name, FALSE);
+ client_send_line(ctx->cmd->client, str_c(str));
}
static bool
@@ -117,7 +209,7 @@ list_insert_ns_prefix(string_t *name_str
/* no namespace prefix, we can't list this */
return FALSE;
}
- } else if (!ctx->match_inbox) {
+ } else if (!ctx->cur_ns_match_inbox) {
/* The mask doesn't match INBOX (eg. prefix.%).
We still want to list prefix.INBOX if it has
children. Otherwise we don't want to list
@@ -134,17 +226,14 @@ list_insert_ns_prefix(string_t *name_str
}
static int
-list_namespace_mailboxes(struct client *client, struct cmd_list_context *ctx)
+list_namespace_mailboxes(struct cmd_list_context *ctx)
{
const struct mailbox_info *info;
+ struct mail_namespace *ns;
+ enum mailbox_info_flags flags;
+ string_t *str, *name_str;
const char *name;
- string_t *str, *name_str;
int ret = 0;
-
- if (ctx->list_iter == NULL) {
- list_namespace_inbox(client, ctx);
- return 1;
- }
t_push();
str = t_str_new(256);
@@ -164,6 +253,7 @@ list_namespace_mailboxes(struct client *
}
}
name = str_c(name_str);
+ flags = info->flags;
if (*ctx->ns->prefix != '\0') {
/* With masks containing '*' we do the checks here
@@ -173,19 +263,32 @@ list_namespace_mailboxes(struct client *
continue;
}
if (strcasecmp(name, "INBOX") == 0) {
- if ((ctx->ns->flags & NAMESPACE_FLAG_INBOX) == 0)
+ i_assert((ctx->ns->flags & NAMESPACE_FLAG_INBOX) != 0);
+ if (ctx->inbox_found) {
+ /* we already listed this at the beginning
+ of handling INBOX/ namespace */
continue;
-
- name = "INBOX";
+ }
ctx->inbox_found = TRUE;
+ }
+ if (ctx->cur_ns_send_prefix)
+ list_namespace_send_prefix(ctx, TRUE);
+
+ /* if there's a namespace with this name, list it as
+ having children */
+ ns = mail_namespace_find_prefix_nosep(ctx->ns, name);
+ if (ns != NULL) {
+ flags |= MAILBOX_CHILDREN;
+ flags &= ~MAILBOX_NOCHILDREN;
+ array_append(&ctx->ns_prefixes_listed, &ns, 1);
}
str_truncate(str, 0);
str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
- mailbox_flags2str(str, info->flags, ctx->list_flags);
+ mailbox_flags2str(str, flags, ctx->list_flags);
str_printfa(str, ") \"%s\" ", ctx->ns->sep_str);
imap_quote_append_string(str, name, FALSE);
- if (client_send_line(client, str_c(str)) == 0) {
+ if (client_send_line(ctx->cmd->client, str_c(str)) == 0) {
/* buffer is full, continue later */
t_pop();
return 0;
@@ -194,9 +297,6 @@ list_namespace_mailboxes(struct client *
if (mailbox_list_iter_deinit(&ctx->list_iter) < 0)
ret = -1;
-
- if (ret == 0)
- list_namespace_inbox(client, ctx);
t_pop();
return ret < 0 ? -1 : 1;
@@ -297,8 +397,7 @@ skip_namespace_prefix_refmask(struct cmd
}
static enum imap_match_result
-list_use_inboxcase(struct client_command_context *cmd,
- struct cmd_list_context *ctx)
+list_use_inboxcase(struct cmd_list_context *ctx)
{
struct imap_match_glob *inbox_glob;
@@ -308,7 +407,7 @@ list_use_inboxcase(struct client_command
/* if the original reference and mask combined produces something
that matches INBOX, the INBOX casing is on. */
- inbox_glob = imap_match_init(cmd->pool,
+ inbox_glob = imap_match_init(ctx->cmd->pool,
t_strconcat(ctx->ref, ctx->mask, NULL),
TRUE, ctx->ns->sep);
return imap_match(inbox_glob, "INBOX");
@@ -349,29 +448,31 @@ skip_mask_wildcard_prefix(const char *cu
*cur_mask_p = cur_mask;
}
-static void
-list_namespace_init(struct client_command_context *cmd,
- struct cmd_list_context *ctx)
-{
- struct client *client = cmd->client;
+static void list_namespace_init(struct cmd_list_context *ctx)
+{
struct mail_namespace *ns = ctx->ns;
const char *cur_ns_prefix, *cur_ref, *cur_mask;
enum imap_match_result match;
enum imap_match_result inbox_match;
size_t len;
- cur_ns_prefix = ctx->ns->prefix;
+ cur_ns_prefix = ns->prefix;
cur_ref = ctx->ref;
cur_mask = ctx->mask;
+
+ ctx->cur_ns_skip_trailing_sep = FALSE;
+
+ if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0)
+ ctx->seen_inbox_namespace = TRUE;
More information about the dovecot-cvs
mailing list