dovecot: Mailbox listing API changed to support more features. U...
dovecot at dovecot.org
dovecot at dovecot.org
Fri Jun 29 03:42:35 EEST 2007
details: http://hg.dovecot.org/dovecot/rev/1d73153584d2
changeset: 5829:1d73153584d2
user: Timo Sirainen <tss at iki.fi>
date: Fri Jun 29 03:39:27 2007 +0300
description:
Mailbox listing API changed to support more features. Used to implement
support for half of LIST-EXTENDED.
diffstat:
16 files changed, 296 insertions(+), 233 deletions(-)
src/imap/cmd-list.c | 172 +++++++++++++++-------
src/lib-storage/index/cydir/cydir-storage.c | 2
src/lib-storage/index/dbox/dbox-storage.c | 2
src/lib-storage/index/mbox/mbox-storage.c | 7
src/lib-storage/list/Makefile.am | 1
src/lib-storage/list/mailbox-list-fs-iter.c | 117 +++++++-------
src/lib-storage/list/mailbox-list-maildir-iter.c | 150 +++++++------------
src/lib-storage/list/mailbox-list-maildir.c | 3
src/lib-storage/mailbox-list.h | 36 +++-
src/lib-storage/mailbox-tree.c | 8 -
src/lib-storage/mailbox-tree.h | 3
src/plugins/acl/acl-backend-vfile-acllist.c | 4
src/plugins/acl/acl-mailbox-list.c | 14 -
src/plugins/convert/convert-storage.c | 6
src/plugins/quota/quota-count.c | 2
src/plugins/quota/quota-maildir.c | 2
diffs (truncated from 1060 to 300 lines):
diff -r 496b7dad3938 -r 1d73153584d2 src/imap/cmd-list.c
--- a/src/imap/cmd-list.c Thu Jun 28 22:34:59 2007 +0300
+++ b/src/imap/cmd-list.c Fri Jun 29 03:39:27 2007 +0300
@@ -9,11 +9,6 @@
#include "commands.h"
#include "mail-namespace.h"
-enum {
- _MAILBOX_LIST_ITER_HIDE_CHILDREN = 0x1000000,
- _MAILBOX_LIST_ITER_LISTEXT = 0x0800000
-};
-
struct cmd_list_context {
struct client_command_context *cmd;
const char *ref;
@@ -32,35 +27,44 @@ struct cmd_list_context {
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;
};
static void
-mailbox_flags2str(string_t *str, enum mailbox_info_flags flags,
- enum mailbox_list_flags list_flags)
+mailbox_flags2str(struct cmd_list_context *ctx, string_t *str,
+ enum mailbox_info_flags flags)
{
unsigned int orig_len = str_len(str);
- if ((flags & MAILBOX_NONEXISTENT) != 0 &&
- (list_flags & _MAILBOX_LIST_ITER_LISTEXT) == 0) {
+ if ((flags & MAILBOX_NONEXISTENT) != 0 && !ctx->used_listext) {
flags |= MAILBOX_NOSELECT;
flags &= ~MAILBOX_NONEXISTENT;
}
- if ((list_flags & _MAILBOX_LIST_ITER_HIDE_CHILDREN) != 0)
+ if ((ctx->list_flags & MAILBOX_LIST_ITER_RETURN_CHILDREN) == 0)
flags &= ~(MAILBOX_CHILDREN|MAILBOX_NOCHILDREN);
+
+ if ((flags & MAILBOX_SUBSCRIBED) != 0 &&
+ (ctx->list_flags & MAILBOX_LIST_ITER_RETURN_SUBSCRIBED) != 0)
+ str_append(str, "\\Subscribed ");
+
+ if ((flags & MAILBOX_CHILD_SUBSCRIBED) != 0 && !ctx->used_listext) {
+ /* LSUB uses \Noselect for this */
+ flags |= MAILBOX_NOSELECT;
+ }
if ((flags & MAILBOX_NOSELECT) != 0)
str_append(str, "\\Noselect ");
if ((flags & MAILBOX_NONEXISTENT) != 0)
str_append(str, "\\NonExistent ");
+
if ((flags & MAILBOX_CHILDREN) != 0)
str_append(str, "\\HasChildren ");
- else {
- if ((flags & MAILBOX_NOCHILDREN) != 0)
- str_append(str, "\\HasNoChildren ");
- if ((flags & MAILBOX_NOINFERIORS) != 0)
- str_append(str, "\\NoInferiors ");
- }
+ else if ((flags & MAILBOX_NOINFERIORS) != 0)
+ str_append(str, "\\NoInferiors ");
+ else if ((flags & MAILBOX_NOCHILDREN) != 0)
+ str_append(str, "\\HasNoChildren ");
+
if ((flags & MAILBOX_MARKED) != 0)
str_append(str, "\\Marked ");
if ((flags & MAILBOX_UNMARKED) != 0)
@@ -70,9 +74,20 @@ mailbox_flags2str(string_t *str, enum ma
str_truncate(str, str_len(str)-1);
}
+static void
+mailbox_childinfo2str(struct cmd_list_context *ctx, string_t *str,
+ enum mailbox_info_flags flags)
+{
+ if (!ctx->used_listext)
+ return;
+
+ if ((flags & MAILBOX_CHILD_SUBSCRIBED) != 0)
+ str_append(str, " (\"CHILDINFO\" (\"SUBSCRIBED\"))");
+}
+
static bool
-parse_list_flags(struct client_command_context *cmd, struct imap_arg *args,
- enum mailbox_list_flags *list_flags)
+parse_select_flags(struct client_command_context *cmd, struct imap_arg *args,
+ enum mailbox_list_flags *list_flags)
{
const char *atom;
@@ -85,15 +100,42 @@ parse_list_flags(struct client_command_c
atom = IMAP_ARG_STR(args);
+ if (strcasecmp(atom, "SUBSCRIBED") == 0) {
+ *list_flags |= MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
+ MAILBOX_LIST_ITER_RETURN_SUBSCRIBED;
+ } else if (strcasecmp(atom, "RECURSIVEMATCH") == 0)
+ *list_flags |= MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH;
+ args++;
+ }
+
+ if ((*list_flags & MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH) != 0 &&
+ (*list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) {
+ client_send_command_error(cmd,
+ "RECURSIVEMATCH must not be the only selection.");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static bool
+parse_return_flags(struct client_command_context *cmd, struct imap_arg *args,
+ enum mailbox_list_flags *list_flags)
+{
+ const char *atom;
+
+ while (args->type != IMAP_ARG_EOL) {
+ if (args->type != IMAP_ARG_ATOM) {
+ client_send_command_error(cmd,
+ "List options contains non-atoms.");
+ return FALSE;
+ }
+
+ atom = IMAP_ARG_STR(args);
+
if (strcasecmp(atom, "SUBSCRIBED") == 0)
- *list_flags |= MAILBOX_LIST_ITER_SUBSCRIBED;
+ *list_flags |= MAILBOX_LIST_ITER_RETURN_SUBSCRIBED;
else if (strcasecmp(atom, "CHILDREN") == 0)
- *list_flags |= MAILBOX_LIST_ITER_CHILDREN;
- else {
- client_send_tagline(cmd, t_strconcat(
- "BAD Invalid list option ", atom, NULL));
- return FALSE;
- }
+ *list_flags |= MAILBOX_LIST_ITER_RETURN_CHILDREN;
args++;
}
return TRUE;
@@ -132,7 +174,7 @@ static bool list_namespace_has_children(
bool ret = FALSE;
list_iter = mailbox_list_iter_init(ctx->ns->list, "%",
- MAILBOX_LIST_ITER_FAST_FLAGS);
+ MAILBOX_LIST_ITER_RETURN_NO_FLAGS);
info = mailbox_list_iter_next(list_iter);
if (info != NULL)
ret = TRUE;
@@ -185,15 +227,17 @@ list_namespace_send_prefix(struct cmd_li
flags |= MAILBOX_NOCHILDREN;
}
}
-
+
+ name = ctx->cur_ns_skip_trailing_sep ?
+ t_strndup(ctx->ns->prefix, len-1) : ctx->ns->prefix;
+
str = t_str_new(128);
str_append(str, "* LIST (");
- mailbox_flags2str(str, flags, ctx->list_flags);
+ mailbox_flags2str(ctx, str, 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);
+ mailbox_childinfo2str(ctx, str, flags);
+
client_send_line(ctx->cmd->client, str_c(str));
}
@@ -285,9 +329,11 @@ list_namespace_mailboxes(struct cmd_list
str_truncate(str, 0);
str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
- mailbox_flags2str(str, flags, ctx->list_flags);
+ mailbox_flags2str(ctx, str, flags);
str_printfa(str, ") \"%s\" ", ctx->ns->sep_str);
imap_quote_append_string(str, name, FALSE);
+ mailbox_childinfo2str(ctx, str, flags);
+
if (client_send_line(ctx->cmd->client, str_c(str)) == 0) {
/* buffer is full, continue later */
t_pop();
@@ -461,7 +507,7 @@ static void list_namespace_init(struct c
cur_mask = ctx->mask;
if ((ctx->ns->flags & NAMESPACE_FLAG_HIDDEN) != 0 &&
- (ctx->list_flags & MAILBOX_LIST_ITER_SUBSCRIBED) != 0) {
+ (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
/* ignore hidden namespaces */
return;
}
@@ -509,7 +555,8 @@ static void list_namespace_init(struct c
if (match == IMAP_MATCH_YES &&
(ns->flags & NAMESPACE_FLAG_LIST) != 0 &&
- (ctx->list_flags & MAILBOX_LIST_ITER_SUBSCRIBED) == 0)
+ (ctx->list_flags &
+ MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0)
ctx->cur_ns_send_prefix = TRUE;
}
@@ -555,7 +602,7 @@ static void list_inbox(struct cmd_list_c
/* INBOX always exists */
if (!ctx->inbox_found && ctx->cur_ns_match_inbox &&
(ctx->ns->flags & NAMESPACE_FLAG_INBOX) != 0 &&
- (ctx->list_flags & MAILBOX_LIST_ITER_SUBSCRIBED) == 0) {
+ (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) {
str = t_strdup_printf("* LIST (\\Unmarked) \"%s\" \"INBOX\"",
ctx->ns->sep_str);
client_send_line(ctx->cmd->client, str);
@@ -651,49 +698,70 @@ bool _cmd_list_full(struct client_comman
enum mailbox_list_flags list_flags;
struct cmd_list_context *ctx;
const char *ref, *mask;
-
- /* [(<options>)] <reference> <mailbox wildcards> */
+ bool used_listext = FALSE;
+
+ /* [(<selection options>)] <reference> <pattern>|(<pattern list>)
+ [RETURN (<return options>)] */
if (!client_read_args(cmd, 0, 0, &args))
return FALSE;
if (lsub) {
/* LSUB - we don't care about flags */
- list_flags = MAILBOX_LIST_ITER_SUBSCRIBED |
- MAILBOX_LIST_ITER_FAST_FLAGS |
- _MAILBOX_LIST_ITER_HIDE_CHILDREN;
+ list_flags = MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
+ MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH |
+ MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
} else if (args[0].type != IMAP_ARG_LIST) {
/* LIST - allow children flags, but don't require them */
- list_flags = 0;
+ list_flags = MAILBOX_LIST_ITER_RETURN_CHILDREN;
} else {
- list_flags =
- (enum mailbox_list_flags)_MAILBOX_LIST_ITER_LISTEXT;
- if (!parse_list_flags(cmd, IMAP_ARG_LIST(&args[0])->args,
- &list_flags))
+ /* LIST-EXTENDED extension */
+ used_listext = TRUE;
+
+ if (!parse_select_flags(cmd, IMAP_ARG_LIST(&args[0])->args,
+ &list_flags))
return TRUE;
args++;
- /* don't show children flags unless explicitly specified */
- if ((list_flags & MAILBOX_LIST_ITER_CHILDREN) == 0)
- list_flags |= _MAILBOX_LIST_ITER_HIDE_CHILDREN;
+ if (args[0].type == IMAP_ARG_EOL ||
+ args[1].type == IMAP_ARG_EOL) {
+ client_send_command_error(cmd, "Invalid arguments.");
+ return TRUE;
+ }
+
+ if (args[2].type == IMAP_ARG_ATOM &&
+ strcasecmp(imap_arg_string(&args[2]), "RETURN") == 0 &&
+ args[3].type == IMAP_ARG_LIST &&
+ args[4].type == IMAP_ARG_EOL) {
+ if (!parse_return_flags(cmd,
+ IMAP_ARG_LIST(&args[3])->args,
+ &list_flags))
+ return TRUE;
+ } else if (args[2].type != IMAP_ARG_EOL) {
+ client_send_command_error(cmd, "Invalid arguments.");
+ return TRUE;
+ }
}
ref = imap_arg_string(&args[0]);
- mask = imap_arg_string(&args[1]);
-
- if (ref == NULL || mask == NULL) {
+ mask = ref == NULL ? NULL : imap_arg_string(&args[1]);
+
+ if (ref == NULL || (mask == NULL && args[1].type != IMAP_ARG_LIST)) {
client_send_command_error(cmd, "Invalid arguments.");
return TRUE;
}
- if (*mask == '\0' && !lsub) {
+ if (mask != NULL && *mask == '\0' && !lsub) {
+ /* only with mask string, not with list */
cmd_list_ref_root(client, ref);
client_send_tagline(cmd, "OK List completed.");
} else {
+ /* FIXME: handle mask lists */
ctx = p_new(cmd->pool, struct cmd_list_context, 1);
ctx->cmd = cmd;
ctx->ref = ref;
ctx->mask = mask;
More information about the dovecot-cvs
mailing list