From: Timo Sirainen Date: Thu, 6 Jun 2013 07:52:14 +0000 (+0300) Subject: imapc: If imapc isn't the inbox=yes namespace, do the login and initial LIST in backg... X-Git-Tag: 2.2.3~57 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3ec969c5cee55a7b08ab5c5bf7afae310176e2bd;p=thirdparty%2Fdovecot%2Fcore.git imapc: If imapc isn't the inbox=yes namespace, do the login and initial LIST in background. --- diff --git a/src/lib-storage/index/imapc/imapc-list.c b/src/lib-storage/index/imapc/imapc-list.c index e04fa991ab..c5986bb892 100644 --- a/src/lib-storage/index/imapc/imapc-list.c +++ b/src/lib-storage/index/imapc/imapc-list.c @@ -140,7 +140,7 @@ static void imapc_untagged_list(const struct imapc_untagged_reply *reply, const struct imap_arg *args = reply->args; const char *sep, *name; - if (list->sep == '\0') { + if (storage->root_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 || @@ -149,8 +149,8 @@ static void imapc_untagged_list(const struct imapc_untagged_reply *reply, return; /* we can't handle NIL separator yet */ - list->sep = sep == NULL ? '/' : sep[0]; - mailbox_tree_set_separator(list->mailboxes, list->sep); + storage->root_sep = sep == NULL ? '/' : sep[0]; + mailbox_tree_set_separator(list->mailboxes, storage->root_sep); } else { (void)imapc_list_update_tree(list, list->mailboxes, args); } @@ -163,7 +163,7 @@ static void imapc_untagged_lsub(const struct imapc_untagged_reply *reply, const struct imap_arg *args = reply->args; struct mailbox_node *node; - if (list->sep == '\0') { + if (storage->root_sep == '\0') { /* we haven't asked for the separator yet */ return; } @@ -192,11 +192,14 @@ void imapc_list_register_callbacks(struct imapc_mailbox_list *list) static char imapc_list_get_hierarchy_sep(struct mailbox_list *_list) { struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list; + char sep; - /* storage should have looked this up when it was created */ - i_assert(list->sep != '\0'); - - return list->sep; + if (imapc_storage_try_get_root_sep(list->storage, &sep) < 0) { + /* we can't really fail here. just return a common separator + and keep failing all list commands until it succeeds. */ + return '/'; + } + return sep; } static const char * @@ -209,7 +212,9 @@ imapc_list_get_storage_name(struct mailbox_list *_list, const char *vname) storage_name = mailbox_list_default_get_storage_name(_list, vname); if (*prefix != '\0' && strcasecmp(storage_name, "INBOX") != 0) { storage_name = storage_name[0] == '\0' ? prefix : - t_strdup_printf("%s%c%s", prefix, list->sep, storage_name); + t_strdup_printf("%s%c%s", prefix, + mailbox_list_get_hierarchy_sep(_list), + storage_name); } return storage_name; } @@ -230,7 +235,8 @@ imapc_list_get_vname(struct mailbox_list *_list, const char *storage_name) if (storage_name[0] == '\0') { /* we're looking up the prefix itself */ } else { - i_assert(storage_name[0] == list->sep); + i_assert(storage_name[0] == + mailbox_list_get_hierarchy_sep(_list)); storage_name++; } } @@ -408,8 +414,12 @@ static int imapc_list_refresh(struct imapc_mailbox_list *list) struct imapc_simple_context ctx; struct mailbox_node *node; const char *pattern; + char sep; - i_assert(list->sep != '\0'); + if (imapc_storage_try_get_root_sep(list->storage, &sep) < 0) { + mailbox_list_set_internal_error(&list->list); + return -1; + } if (list->refreshed_mailboxes) return 0; @@ -427,7 +437,7 @@ static int imapc_list_refresh(struct imapc_mailbox_list *list) cmd = imapc_list_simple_context_init(&ctx, list); imapc_command_sendf(cmd, "LIST \"\" %s", pattern); mailbox_tree_deinit(&list->mailboxes); - list->mailboxes = mailbox_tree_init(list->sep); + list->mailboxes = mailbox_tree_init(sep); mailbox_tree_set_parents_nonexistent(list->mailboxes); imapc_simple_run(&ctx); @@ -505,7 +515,10 @@ imapc_list_iter_init(struct mailbox_list *_list, const char *const *patterns, return _ctx; } - sep = mailbox_list_get_hierarchy_sep(_list); + if (imapc_storage_try_get_root_sep(list->storage, &sep) < 0) { + mailbox_list_set_internal_error(_list); + ret = -1; + } pool = pool_alloconly_create("mailbox list imapc iter", 1024); ctx = p_new(pool, struct imapc_mailbox_list_iterate_context, 1); @@ -623,23 +636,25 @@ imapc_list_subscriptions_refresh(struct mailbox_list *_src_list, struct imapc_simple_context ctx; struct imapc_command *cmd; const char *pattern; - char sep; + char src_sep, dest_sep; i_assert(src_list->tmp_subscriptions == NULL); if (src_list->refreshed_subscriptions) { if (dest_list->subscriptions == NULL) { - sep = mailbox_list_get_hierarchy_sep(dest_list); + dest_sep = mailbox_list_get_hierarchy_sep(dest_list); dest_list->subscriptions = - mailbox_tree_init(sep); + mailbox_tree_init(dest_sep); } return 0; } - if (src_list->sep == '\0') - (void)mailbox_list_get_hierarchy_sep(_src_list); + if (imapc_storage_try_get_root_sep(src_list->storage, &src_sep) < 0) { + mailbox_list_set_internal_error(dest_list); + return -1; + } - src_list->tmp_subscriptions = mailbox_tree_init(src_list->sep); + src_list->tmp_subscriptions = mailbox_tree_init(src_sep); cmd = imapc_list_simple_context_init(&ctx, src_list); if (*src_list->storage->set->imapc_list_prefix == '\0') @@ -647,7 +662,7 @@ imapc_list_subscriptions_refresh(struct mailbox_list *_src_list, else { pattern = t_strdup_printf("%s%c*", src_list->storage->set->imapc_list_prefix, - src_list->sep); + src_sep); } imapc_command_sendf(cmd, "LSUB \"\" %s", pattern); imapc_simple_run(&ctx); @@ -763,8 +778,12 @@ int imapc_list_get_mailbox_flags(struct mailbox_list *_list, const char *name, struct imapc_simple_context sctx; struct mailbox_node *node; const char *vname; + char sep; - i_assert(list->sep != '\0'); + if (imapc_storage_try_get_root_sep(list->storage, &sep) < 0) { + mailbox_list_set_internal_error(_list); + return -1; + } vname = mailbox_list_get_vname(_list, name); if (!list->refreshed_mailboxes) { diff --git a/src/lib-storage/index/imapc/imapc-list.h b/src/lib-storage/index/imapc/imapc-list.h index a764f21205..d3bc242766 100644 --- a/src/lib-storage/index/imapc/imapc-list.h +++ b/src/lib-storage/index/imapc/imapc-list.h @@ -13,7 +13,6 @@ struct imapc_mailbox_list { struct mailbox_list *index_list; struct mailbox_tree_context *mailboxes, *tmp_subscriptions; - char sep; unsigned int iter_count; diff --git a/src/lib-storage/index/imapc/imapc-storage.c b/src/lib-storage/index/imapc/imapc-storage.c index 0e575f1e46..cae2e6b10e 100644 --- a/src/lib-storage/index/imapc/imapc-storage.c +++ b/src/lib-storage/index/imapc/imapc-storage.c @@ -180,36 +180,61 @@ static void imapc_storage_untagged_cb(const struct imapc_untagged_reply *reply, } } -static int -imapc_storage_get_hierarchy_sep(struct imapc_storage *storage, - const char **error_r) +static void imapc_storage_sep_verify(struct imapc_storage *storage) { - struct imapc_command *cmd; - struct imapc_simple_context sctx; const char *imapc_list_prefix = storage->set->imapc_list_prefix; - imapc_simple_context_init(&sctx, storage); - cmd = imapc_client_cmd(storage->client, imapc_simple_callback, &sctx); - imapc_command_send(cmd, "LIST \"\" \"\""); - imapc_simple_run(&sctx); - - if (sctx.ret < 0) { - *error_r = t_strdup_printf("LIST failed: %s", - mail_storage_get_last_error(&storage->storage, NULL)); - return -1; + if (storage->root_sep == '\0') { + mail_storage_set_critical(&storage->storage, + "imapc: LIST didn't return hierarchy separator"); + } else if (imapc_list_prefix[0] != '\0' && + imapc_list_prefix[strlen(imapc_list_prefix)-1] == storage->root_sep) { + mail_storage_set_critical(&storage->storage, + "imapc_list_prefix must not end with hierarchy separator"); } +} - if (storage->list->sep == '\0') { - *error_r = "LIST didn't return hierarchy separator"; - return -1; +static void imapc_storage_sep_callback(const struct imapc_command_reply *reply, + void *context) +{ + struct imapc_storage *storage = context; + + storage->root_sep_pending = FALSE; + if (reply->state == IMAPC_COMMAND_STATE_OK) + imapc_storage_sep_verify(storage); + else if (reply->state == IMAPC_COMMAND_STATE_NO) + imapc_copy_error_from_reply(storage, MAIL_ERROR_PARAMS, reply); + else { + mail_storage_set_critical(&storage->storage, + "imapc: Command failed: %s", reply->text_full); } + imapc_client_stop(storage->client); +} - if (imapc_list_prefix[0] != '\0' && - imapc_list_prefix[strlen(imapc_list_prefix)-1] == storage->list->sep) { - *error_r = "imapc_list_prefix must not end with hierarchy separator"; - return -1; +static void imapc_storage_send_hierarcy_sep_lookup(struct imapc_storage *storage) +{ + struct imapc_command *cmd; + + if (storage->root_sep_pending) + return; + storage->root_sep_pending = TRUE; + + cmd = imapc_client_cmd(storage->client, + imapc_storage_sep_callback, storage); + imapc_command_send(cmd, "LIST \"\" \"\""); +} + +int imapc_storage_try_get_root_sep(struct imapc_storage *storage, char *sep_r) +{ + if (storage->root_sep == '\0') { + imapc_storage_send_hierarcy_sep_lookup(storage); + while (storage->root_sep_pending) + imapc_client_run(storage->client); + if (storage->root_sep == '\0') + return -1; } - return sctx.ret; + *sep_r = storage->root_sep; + return 0; } static int @@ -220,6 +245,7 @@ imapc_storage_create(struct mail_storage *_storage, struct imapc_storage *storage = (struct imapc_storage *)_storage; struct imapc_client_settings set; string_t *str; + char sep; storage->set = mail_storage_get_driver_settings(_storage); @@ -279,10 +305,19 @@ imapc_storage_create(struct mail_storage *_storage, imapc_untagged_status); imapc_storage_register_untagged(storage, "NAMESPACE", imapc_untagged_namespace); - /* connect to imap server and get the hierarchy separator. */ - if (imapc_storage_get_hierarchy_sep(storage, error_r) < 0) { - imapc_client_deinit(&storage->client); - return -1; + /* start connecting to imap server and get the hierarchy separator. */ + imapc_client_login(storage->client, NULL, NULL); + imapc_storage_send_hierarcy_sep_lookup(storage); + if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) { + /* we're using imapc for the INBOX namespace. wait and make + sure we can successfully access the IMAP server (so if the + username is invalid we don't just keep failing every + command). */ + if (imapc_storage_try_get_root_sep(storage, &sep) < 0) { + imapc_client_deinit(&storage->client); + *error_r = "Failed to access imapc backend"; + return -1; + } } return 0; } @@ -302,10 +337,7 @@ static void imapc_storage_add_list(struct mail_storage *_storage, struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list; i_assert(storage->list != NULL); - i_assert(storage->list->sep != '\0'); - list->storage = storage; - list->sep = storage->list->sep; } void imapc_storage_register_untagged(struct imapc_storage *storage, diff --git a/src/lib-storage/index/imapc/imapc-storage.h b/src/lib-storage/index/imapc/imapc-storage.h index 941d7dc177..77485cfc65 100644 --- a/src/lib-storage/index/imapc/imapc-storage.h +++ b/src/lib-storage/index/imapc/imapc-storage.h @@ -47,6 +47,7 @@ struct imapc_storage { struct ioloop *root_ioloop; struct imapc_mailbox_list *list; struct imapc_client *client; + char root_sep; struct imapc_mailbox *cur_status_box; struct mailbox_status *cur_status; @@ -56,6 +57,7 @@ struct imapc_storage { ARRAY(struct imapc_storage_event_callback) untagged_callbacks; unsigned int namespaces_requested:1; + unsigned int root_sep_pending:1; }; struct imapc_mail_cache { @@ -128,6 +130,7 @@ void imapc_transaction_save_rollback(struct mail_save_context *ctx); void imapc_storage_run(struct imapc_storage *storage); void imapc_mail_cache_free(struct imapc_mail_cache *cache); int imapc_mailbox_select(struct imapc_mailbox *mbox); +int imapc_storage_try_get_root_sep(struct imapc_storage *storage, char *sep_r); void imapc_copy_error_from_reply(struct imapc_storage *storage, enum mail_error default_error,