]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: If imapc isn't the inbox=yes namespace, do the login and initial LIST in backg...
authorTimo Sirainen <tss@iki.fi>
Thu, 6 Jun 2013 07:52:14 +0000 (10:52 +0300)
committerTimo Sirainen <tss@iki.fi>
Thu, 6 Jun 2013 07:52:14 +0000 (10:52 +0300)
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

index e04fa991ab0625c9136c8103dbdda87de03e43c1..c5986bb8922450f0e3bf4fed8589037b86bc8ccd 100644 (file)
@@ -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) {
index a764f212050f5761d7f29c11972cb74bab1c44af..d3bc242766aa7ad61f9ebe2c56cd674e17e15242 100644 (file)
@@ -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;
 
index 0e575f1e46771d145cc6306984f24aa2e4459625..cae2e6b10e6eda68a123a8972d56259b4681c4eb 100644 (file)
@@ -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,
index 941d7dc177f44c5f106b5bca67e0e6f1558e17ff..77485cfc6550fc127f25bfbb55949614884a2cbb 100644 (file)
@@ -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,