Mercurial > dovecot > core-2.2
changeset 12588:1b8fb4ff2bb3
imapc: Added support for LIST/LSUB.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 20 Jan 2011 22:45:41 +0200 |
parents | c3a258ee96c4 |
children | 2fd54529e7d6 |
files | src/lib-storage/index/imapc/Makefile.am src/lib-storage/index/imapc/imapc-list.c src/lib-storage/index/imapc/imapc-list.h src/lib-storage/index/imapc/imapc-storage.c src/lib-storage/index/imapc/imapc-storage.h src/lib-storage/register/Makefile.am |
diffstat | 6 files changed, 406 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/imapc/Makefile.am Thu Jan 20 22:44:53 2011 +0200 +++ b/src/lib-storage/index/imapc/Makefile.am Thu Jan 20 22:45:41 2011 +0200 @@ -12,6 +12,7 @@ libstorage_imapc_la_SOURCES = \ imapc-client.c \ imapc-connection.c \ + imapc-list.c \ imapc-mail.c \ imapc-save.c \ imapc-search.c \ @@ -21,6 +22,7 @@ headers = \ imapc-connection.h \ + imapc-list.h \ imapc-seqmap.h \ imapc-storage.h \ imapc-sync.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/imapc/imapc-list.c Thu Jan 20 22:45:41 2011 +0200 @@ -0,0 +1,357 @@ +/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "imap-arg.h" +#include "imap-match.h" +#include "mailbox-tree.h" +#include "imapc-client.h" +#include "imapc-storage.h" +#include "imapc-list.h" + +struct imapc_mailbox_list_iterate_context { + struct mailbox_list_iterate_context ctx; + struct mailbox_tree_iterate_context *iter; + struct imap_match_glob *glob; + struct mailbox_info info; + bool failed; +}; + +extern struct mailbox_list imapc_mailbox_list; + +static struct mailbox_list *imapc_list_alloc(void) +{ + struct imapc_mailbox_list *list; + pool_t pool; + + pool = pool_alloconly_create("imapc mailbox list", 1024); + list = p_new(pool, struct imapc_mailbox_list, 1); + list->list = imapc_mailbox_list; + list->list.pool = pool; + return &list->list; +} + +static void imapc_list_deinit(struct mailbox_list *_list) +{ + struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list; + + if (list->mailboxes != NULL) + mailbox_tree_deinit(&list->mailboxes); + if (list->subscriptions != NULL) + mailbox_tree_deinit(&list->subscriptions); + pool_unref(&list->list.pool); +} + +static struct mailbox_node * +imapc_list_update_tree(struct mailbox_tree_context *tree, + const struct imap_arg *args) +{ + struct mailbox_node *node; + const struct imap_arg *flags; + const char *name, *flag; + enum mailbox_info_flags info_flags = 0; + bool created; + + if (!imap_arg_get_list(&args[0], &flags) || + args[1].type == IMAP_ARG_EOL || + !imap_arg_get_astring(&args[2], &name)) + return NULL; + + while (imap_arg_get_atom(flags, &flag)) { + if (strcasecmp(flag, "\\NoSelect") == 0) + info_flags |= MAILBOX_NOSELECT; + else if (strcasecmp(flag, "\\NonExistent") == 0) + info_flags |= MAILBOX_NONEXISTENT; + else if (strcasecmp(flag, "\\NoInferiors") == 0) + info_flags |= MAILBOX_NOINFERIORS; + else if (strcasecmp(flag, "\\Subscribed") == 0) + info_flags |= MAILBOX_SUBSCRIBED; + flags++; + } + + if ((info_flags & MAILBOX_NONEXISTENT) != 0) + node = mailbox_tree_lookup(tree, name); + else + node = mailbox_tree_get(tree, name, &created); + if (node != NULL) + node->flags = info_flags; + return node; +} + +void imapc_list_update_mailbox(struct imapc_mailbox_list *list, + const struct imap_arg *args) +{ + const char *sep, *name; + + if (list->sep == '\0') { + /* we haven't asked for the separator yet. + lets see if this is the reply for its request. */ + if (args[0].type == IMAP_ARG_EOL || + !imap_arg_get_nstring(&args[1], &sep) || + !imap_arg_get_astring(&args[2], &name) || *name != '\0') + return; + + /* we can't handle NIL separator yet */ + list->sep = sep == NULL ? '/' : sep[0]; + return; + } + if (list->mailboxes == NULL) + list->mailboxes = mailbox_tree_init(list->sep); + (void)imapc_list_update_tree(list->mailboxes, args); +} + +void imapc_list_update_subscription(struct imapc_mailbox_list *list, + const struct imap_arg *args) +{ + struct mailbox_node *node; + + if (list->sep == '\0') { + /* we haven't asked for the separator yet */ + return; + } + if (list->subscriptions == NULL) + list->subscriptions = mailbox_tree_init(list->sep); + node = imapc_list_update_tree(list->subscriptions, args); + if (node != NULL) + node->flags |= MAILBOX_SUBSCRIBED; +} + +static int imapc_list_refresh(struct imapc_mailbox_list *list, + enum mailbox_list_iter_flags flags) +{ + struct imapc_simple_context ctx; + + ctx.storage = list->storage; + if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) { + imapc_client_cmdf(list->storage->client, + imapc_simple_callback, &ctx, "LIST \"\" *"); + if (list->mailboxes != NULL) + mailbox_tree_deinit(&list->mailboxes); + } else { + imapc_client_cmdf(list->storage->client, + imapc_simple_callback, &ctx, "LSUB \"\" *"); + if (list->subscriptions != NULL) + mailbox_tree_deinit(&list->subscriptions); + } + + imapc_client_run(list->storage->client); + return ctx.ret; +} + +static bool +imapc_is_valid_pattern(struct mailbox_list *list, const char *pattern) +{ + return TRUE; +} + +static bool +imapc_is_valid_existing_name(struct mailbox_list *list, const char *name) +{ + return TRUE; +} + +static bool +imapc_is_valid_create_name(struct mailbox_list *list, const char *name) +{ + return TRUE; +} + +static char imapc_list_get_hierarchy_sep(struct mailbox_list *_list) +{ + struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list; + struct imapc_simple_context ctx; + + if (list->sep == '\0') { + ctx.storage = list->storage; + imapc_client_cmdf(list->storage->client, + imapc_simple_callback, &ctx, + "LIST \"\" \"\""); + imapc_client_run(list->storage->client); + if (ctx.ret < 0) { + list->broken = TRUE; + return '/'; + } + } + return list->sep; +} + +static const char * +imapc_list_get_path(struct mailbox_list *list, const char *name, + enum mailbox_list_path_type type) +{ + if (type == MAILBOX_LIST_PATH_TYPE_INDEX) + return ""; + return NULL; +} + +static const char * +imapc_list_get_temp_prefix(struct mailbox_list *list, bool global ATTR_UNUSED) +{ + i_panic("imapc: Can't return a temp prefix for '%s'", + list->ns->prefix); + return NULL; +} + +static const char * +imapc_list_join_refpattern(struct mailbox_list *list ATTR_UNUSED, + const char *ref, const char *pattern) +{ + return t_strconcat(ref, pattern, NULL); +} + +static struct mailbox_list_iterate_context * +imapc_list_iter_init(struct mailbox_list *_list, const char *const *patterns, + enum mailbox_list_iter_flags flags) +{ + struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list; + struct imapc_mailbox_list_iterate_context *ctx; + struct mailbox_tree_context *tree; + char sep; + + sep = mailbox_list_get_hierarchy_sep(_list); + + ctx = i_new(struct imapc_mailbox_list_iterate_context, 1); + ctx->ctx.list = _list; + ctx->ctx.flags = flags; + ctx->info.ns = _list->ns; + ctx->glob = imap_match_init_multiple(default_pool, patterns, + FALSE, sep); + if (imapc_list_refresh(list, flags) < 0) + ctx->failed = TRUE; + else { + tree = (flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0 ? + list->subscriptions : list->mailboxes; + ctx->iter = mailbox_tree_iterate_init(tree, NULL, 0); + } + return &ctx->ctx; +} + +static const struct mailbox_info * +imapc_list_iter_next(struct mailbox_list_iterate_context *_ctx) +{ + struct imapc_mailbox_list_iterate_context *ctx = + (struct imapc_mailbox_list_iterate_context *)_ctx; + struct mailbox_node *node; + const char *name; + + if (ctx->failed) + return NULL; + + while ((node = mailbox_tree_iterate_next(ctx->iter, &name)) != NULL) { + if (imap_match(ctx->glob, name) == IMAP_MATCH_YES) { + ctx->info.flags &= ~(MAILBOX_CHILDREN | + MAILBOX_NOCHILDREN); + if (node->children == NULL) + ctx->info.flags |= MAILBOX_NOCHILDREN; + else + ctx->info.flags |= MAILBOX_CHILDREN; + ctx->info.name = name; + return &ctx->info; + } + } + return NULL; +} + +static int imapc_list_iter_deinit(struct mailbox_list_iterate_context *_ctx) +{ + struct imapc_mailbox_list_iterate_context *ctx = + (struct imapc_mailbox_list_iterate_context *)_ctx; + int ret = ctx->failed ? -1 : 0; + + if (ctx->iter != NULL) + mailbox_tree_iterate_deinit(&ctx->iter); + imap_match_deinit(&ctx->glob); + i_free(ctx); + return ret; +} + +static int imapc_list_set_subscribed(struct mailbox_list *_list, + const char *name, bool set) +{ + struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list; + struct imapc_simple_context ctx; + + ctx.storage = list->storage; + imapc_client_cmdf(list->storage->client, + imapc_simple_callback, &ctx, + set ? "SUBSCRIBE %s" : "UNSUBSCRIBE %s", name); + imapc_client_run(list->storage->client); + return ctx.ret; +} + +static int +imapc_list_create_mailbox_dir(struct mailbox_list *list, const char *name, + enum mailbox_dir_create_type type) +{ + return -1; +} + +static int +imapc_list_delete_mailbox(struct mailbox_list *list, const char *name) +{ + return -1; +} + +static int +imapc_list_delete_dir(struct mailbox_list *list, const char *name) +{ + return -1; +} + +static int +imapc_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname, + struct mailbox_list *newlist, const char *newname, + bool rename_children) +{ + struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)oldlist; + struct imapc_simple_context ctx; + + if (!rename_children) { + mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE, + "Renaming without children not supported."); + return -1; + } + + if (oldlist != newlist) { + mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE, + "Can't rename mailboxes across storages."); + return -1; + } + + ctx.storage = list->storage; + imapc_client_cmdf(list->storage->client, + imapc_simple_callback, &ctx, + "RENAME %s %s", oldname, newname); + imapc_client_run(list->storage->client); + return ctx.ret; +} + +struct mailbox_list imapc_mailbox_list = { + .name = MAILBOX_LIST_NAME_IMAPC, + .props = 0, + .mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH, + + { + imapc_list_alloc, + imapc_list_deinit, + NULL, + imapc_is_valid_pattern, + imapc_is_valid_existing_name, + imapc_is_valid_create_name, + imapc_list_get_hierarchy_sep, + mailbox_list_default_get_vname, + mailbox_list_default_get_storage_name, + imapc_list_get_path, + imapc_list_get_temp_prefix, + imapc_list_join_refpattern, + imapc_list_iter_init, + imapc_list_iter_next, + imapc_list_iter_deinit, + NULL, + NULL, + imapc_list_set_subscribed, + imapc_list_create_mailbox_dir, + imapc_list_delete_mailbox, + imapc_list_delete_dir, + imapc_list_rename_mailbox + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/imapc/imapc-list.h Thu Jan 20 22:45:41 2011 +0200 @@ -0,0 +1,27 @@ +#ifndef IMAPC_LIST_H +#define IMAPC_LIST_H + +struct imap_arg; + +#include "mailbox-list-private.h" + +#define MAILBOX_LIST_NAME_IMAPC "imapc" + +struct imapc_mailbox_list { + struct mailbox_list list; + struct imapc_storage *storage; + + struct mailbox_tree_context *mailboxes, *subscriptions; + char sep; + + /* we've returned wrong separator. all mailbox list operations must + fail from now on. */ + unsigned int broken:1; +}; + +void imapc_list_update_mailbox(struct imapc_mailbox_list *list, + const struct imap_arg *args); +void imapc_list_update_subscription(struct imapc_mailbox_list *list, + const struct imap_arg *args); + +#endif
--- a/src/lib-storage/index/imapc/imapc-storage.c Thu Jan 20 22:44:53 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-storage.c Thu Jan 20 22:45:41 2011 +0200 @@ -9,6 +9,7 @@ #include "index-mail.h" #include "mailbox-list-private.h" #include "imapc-client.h" +#include "imapc-list.h" #include "imapc-seqmap.h" #include "imapc-sync.h" #include "imapc-storage.h" @@ -17,11 +18,6 @@ #define DNS_CLIENT_SOCKET_NAME "dns-client" -struct imapc_simple_context { - struct imapc_storage *storage; - int ret; -}; - struct imapc_open_context { struct imapc_mailbox *mbox; int ret; @@ -108,9 +104,8 @@ } } -static void -imapc_simple_callback(const struct imapc_command_reply *reply, - void *context) +void imapc_simple_callback(const struct imapc_command_reply *reply, + void *context) { struct imapc_simple_context *ctx = context; @@ -232,6 +227,11 @@ struct imapc_seqmap *seqmap; uint32_t lseq; + if (strcasecmp(reply->name, "LIST") == 0) + imapc_list_update_mailbox(storage->list, reply->args); + else if (strcasecmp(reply->name, "LSUB") == 0) + imapc_list_update_subscription(storage->list, reply->args); + if (mbox == NULL) return; @@ -283,6 +283,8 @@ set.dns_client_socket_path = t_strconcat(_storage->user->set->base_dir, "/", DNS_CLIENT_SOCKET_NAME, NULL); + storage->list = (struct imapc_list *)ns->list; + storage->list->storage = storage; storage->client = imapc_client_init(&set); imapc_client_register_untagged(storage->client, imapc_storage_untagged_cb, storage); @@ -300,7 +302,7 @@ imapc_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED, struct mailbox_list_settings *set) { - set->layout = "none"; + set->layout = MAILBOX_LIST_NAME_IMAPC; } static struct mailbox *
--- a/src/lib-storage/index/imapc/imapc-storage.h Thu Jan 20 22:44:53 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-storage.h Thu Jan 20 22:45:41 2011 +0200 @@ -10,6 +10,7 @@ struct imapc_storage { struct mail_storage storage; + struct imapc_mailbox_list *list; struct imapc_client *client; }; @@ -26,6 +27,11 @@ unsigned int new_msgs:1; }; +struct imapc_simple_context { + struct imapc_storage *storage; + int ret; +}; + extern struct mail_vfuncs imapc_mail_vfuncs; struct mail_save_context * @@ -48,6 +54,8 @@ struct mail *mail, bool *tryagain_r); void imapc_fetch_mail_update(struct mail *mail, const struct imap_arg *args); +void imapc_simple_callback(const struct imapc_command_reply *reply, + void *context); void imapc_async_stop_callback(const struct imapc_command_reply *reply, void *context);
--- a/src/lib-storage/register/Makefile.am Thu Jan 20 22:44:53 2011 +0200 +++ b/src/lib-storage/register/Makefile.am Thu Jan 20 22:45:41 2011 +0200 @@ -2,7 +2,7 @@ mail_storages = @mail_storages@ -mailbox_list_drivers = maildir imapdir none fs shared +mailbox_list_drivers = maildir imapdir none fs shared imapc mail-storage-register.c: Makefile rm -f $@