dovecot-2.2: Moved most of the IMAP LIST code to lib-storage.
dovecot at dovecot.org
dovecot at dovecot.org
Thu Aug 30 21:12:40 EEST 2012
details: http://hg.dovecot.org/dovecot-2.2/rev/5ffcde8baa8a
changeset: 14986:5ffcde8baa8a
user: Timo Sirainen <tss at iki.fi>
date: Thu Aug 30 21:12:23 2012 +0300
description:
Moved most of the IMAP LIST code to lib-storage.
Also removed MAILBOX_LIST_ITER_SHOW_EXISTING_PARENT flag, since there wasn't
any clearly good way to handle it. Some clients got confused when they saw
that foo/ mailbox was returned with \Noselect flag. Either they thought that
the mailbox was named foo/ or that foo was \Noselect. Pretty much the only
sane way to handle this would be to not make return \Noselect and to treat
foo and foo/ as equivalent in all commands, but that might cause trouble
with ACLs and similar checks..
diffstat:
src/imap/cmd-list.c | 658 ++-------------------------
src/lib-storage/list/mailbox-list-fs-iter.c | 17 +-
src/lib-storage/mailbox-list-iter.c | 411 +++++++++++++---
src/lib-storage/mailbox-list.h | 4 -
4 files changed, 379 insertions(+), 711 deletions(-)
diffs (truncated from 1351 to 300 lines):
diff -r e4c09527aa9e -r 5ffcde8baa8a src/imap/cmd-list.c
--- a/src/imap/cmd-list.c Thu Aug 30 18:44:43 2012 +0300
+++ b/src/imap/cmd-list.c Thu Aug 30 21:12:23 2012 +0300
@@ -14,24 +14,15 @@
struct cmd_list_context {
struct client_command_context *cmd;
- const char *ref;
- const char *const *patterns;
+ struct mail_user *user;
+
enum mailbox_list_iter_flags list_flags;
struct imap_status_items status_items;
- enum mailbox_info_flags inbox_flags;
- struct mail_namespace *ns;
struct mailbox_list_iterate_context *list_iter;
- ARRAY(struct mail_namespace *) ns_prefixes_listed;
-
unsigned int lsub:1;
unsigned int lsub_no_unsubscribed:1;
- unsigned int inbox_found: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;
unsigned int used_listext:1;
unsigned int used_status:1;
};
@@ -164,90 +155,6 @@
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_USER) == 0) {
- /* INBOX doesn't exist. use the default INBOX flags */
- return flags;
- }
-
- /* find the INBOX flags */
- ns = mail_namespace_find_inbox(ctx->cmd->client->user->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->vname, "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)
-{
- enum mailbox_list_iter_flags list_flags =
- MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
- struct mailbox_list_iterate_context *list_iter;
- const struct mailbox_info *info;
- bool ret = FALSE;
-
- if ((ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0)
- list_flags |= MAILBOX_LIST_ITER_SELECT_SUBSCRIBED;
-
- list_iter = mailbox_list_iter_init(ctx->ns->list,
- t_strconcat(ctx->ns->prefix, "%", NULL), list_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 const char *ns_get_listed_prefix(struct cmd_list_context *ctx)
-{
- struct imap_match_glob *glob;
- enum imap_match_result match;
- const char *ns_prefix, *p;
- bool inboxcase;
- unsigned int skip_len;
-
- skip_len = strlen(ctx->ref);
- if (strncmp(ctx->ns->prefix, ctx->ref, skip_len) != 0)
- skip_len = 0;
-
- inboxcase = strncasecmp(ctx->ns->prefix, "INBOX", 5) == 0 &&
- ctx->ns->prefix[5] == mail_namespace_get_sep(ctx->ns);
- glob = imap_match_init_multiple(pool_datastack_create(),
- ctx->patterns, inboxcase,
- mail_namespace_get_sep(ctx->ns));
- ns_prefix = ctx->ns->prefix + skip_len;
- match = imap_match(glob, ns_prefix);
- if (match == IMAP_MATCH_YES) {
- return !ctx->cur_ns_skip_trailing_sep ? ctx->ns->prefix :
- t_strndup(ctx->ns->prefix, strlen(ctx->ns->prefix)-1);
- }
-
- while ((match & IMAP_MATCH_PARENT) != 0) {
- p = strrchr(ns_prefix, mail_namespace_get_sep(ctx->ns));
- i_assert(p != NULL);
- ns_prefix = t_strdup_until(ns_prefix, p);
- match = imap_match(glob, ns_prefix);
- }
- i_assert(match == IMAP_MATCH_YES);
- return t_strconcat(t_strndup(ctx->ns->prefix, skip_len),
- ns_prefix, NULL);
-}
-
static void list_reply_append_ns_sep_param(string_t *str, char sep)
{
str_append_c(str, '"');
@@ -259,101 +166,6 @@
}
static void
-list_namespace_send_prefix(struct cmd_list_context *ctx, bool have_children)
-{
- struct mail_namespace *const *listed;
- const struct mailbox_settings *mailbox_set;
- struct mailbox *box;
- enum mailbox_existence existence;
- unsigned int len;
- enum mailbox_info_flags flags;
- const char *name;
- string_t *str;
- bool same_ns, ends_with_sep;
- char ns_sep = mail_namespace_get_sep(ctx->ns);
-
- ctx->cur_ns_send_prefix = FALSE;
-
- /* see if we already listed this as a valid mailbox in another
- namespace */
- array_foreach(&ctx->ns_prefixes_listed, listed) {
- if (*listed == ctx->ns)
- return;
- }
-
- name = ns_get_listed_prefix(ctx);
- len = strlen(ctx->ns->prefix);
- ends_with_sep = ctx->ns->prefix[len-1] == ns_sep;
-
- /* we may be listing namespace's parent. in such case we always want to
- set the name as nonexistent. */
- same_ns = strcmp(name, ctx->ns->prefix) == 0 ||
- (strncmp(name, ctx->ns->prefix, len - 1) == 0 && ends_with_sep);
- if (len == 6 && strncasecmp(ctx->ns->prefix, "INBOX", len-1) == 0 &&
- ends_with_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 if (!same_ns) {
- /* parent */
- flags = MAILBOX_NONEXISTENT;
- } else {
- /* see if namespace prefix is selectable */
- box = mailbox_alloc(ctx->ns->list, name, 0);
- if (mailbox_exists(box, TRUE, &existence) == 0 &&
- existence == MAILBOX_EXISTENCE_SELECT)
- flags = MAILBOX_SELECT;
- else
- flags = MAILBOX_NONEXISTENT;
- mailbox_free(&box);
- }
-
- if ((flags & MAILBOX_CHILDREN) == 0) {
- if (have_children || list_namespace_has_children(ctx)) {
- flags |= MAILBOX_CHILDREN;
- flags &= ~MAILBOX_NOCHILDREN;
- } else {
- flags |= MAILBOX_NOCHILDREN;
- }
- }
-
- if ((ctx->ns->flags & NAMESPACE_FLAG_LIST_CHILDREN) != 0 ||
- (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 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. */
- }
-
- str = t_str_new(128);
- str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
- if (ctx->lsub)
- flags |= MAILBOX_NONEXISTENT;
- mailbox_set = (ctx->list_flags & MAILBOX_LIST_ITER_RETURN_SPECIALUSE) == 0 ? NULL :
- mailbox_settings_find(ctx->cmd->client->user, name);
- mailbox_flags2str(ctx, str, mailbox_set == NULL ? NULL :
- mailbox_set->special_use, flags);
- str_append(str, ") ");
- list_reply_append_ns_sep_param(str, ns_sep);
- str_append_c(str, ' ');
- imap_quote_append_string(str, name, FALSE);
- mailbox_childinfo2str(ctx, str, flags);
-
- client_send_line(ctx->cmd->client, str_c(str));
-}
-
-static void
list_send_status(struct cmd_list_context *ctx, const char *name,
const char *mutf7_name, enum mailbox_info_flags flags)
{
@@ -372,7 +184,7 @@
/* if we're listing subscriptions and there are subscriptions=no
namespaces, ctx->ns may not point to correct one */
- ns = mail_namespace_find(ctx->ns->user->namespaces, name);
+ ns = mail_namespace_find(ctx->user->namespaces, name);
if (imap_status_get(ctx->cmd, ns, name,
&ctx->status_items, &result) < 0) {
client_send_line(ctx->cmd->client,
@@ -384,71 +196,26 @@
&ctx->status_items, &result);
}
-static bool list_has_empty_prefix_ns(struct mail_user *user)
+static bool cmd_list_continue(struct client_command_context *cmd)
{
- struct mail_namespace *ns;
-
- ns = mail_namespace_find_prefix(user->namespaces, "");
- return ns != NULL && (ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
- NAMESPACE_FLAG_LIST_CHILDREN)) != 0;
-}
-
-static int
-list_namespace_mailboxes(struct cmd_list_context *ctx)
-{
+ struct cmd_list_context *ctx = cmd->context;
const struct mailbox_info *info;
- struct mail_namespace *ns;
enum mailbox_info_flags flags;
string_t *str, *mutf7_name;
const char *name;
int ret = 0;
+ if (cmd->cancel) {
+ if (ctx->list_iter != NULL)
+ (void)mailbox_list_iter_deinit(&ctx->list_iter);
+ return TRUE;
+ }
str = t_str_new(256);
mutf7_name = t_str_new(128);
while ((info = mailbox_list_iter_next(ctx->list_iter)) != NULL) {
name = info->vname;
flags = info->flags;
- if (strcasecmp(name, "INBOX") == 0) {
- if (ctx->inbox_found) {
- /* we already listed this at the beginning
- of handling INBOX/ namespace */
- continue;
- }
- if ((ctx->ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0) {
- /* INBOX is in non-empty prefix namespace,
- and we're now listing prefixless namespace
- that contains INBOX. There's no way we can
- show this mailbox. */
- ctx->inbox_flags = flags &
- (MAILBOX_CHILDREN|MAILBOX_NOCHILDREN);
- continue;
- }
-
- if (*info->ns->prefix != '\0' &&
- list_has_empty_prefix_ns(info->ns->user)) {
- /* INBOX is in its own namespace, while a
- namespace with prefix="" has its children. */
- flags &= ~(MAILBOX_CHILDREN|MAILBOX_NOCHILDREN|
- MAILBOX_NOINFERIORS);
- flags |= ctx->inbox_flags;
- }
- ctx->inbox_found = TRUE;
- }
- if (ctx->cur_ns_send_prefix)
- list_namespace_send_prefix(ctx, TRUE);
-
- /* if there's a list=yes namespace with this name, list it as
- having children */
- ns = mail_namespace_find_prefix_nosep(ctx->ns, name);
More information about the dovecot-cvs
mailing list