Mercurial > dovecot > original-hg > dovecot-1.2
changeset 1244:40bae47bdba1 HEAD
Added support for CHILDREN and LISTEXT extensions.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 24 Feb 2003 19:39:31 +0200 |
parents | 478471737964 |
children | 06b1b95ae756 |
files | configure.in src/imap/cmd-list.c src/imap/commands.h src/lib-storage/index/maildir/maildir-list.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/mbox/mbox-list.c src/lib-storage/mail-storage.h |
diffstat | 7 files changed, 172 insertions(+), 91 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.in Mon Feb 24 03:16:30 2003 +0200 +++ b/configure.in Mon Feb 24 19:39:31 2003 +0200 @@ -871,7 +871,7 @@ dnl ** capabilities dnl ** -capability="IMAP4rev1 SORT THREAD=REFERENCES MULTIAPPEND UNSELECT LITERAL+ IDLE" +capability="IMAP4rev1 SORT THREAD=REFERENCES MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN LISTEXT LIST-SUBSCRIBED" AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", IMAP capabilities) CFLAGS="$CFLAGS $EXTRA_CFLAGS"
--- a/src/imap/cmd-list.c Mon Feb 24 03:16:30 2003 +0200 +++ b/src/imap/cmd-list.c Mon Feb 24 19:39:31 2003 +0200 @@ -19,14 +19,36 @@ struct mail_storage *storage; }; -static const char *mailbox_flags2str(enum mailbox_flags flags) +struct list_send_context { + struct client *client; + const char *response_name; + const char *sep; + struct imap_match_glob *glob; + int listext; +}; + +static const char *mailbox_flags2str(enum mailbox_flags flags, int listext) { const char *str; - if (flags == MAILBOX_PLACEHOLDER) - flags = MAILBOX_NOSELECT; + if (flags & MAILBOX_PLACEHOLDER) { + if (flags == MAILBOX_PLACEHOLDER) { + if (!listext) + flags = MAILBOX_NOSELECT; + } else { + /* it was at one point, but then we got better specs */ + flags &= ~MAILBOX_PLACEHOLDER; + } + flags |= MAILBOX_CHILDREN; + } + if ((flags & MAILBOX_NONEXISTENT) != 0 && !listext) + flags |= MAILBOX_NOSELECT; str = t_strconcat((flags & MAILBOX_NOSELECT) ? " \\Noselect" : "", + (flags & MAILBOX_NONEXISTENT) ? " \\NonExistent" : "", + (flags & MAILBOX_PLACEHOLDER) ? " \\PlaceHolder" : "", + (flags & MAILBOX_CHILDREN) ? " \\Children" : "", + (flags & MAILBOX_NOCHILDREN) ? " \\NoChildren" : "", (flags & MAILBOX_NOINFERIORS) ? " \\NoInferiors" : "", (flags & MAILBOX_MARKED) ? " \\Marked" : "", (flags & MAILBOX_UNMARKED) ? " \\UnMarked" : "", @@ -35,8 +57,9 @@ return *str == '\0' ? "" : str+1; } -static struct list_node *list_node_get(pool_t pool, struct list_node **node, - const char *path, char separator) +static void list_node_update(pool_t pool, struct list_node **node, + const char *path, char separator, + enum mailbox_flags flags) { const char *name, *parent; @@ -64,7 +87,11 @@ /* not found, create it */ *node = p_new(pool, struct list_node, 1); (*node)->name = p_strdup(pool, name); - (*node)->flags = MAILBOX_PLACEHOLDER; + (*node)->flags = *path == '\0' ? + flags : MAILBOX_PLACEHOLDER; + } else { + if (*path == '\0') + (*node)->flags |= flags; } t_pop(); @@ -76,15 +103,12 @@ parent = (*node)->name; node = &(*node)->children; } - - return *node; } -static void list_send(struct client *client, struct list_node *node, - const char *cmd, const char *path, const char *sep, - struct imap_match_glob *glob) +static void list_send(struct list_send_context *ctx, struct list_node *node, + const char *path) { - const char *name, *send_name, *str; + const char *name, *send_name, *str, *flagstr; enum imap_match_result match; for (; node != NULL; node = node->next) { @@ -92,7 +116,7 @@ /* Send INBOX always uppercased */ if (path != NULL) - name = t_strconcat(path, sep, node->name, NULL); + name = t_strconcat(path, ctx->sep, node->name, NULL); else if (strcasecmp(node->name, "INBOX") == 0) name = "INBOX"; else @@ -106,24 +130,25 @@ const char *buf; buf = str_unescape(t_strdup_noconst(name)); - match = imap_match(glob, buf); + match = imap_match(ctx->glob, buf); if (match == IMAP_MATCH_CHILDREN) { - send_name = t_strconcat(name, sep, NULL); + send_name = t_strconcat(name, ctx->sep, NULL); buf = str_unescape(t_strdup_noconst(send_name)); - match = imap_match(glob, buf); + match = imap_match(ctx->glob, buf); } } if (match == IMAP_MATCH_YES) { /* node->name should already be escaped */ - str = t_strdup_printf("* %s (%s) \"%s\" \"%s\"", cmd, - mailbox_flags2str(node->flags), - sep, send_name); - client_send_line(client, str); + flagstr = mailbox_flags2str(node->flags, ctx->listext); + str = t_strdup_printf("* %s (%s) \"%s\" \"%s\"", + ctx->response_name, flagstr, + ctx->sep, send_name); + client_send_line(ctx->client, str); } if (node->children != NULL) - list_send(client, node->children, cmd, name, sep, glob); + list_send(ctx, node->children, name); t_pop(); } @@ -131,32 +156,38 @@ static void list_and_sort(struct client *client, struct mailbox_list_context *ctx, - const char *cmd, const char *sep, const char *mask) + const char *response_name, + const char *sep, const char *mask, int listext) { struct mailbox_list *list; - struct list_node *nodes, *node; - struct imap_match_glob *glob; + struct list_node *nodes; + struct list_send_context send_ctx; pool_t pool; pool = pool_alloconly_create("list_mailboxes", 10240); nodes = NULL; while ((list = client->storage->list_mailbox_next(ctx)) != NULL) { - node = list_node_get(pool, &nodes, list->name, - client->storage->hierarchy_sep); - node->flags |= list->flags; + list_node_update(pool, &nodes, list->name, + client->storage->hierarchy_sep, + list->flags); } - glob = imap_match_init(data_stack_pool, mask, TRUE, - client->storage->hierarchy_sep); - list_send(client, nodes, cmd, NULL, sep, glob); - imap_match_deinit(glob); + send_ctx.client = client; + send_ctx.response_name = response_name; + send_ctx.sep = sep; + send_ctx.glob = imap_match_init(data_stack_pool, mask, TRUE, + client->storage->hierarchy_sep); + send_ctx.listext = listext; + + list_send(&send_ctx, nodes, NULL); + imap_match_deinit(send_ctx.glob); pool_unref(pool); } static void list_unsorted(struct client *client, struct mailbox_list_context *ctx, - const char *cmd, const char *sep) + const char *reply, const char *sep, int listext) { struct mailbox_list *list; const char *name, *str; @@ -167,42 +198,50 @@ name = "INBOX"; else name = str_escape(list->name); - str = t_strdup_printf("* %s (%s) \"%s\" \"%s\"", cmd, - mailbox_flags2str(list->flags), + str = t_strdup_printf("* %s (%s) \"%s\" \"%s\"", reply, + mailbox_flags2str(list->flags, listext), sep, name); client_send_line(client, str); t_pop(); } } -static int list_mailboxes(struct client *client, const char *mask, - int subscribed, const char *sep) +static int parse_list_flags(struct client *client, struct imap_arg *args, + enum mailbox_list_flags *list_flags) { - struct mailbox_list_context *ctx; - const char *cmd; - int sorted; + const char *atom; + + while (args->type != IMAP_ARG_EOL) { + if (args->type != IMAP_ARG_ATOM) { + client_send_command_error(client, + "List options contains non-atoms."); + return FALSE; + } - ctx = client->storage-> - list_mailbox_init(client->storage, mask, - subscribed ? MAILBOX_LIST_SUBSCRIBED : 0, - &sorted); - if (ctx == NULL) - return FALSE; + atom = IMAP_ARG_STR(args); - cmd = subscribed ? "LSUB" : "LIST"; - if (sorted) - list_unsorted(client, ctx, cmd, sep); - else - list_and_sort(client, ctx, cmd, sep, mask); - - return client->storage->list_mailbox_deinit(ctx); + if (strcasecmp(atom, "SUBSCRIBED") == 0) + *list_flags |= MAILBOX_LIST_SUBSCRIBED; + else if (strcasecmp(atom, "CHILDREN") == 0) + *list_flags |= MAILBOX_LIST_CHILDREN; + else { + client_send_tagline(client, t_strconcat( + "BAD Invalid list option ", atom, NULL)); + return FALSE; + } + args++; + } + return TRUE; } -int _cmd_list_full(struct client *client, int subscribed) +int _cmd_list_full(struct client *client, int lsub) { + struct imap_arg *args; + enum mailbox_list_flags list_flags; + struct mailbox_list_context *ctx; const char *ref, *mask; char sep_chr, sep[3]; - int failed; + int failed, sorted, listext; sep_chr = client->storage->hierarchy_sep; if (IS_ESCAPED_CHAR(sep_chr)) { @@ -214,11 +253,34 @@ sep[1] = '\0'; } - /* <reference> <mailbox wildcards> */ - if (!client_read_string_args(client, 2, &ref, &mask)) + /* [(<options>)] <reference> <mailbox wildcards> */ + if (!client_read_args(client, 0, 0, &args)) return FALSE; - if (*mask == '\0' && !subscribed) { + listext = FALSE; + if (lsub) + list_flags = MAILBOX_LIST_SUBSCRIBED | MAILBOX_LIST_FAST_FLAGS; + else { + list_flags = 0; + if (args[0].type == IMAP_ARG_LIST) { + listext = TRUE; + if (!parse_list_flags(client, + IMAP_ARG_LIST(&args[0])->args, + &list_flags)) + return TRUE; + args++; + } + } + + ref = imap_arg_string(&args[0]); + mask = imap_arg_string(&args[1]); + + if (ref == NULL || mask == NULL) { + client_send_command_error(client, "Invalid FETCH arguments."); + return TRUE; + } + + if (*mask == '\0' && !lsub) { /* special request to return the hierarchy delimiter */ client_send_line(client, t_strconcat( "* LIST (\\Noselect) \"", sep, "\" \"\"", NULL)); @@ -240,13 +302,29 @@ } } - failed = !list_mailboxes(client, mask, subscribed, sep); + ctx = client->storage->list_mailbox_init(client->storage, mask, + list_flags, &sorted); + if (ctx == NULL) + failed = TRUE; + else { + const char *response_name = lsub ? "LSUB" : "LIST"; + + if (sorted) { + list_unsorted(client, ctx, response_name, sep, + listext); + } else { + list_and_sort(client, ctx, response_name, sep, + mask, listext); + } + + failed = !client->storage->list_mailbox_deinit(ctx); + } } if (failed) client_send_storage_error(client); else { - client_send_tagline(client, subscribed ? + client_send_tagline(client, lsub ? "OK Lsub completed." : "OK List completed."); }
--- a/src/imap/commands.h Mon Feb 24 03:16:30 2003 +0200 +++ b/src/imap/commands.h Mon Feb 24 19:39:31 2003 +0200 @@ -47,7 +47,7 @@ int cmd_idle(struct client *client); /* private: */ -int _cmd_list_full(struct client *client, int subscribed); +int _cmd_list_full(struct client *client, int lsub); int _cmd_select_full(struct client *client, int readonly); int _cmd_subscribe_full(struct client *client, int subscribe);
--- a/src/lib-storage/index/maildir/maildir-list.c Mon Feb 24 03:16:30 2003 +0200 +++ b/src/lib-storage/index/maildir/maildir-list.c Mon Feb 24 19:39:31 2003 +0200 @@ -147,9 +147,6 @@ ctx->list.flags = 0; ctx->list.name = name; - if ((ctx->flags & MAILBOX_LIST_NO_FLAGS) != 0) - return &ctx->list; - if (match == IMAP_MATCH_PARENT) { /* placeholder */ ctx->list.flags = MAILBOX_PLACEHOLDER; @@ -163,6 +160,9 @@ i_unreached(); } + if ((ctx->flags & MAILBOX_LIST_FAST_FLAGS) != 0) + return &ctx->list; + t_push(); path = maildir_get_path(ctx->storage, ctx->list.name); if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) @@ -171,7 +171,7 @@ if (strcasecmp(ctx->list.name, "INBOX") == 0) ctx->list.flags = 0; else - ctx->list.flags = MAILBOX_NOSELECT; + ctx->list.flags = MAILBOX_NONEXISTENT; } t_pop(); return &ctx->list; @@ -253,8 +253,8 @@ } p_clear(ctx->list_pool); - if ((ctx->flags & MAILBOX_LIST_NO_FLAGS) == 0) - ctx->list.flags = maildir_get_marked_flags(path); + ctx->list.flags = (ctx->flags & MAILBOX_LIST_FAST_FLAGS) == 0 ? + maildir_get_marked_flags(path) : 0; ctx->list.name = p_strconcat(ctx->list_pool, ctx->prefix, fname, NULL); return &ctx->list; @@ -270,7 +270,8 @@ if (imap_match(ctx->glob, "INBOX") > 0) { const char *path = maildir_get_path(ctx->storage, "INBOX"); - ctx->list.flags = maildir_get_marked_flags(path); + ctx->list.flags = (ctx->flags & MAILBOX_LIST_FAST_FLAGS) == 0 ? + maildir_get_marked_flags(path) : 0; ctx->list.name = "INBOX"; return &ctx->list; }
--- a/src/lib-storage/index/maildir/maildir-storage.c Mon Feb 24 03:16:30 2003 +0200 +++ b/src/lib-storage/index/maildir/maildir-storage.c Mon Feb 24 19:39:31 2003 +0200 @@ -416,7 +416,7 @@ ctx = storage->list_mailbox_init(storage, t_strconcat(oldname, ".*", NULL), - MAILBOX_LIST_NO_FLAGS, &sorted); + MAILBOX_LIST_FAST_FLAGS, &sorted); while ((list = maildir_list_mailbox_next(ctx)) != NULL) { i_assert(oldnamelen <= strlen(list->name));
--- a/src/lib-storage/index/mbox/mbox-list.c Mon Feb 24 03:16:30 2003 +0200 +++ b/src/lib-storage/index/mbox/mbox-list.c Mon Feb 24 19:39:31 2003 +0200 @@ -233,13 +233,13 @@ path = t_strconcat(list_path, "/", NULL); match2 = imap_match(ctx->glob, path); - if (match > 0) { - ctx->list.flags = MAILBOX_NOSELECT; + ctx->list.flags = MAILBOX_NOSELECT | MAILBOX_CHILDREN; + if (match > 0) ctx->list.name = p_strdup(ctx->list_pool, list_path); - } else if (match2 > 0) { - ctx->list.flags = MAILBOX_NOSELECT; + else if (match2 > 0) ctx->list.name = p_strdup(ctx->list_pool, path); - } + else + ctx->list.name = NULL; ret = match2 < 0 ? 0 : list_opendir(ctx->storage, real_path, FALSE, &dirp); @@ -286,9 +286,6 @@ ctx->list.flags = 0; ctx->list.name = name; - if ((ctx->flags & MAILBOX_LIST_NO_FLAGS) != 0) - return &ctx->list; - if (match == IMAP_MATCH_PARENT) { /* placeholder */ ctx->list.flags = MAILBOX_PLACEHOLDER; @@ -302,11 +299,14 @@ i_unreached(); } + if ((ctx->flags & MAILBOX_LIST_FAST_FLAGS) != 0) + return &ctx->list; + t_push(); path = mbox_get_path(ctx->storage, ctx->list.name); if (stat(path, &st) == 0) { if (S_ISDIR(st.st_mode)) - ctx->list.flags = MAILBOX_NOSELECT; + ctx->list.flags = MAILBOX_NOSELECT | MAILBOX_CHILDREN; else { ctx->list.flags = MAILBOX_NOINFERIORS | STAT_GET_MARKED(st); @@ -315,7 +315,7 @@ if (strcasecmp(ctx->list.name, "INBOX") == 0) ctx->list.flags = MAILBOX_UNMARKED; else - ctx->list.flags = MAILBOX_NOSELECT; + ctx->list.flags = MAILBOX_NONEXISTENT; } t_pop(); return &ctx->list; @@ -332,7 +332,7 @@ /* INBOX exists always, even if the file doesn't. */ ctx->list.flags = MAILBOX_NOINFERIORS; - if ((ctx->flags & MAILBOX_LIST_NO_FLAGS) == 0) { + if ((ctx->flags & MAILBOX_LIST_FAST_FLAGS) == 0) { if (stat(ctx->storage->inbox_file, &st) < 0) ctx->list.flags |= MAILBOX_UNMARKED; else @@ -347,7 +347,7 @@ { ctx->next = mbox_list_next; - ctx->list.flags = MAILBOX_NOSELECT; + ctx->list.flags = MAILBOX_NOSELECT | MAILBOX_CHILDREN; ctx->list.name = p_strconcat(ctx->list_pool, ctx->dir->virtual_path, "/", NULL);
--- a/src/lib-storage/mail-storage.h Mon Feb 24 03:16:30 2003 +0200 +++ b/src/lib-storage/mail-storage.h Mon Feb 24 19:39:31 2003 +0200 @@ -6,20 +6,22 @@ #include "imap-util.h" enum mailbox_list_flags { - MAILBOX_LIST_SUBSCRIBED = 0x01, /* show only subscribed */ - MAILBOX_LIST_NO_FLAGS = 0x02 /* don't set mailbox_flags */ + MAILBOX_LIST_SUBSCRIBED = 0x01, + MAILBOX_LIST_FAST_FLAGS = 0x02, + MAILBOX_LIST_CHILDREN = 0x04 }; enum mailbox_flags { - MAILBOX_NOSELECT = 0x01, - MAILBOX_CHILDREN = 0x02, - MAILBOX_NOCHILDREN = 0x04, - MAILBOX_NOINFERIORS = 0x08, - MAILBOX_MARKED = 0x10, - MAILBOX_UNMARKED = 0x20, - MAILBOX_PLACEHOLDER = 0x40, + MAILBOX_NOSELECT = 0x001, + MAILBOX_NONEXISTENT = 0x002, + MAILBOX_PLACEHOLDER = 0x004, + MAILBOX_CHILDREN = 0x008, + MAILBOX_NOCHILDREN = 0x010, + MAILBOX_NOINFERIORS = 0x020, + MAILBOX_MARKED = 0x040, + MAILBOX_UNMARKED = 0x080, - MAILBOX_READONLY = 0x40 + MAILBOX_READONLY = 0x100 }; enum mailbox_status_items {