]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Reorganize code so that imapc_list works without imapc_storage.
authorTimo Sirainen <tss@iki.fi>
Wed, 10 Jul 2013 03:54:57 +0000 (06:54 +0300)
committerTimo Sirainen <tss@iki.fi>
Wed, 10 Jul 2013 03:54:57 +0000 (06:54 +0300)
Most importantly fixes crashes when imapc_list is trying to lookup hierarchy
separator before storage is created.

src/lib-storage/index/imapc/imapc-list.c
src/lib-storage/index/imapc/imapc-list.h
src/lib-storage/index/imapc/imapc-mail-fetch.c
src/lib-storage/index/imapc/imapc-save.c
src/lib-storage/index/imapc/imapc-storage.c
src/lib-storage/index/imapc/imapc-storage.h
src/lib-storage/index/imapc/imapc-sync.c

index 2a58b65508ec3f84235af4f8ef2048dd44373c38..be755f3329b3b097256f7304798e5202d769bb0b 100644 (file)
@@ -41,6 +41,12 @@ static struct {
 
 extern struct mailbox_list imapc_mailbox_list;
 
+static void imapc_list_send_hierarcy_sep_lookup(struct imapc_mailbox_list *list);
+static void imapc_untagged_list(const struct imapc_untagged_reply *reply,
+                               struct imapc_storage_client *client);
+static void imapc_untagged_lsub(const struct imapc_untagged_reply *reply,
+                               struct imapc_storage_client *client);
+
 static struct mailbox_list *imapc_list_alloc(void)
 {
        struct imapc_mailbox_list *list;
@@ -50,20 +56,41 @@ static struct mailbox_list *imapc_list_alloc(void)
        list = p_new(pool, struct imapc_mailbox_list, 1);
        list->list = imapc_mailbox_list;
        list->list.pool = pool;
-       /* separator is set when storage is created */
+       /* separator is set lazily */
        list->mailboxes = mailbox_tree_init('\0');
        mailbox_tree_set_parents_nonexistent(list->mailboxes);
        return &list->list;
 }
 
-static int
-imapc_list_init(struct mailbox_list *_list, const char **error_r ATTR_UNUSED)
+static int imapc_list_init(struct mailbox_list *_list, const char **error_r)
 {
        struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list;
+       char sep;
 
        list->set = mail_user_set_get_driver_settings(_list->ns->user->set_info,
                                                      _list->ns->user->set,
                                                      IMAPC_STORAGE_NAME);
+       if (imapc_storage_client_create(_list->ns, list->set, _list->mail_set,
+                                       &list->client, error_r) < 0)
+               return -1;
+       list->client->_list = list;
+
+       imapc_storage_client_register_untagged(list->client, "LIST",
+                                              imapc_untagged_list);
+       imapc_storage_client_register_untagged(list->client, "LSUB",
+                                              imapc_untagged_lsub);
+       imapc_list_send_hierarcy_sep_lookup(list);
+       if ((_list->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_list_try_get_root_sep(list, &sep) < 0) {
+                       imapc_storage_client_unref(&list->client);
+                       *error_r = "Failed to access imapc backend";
+                       return -1;
+               }
+       }
        return 0;
 }
 
@@ -76,21 +103,43 @@ static void imapc_list_deinit(struct mailbox_list *_list)
        mailbox_tree_deinit(&list->mailboxes);
        if (list->tmp_subscriptions != NULL)
                mailbox_tree_deinit(&list->tmp_subscriptions);
+       imapc_storage_client_unref(&list->client);
        pool_unref(&list->list.pool);
 }
 
+static void
+imapc_list_copy_error_from_reply(struct imapc_mailbox_list *list,
+                                enum mail_error default_error,
+                                const struct imapc_command_reply *reply)
+{
+       enum mail_error error;
+
+       if (imap_resp_text_code_parse(reply->resp_text_key, &error)) {
+               mailbox_list_set_error(&list->list, error,
+                                      reply->text_without_resp);
+       } else {
+               mailbox_list_set_error(&list->list, default_error,
+                                      reply->text_without_resp);
+       }
+}
+
 static void imapc_list_simple_callback(const struct imapc_command_reply *reply,
                                       void *context)
 {
        struct imapc_simple_context *ctx = context;
-       const char *str;
-       enum mail_error error;
 
-       imapc_simple_callback(reply, context);
-       if (ctx->ret < 0) {
-               str = mail_storage_get_last_error(&ctx->storage->storage, &error);
-               mailbox_list_set_error(&ctx->storage->list->list, error, str);
+       if (reply->state == IMAPC_COMMAND_STATE_OK)
+               ctx->ret = 0;
+       else if (reply->state == IMAPC_COMMAND_STATE_NO) {
+               imapc_list_copy_error_from_reply(ctx->client->_list,
+                                                MAIL_ERROR_PARAMS, reply);
+               ctx->ret = -1;
+       } else {
+               mailbox_list_set_critical(&ctx->client->_list->list,
+                       "imapc: Command failed: %s", reply->text_full);
+               ctx->ret = -1;
        }
+       imapc_client_stop(ctx->client->client);
 }
 
 static bool
@@ -144,13 +193,13 @@ imapc_list_update_tree(struct imapc_mailbox_list *list,
 }
 
 static void imapc_untagged_list(const struct imapc_untagged_reply *reply,
-                               struct imapc_storage *storage)
+                               struct imapc_storage_client *client)
 {
-       struct imapc_mailbox_list *list = storage->list;
+       struct imapc_mailbox_list *list = client->_list;
        const struct imap_arg *args = reply->args;
        const char *sep, *name;
 
-       if (storage->root_sep == '\0') {
+       if (list->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 ||
@@ -159,21 +208,21 @@ static void imapc_untagged_list(const struct imapc_untagged_reply *reply,
                        return;
 
                /* we can't handle NIL separator yet */
-               storage->root_sep = sep == NULL ? '/' : sep[0];
-               mailbox_tree_set_separator(list->mailboxes, storage->root_sep);
+               list->root_sep = sep == NULL ? '/' : sep[0];
+               mailbox_tree_set_separator(list->mailboxes, list->root_sep);
        } else {
                (void)imapc_list_update_tree(list, list->mailboxes, args);
        }
 }
 
 static void imapc_untagged_lsub(const struct imapc_untagged_reply *reply,
-                               struct imapc_storage *storage)
+                               struct imapc_storage_client *client)
 {
-       struct imapc_mailbox_list *list = storage->list;
+       struct imapc_mailbox_list *list = client->_list;
        const struct imap_arg *args = reply->args;
        struct mailbox_node *node;
 
-       if (storage->root_sep == '\0') {
+       if (list->root_sep == '\0') {
                /* we haven't asked for the separator yet */
                return;
        }
@@ -191,12 +240,61 @@ static void imapc_untagged_lsub(const struct imapc_untagged_reply *reply,
        }
 }
 
-void imapc_list_register_callbacks(struct imapc_mailbox_list *list)
+static void imapc_list_sep_verify(struct imapc_mailbox_list *list)
 {
-       imapc_storage_register_untagged(list->storage, "LIST",
-                                       imapc_untagged_list);
-       imapc_storage_register_untagged(list->storage, "LSUB",
-                                       imapc_untagged_lsub);
+       const char *imapc_list_prefix = list->set->imapc_list_prefix;
+
+       if (list->root_sep == '\0') {
+               mailbox_list_set_critical(&list->list,
+                       "imapc: LIST didn't return hierarchy separator");
+       } else if (imapc_list_prefix[0] != '\0' &&
+                  imapc_list_prefix[strlen(imapc_list_prefix)-1] == list->root_sep) {
+               mailbox_list_set_critical(&list->list,
+                       "imapc_list_prefix must not end with hierarchy separator");
+       }
+}
+
+static void imapc_storage_sep_callback(const struct imapc_command_reply *reply,
+                                      void *context)
+{
+       struct imapc_mailbox_list *list = context;
+
+       list->root_sep_pending = FALSE;
+       if (reply->state == IMAPC_COMMAND_STATE_OK)
+               imapc_list_sep_verify(list);
+       else if (reply->state == IMAPC_COMMAND_STATE_NO)
+               imapc_list_copy_error_from_reply(list, MAIL_ERROR_PARAMS, reply);
+       else {
+               mailbox_list_set_critical(&list->list,
+                       "imapc: Command failed: %s", reply->text_full);
+       }
+       imapc_client_stop(list->client->client);
+}
+
+static void imapc_list_send_hierarcy_sep_lookup(struct imapc_mailbox_list *list)
+{
+       struct imapc_command *cmd;
+
+       if (list->root_sep_pending)
+               return;
+       list->root_sep_pending = TRUE;
+
+       cmd = imapc_client_cmd(list->client->client,
+                              imapc_storage_sep_callback, list);
+       imapc_command_send(cmd, "LIST \"\" \"\"");
+}
+
+int imapc_list_try_get_root_sep(struct imapc_mailbox_list *list, char *sep_r)
+{
+       if (list->root_sep == '\0') {
+               imapc_list_send_hierarcy_sep_lookup(list);
+               while (list->root_sep_pending)
+                       imapc_client_run(list->client->client);
+               if (list->root_sep == '\0')
+                       return -1;
+       }
+       *sep_r = list->root_sep;
+       return 0;
 }
 
 static char imapc_list_get_hierarchy_sep(struct mailbox_list *_list)
@@ -204,7 +302,7 @@ static char imapc_list_get_hierarchy_sep(struct mailbox_list *_list)
        struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list;
        char sep;
 
-       if (imapc_storage_try_get_root_sep(list->storage, &sep) < 0) {
+       if (imapc_list_try_get_root_sep(list, &sep) < 0) {
                /* we can't really fail here. just return a common separator
                   and keep failing all list commands until it succeeds. */
                return '/';
@@ -367,8 +465,8 @@ static struct imapc_command *
 imapc_list_simple_context_init(struct imapc_simple_context *ctx,
                               struct imapc_mailbox_list *list)
 {
-       imapc_simple_context_init(ctx, list->storage);
-       return imapc_client_cmd(list->storage->client,
+       imapc_simple_context_init(ctx, list->client);
+       return imapc_client_cmd(list->client->client,
                                imapc_list_simple_callback, ctx);
 }
 
@@ -690,7 +788,7 @@ imapc_list_delete_mailbox(struct mailbox_list *_list, const char *name)
        struct imapc_command *cmd;
        struct imapc_simple_context ctx;
 
-       capa = imapc_client_get_capabilities(list->storage->client);
+       capa = imapc_client_get_capabilities(list->client->client);
 
        cmd = imapc_list_simple_context_init(&ctx, list);
        imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_SELECT);
index 764be30f6c30358f18f5236c6f3be5b06d56ba04..c3338114cc2c7c86fd499291004c148712e6c7f3 100644 (file)
@@ -10,21 +10,22 @@ struct imap_arg;
 struct imapc_mailbox_list {
        struct mailbox_list list;
        const struct imapc_settings *set;
-       struct imapc_storage *storage;
+       struct imapc_storage_client *client;
        struct mailbox_list *index_list;
 
        struct mailbox_tree_context *mailboxes, *tmp_subscriptions;
+       char root_sep;
 
        unsigned int iter_count;
 
        unsigned int refreshed_subscriptions:1;
        unsigned int refreshed_mailboxes:1;
        unsigned int index_list_failed:1;
+       unsigned int root_sep_pending:1;
 };
 
 int imapc_list_get_mailbox_flags(struct mailbox_list *list, const char *name,
                                 enum mailbox_info_flags *flags_r);
-
-void imapc_list_register_callbacks(struct imapc_mailbox_list *list);
+int imapc_list_try_get_root_sep(struct imapc_mailbox_list *list, char *sep_r);
 
 #endif
index ddc235647ab40d7496bece4874d433d4ba76bd74..13b17fb743fb6d56f6fb83f2001457714b705430 100644 (file)
@@ -48,7 +48,7 @@ imapc_mail_prefetch_callback(const struct imapc_command_reply *reply,
                        "imapc: Mail prefetch failed: %s", reply->text_full);
        }
        pool_unref(&mail->imail.mail.pool);
-       imapc_client_stop(mbox->storage->client);
+       imapc_client_stop(mbox->storage->client->client);
 }
 
 static int
@@ -407,6 +407,6 @@ void imapc_mail_fetch_update(struct imapc_mail *mail,
        if (!match) {
                /* this is only a FETCH FLAGS update for the wanted mail */
        } else {
-               imapc_client_stop(mbox->storage->client);
+               imapc_client_stop(mbox->storage->client->client);
        }
 }
index 0556b7602afedf8e976d6ded5b475b250910d20e..dec39b2c063952b04096c3d1008299a3df14cd03 100644 (file)
@@ -66,7 +66,8 @@ int imapc_save_begin(struct mail_save_context *_ctx, struct istream *input)
 
        i_assert(ctx->fd == -1);
 
-       ctx->fd = imapc_client_create_temp_fd(ctx->mbox->storage->client, &path);
+       ctx->fd = imapc_client_create_temp_fd(ctx->mbox->storage->client->client,
+                                             &path);
        if (ctx->fd == -1) {
                mail_storage_set_critical(storage,
                                          "Couldn't create temp file %s", path);
@@ -180,7 +181,7 @@ static void imapc_save_callback(const struct imapc_command_reply *reply,
                        "imapc: COPY failed: %s", reply->text_full);
                ctx->ret = -1;
        }
-       imapc_client_stop(ctx->ctx->mbox->storage->client);
+       imapc_client_stop(ctx->ctx->mbox->storage->client->client);
 }
 
 static void
@@ -191,7 +192,7 @@ imapc_save_noop_callback(const struct imapc_command_reply *reply ATTR_UNUSED,
 
        /* we don't really care about the reply */
        ctx->ret = 0;
-       imapc_client_stop(ctx->ctx->mbox->storage->client);
+       imapc_client_stop(ctx->ctx->mbox->storage->client->client);
 }
 
 static void
@@ -239,7 +240,7 @@ static int imapc_save_append(struct imapc_save_context *ctx)
        input = i_stream_create_fd(ctx->fd, IO_BLOCK_SIZE, FALSE);
        sctx.ctx = ctx;
        sctx.ret = -2;
-       cmd = imapc_client_cmd(ctx->mbox->storage->client,
+       cmd = imapc_client_cmd(ctx->mbox->storage->client->client,
                               imapc_save_callback, &sctx);
        imapc_command_sendf(cmd, "APPEND %s%1s%1s %p",
                            ctx->mbox->box.name, flags, internaldate, input);
@@ -254,7 +255,7 @@ static int imapc_save_append(struct imapc_save_context *ctx)
                   but it makes the behavior better. See if NOOP finds
                   the mail. */
                sctx.ret = -2;
-               cmd = imapc_client_cmd(ctx->mbox->storage->client,
+               cmd = imapc_client_cmd(ctx->mbox->storage->client->client,
                                       imapc_save_noop_callback, &sctx);
                imapc_command_send(cmd, "NOOP");
                while (sctx.ret == -2)
@@ -398,7 +399,7 @@ static void imapc_copy_callback(const struct imapc_command_reply *reply,
                        "imapc: COPY failed: %s", reply->text_full);
                ctx->ret = -1;
        }
-       imapc_client_stop(ctx->ctx->mbox->storage->client);
+       imapc_client_stop(ctx->ctx->mbox->storage->client->client);
 }
 
 int imapc_copy(struct mail_save_context *_ctx, struct mail *mail)
index 8a7be8c5e497cf6b17ca49813d47e0b188ddc984..08611f1b3fad49f25d7103be5954e6fab981e10d 100644 (file)
@@ -51,12 +51,11 @@ static struct imapc_resp_code_map imapc_resp_code_map[] = {
 };
 
 static void imapc_untagged_status(const struct imapc_untagged_reply *reply,
-                                 struct imapc_storage *storage);
+                                 struct imapc_storage_client *client);
 static void imapc_untagged_namespace(const struct imapc_untagged_reply *reply,
-                                    struct imapc_storage *storage);
+                                    struct imapc_storage_client *client);
 
-static bool
-imap_resp_text_code_parse(const char *str, enum mail_error *error_r)
+bool imap_resp_text_code_parse(const char *str, enum mail_error *error_r)
 {
        unsigned int i;
 
@@ -101,23 +100,23 @@ void imapc_copy_error_from_reply(struct imapc_storage *storage,
 }
 
 void imapc_simple_context_init(struct imapc_simple_context *sctx,
-                              struct imapc_storage *storage)
+                              struct imapc_storage_client *client)
 {
        memset(sctx, 0, sizeof(*sctx));
-       sctx->storage = storage;
+       sctx->client = client;
        sctx->ret = -2;
 }
 
 void imapc_simple_run(struct imapc_simple_context *sctx)
 {
        while (sctx->ret == -2)
-               imapc_storage_run(sctx->storage);
+               imapc_client_run(sctx->client->client);
 }
 
 void imapc_storage_run(struct imapc_storage *storage)
 {
        do {
-               imapc_client_run(storage->client);
+               imapc_client_run(storage->client->client);
        } while (storage->reopen_count > 0);
 }
 
@@ -129,14 +128,15 @@ void imapc_simple_callback(const struct imapc_command_reply *reply,
        if (reply->state == IMAPC_COMMAND_STATE_OK)
                ctx->ret = 0;
        else if (reply->state == IMAPC_COMMAND_STATE_NO) {
-               imapc_copy_error_from_reply(ctx->storage, MAIL_ERROR_PARAMS, reply);
+               imapc_copy_error_from_reply(ctx->client->_storage,
+                                           MAIL_ERROR_PARAMS, reply);
                ctx->ret = -1;
        } else {
-               mail_storage_set_critical(&ctx->storage->storage,
+               mail_storage_set_critical(&ctx->client->_storage->storage,
                        "imapc: Command failed: %s", reply->text_full);
                ctx->ret = -1;
        }
-       imapc_client_stop(ctx->storage->client);
+       imapc_client_stop(ctx->client->client);
 }
 
 void imapc_mailbox_noop(struct imapc_mailbox *mbox)
@@ -144,24 +144,25 @@ void imapc_mailbox_noop(struct imapc_mailbox *mbox)
        struct imapc_command *cmd;
        struct imapc_simple_context sctx;
 
-       imapc_simple_context_init(&sctx, mbox->storage);
+       imapc_simple_context_init(&sctx, mbox->storage->client);
        cmd = imapc_client_mailbox_cmd(mbox->client_box,
                                       imapc_simple_callback, &sctx);
        imapc_command_send(cmd, "NOOP");
        imapc_simple_run(&sctx);
 }
 
-static void imapc_storage_untagged_cb(const struct imapc_untagged_reply *reply,
-                                     void *context)
+static void
+imapc_storage_client_untagged_cb(const struct imapc_untagged_reply *reply,
+                                void *context)
 {
-       struct imapc_storage *storage = context;
+       struct imapc_storage_client *client = context;
        struct imapc_mailbox *mbox = reply->untagged_box_context;
        const struct imapc_storage_event_callback *cb;
        const struct imapc_mailbox_event_callback *mcb;
 
-       array_foreach(&storage->untagged_callbacks, cb) {
+       array_foreach(&client->untagged_callbacks, cb) {
                if (strcasecmp(reply->name, cb->name) == 0)
-                       cb->callback(reply, storage);
+                       cb->callback(reply, client);
        }
 
        if (mbox == NULL)
@@ -180,71 +181,13 @@ static void imapc_storage_untagged_cb(const struct imapc_untagged_reply *reply,
        }
 }
 
-static void imapc_storage_sep_verify(struct imapc_storage *storage)
-{
-       const char *imapc_list_prefix = storage->set->imapc_list_prefix;
-
-       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");
-       }
-}
-
-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);
-}
-
-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)
-{
-       i_assert(storage->list != NULL);
-
-       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;
-       }
-       *sep_r = storage->root_sep;
-       return 0;
-}
-
-static int
-imapc_client_create(struct mail_namespace *ns,
-                   const struct imapc_settings *imapc_set,
-                   const struct mail_storage_settings *mail_set,
-                   struct imapc_client **client_r, const char **error_r)
+int imapc_storage_client_create(struct mail_namespace *ns,
+                               const struct imapc_settings *imapc_set,
+                               const struct mail_storage_settings *mail_set,
+                               struct imapc_storage_client **client_r,
+                               const char **error_r)
 {
+       struct imapc_storage_client *client;
        struct imapc_client_settings set;
        string_t *str;
 
@@ -290,53 +233,61 @@ imapc_client_create(struct mail_namespace *ns,
                set.ssl_mode = IMAPC_CLIENT_SSL_MODE_NONE;
        set.ssl_crypto_device = mail_set->ssl_crypto_device;
 
-       *client_r = imapc_client_init(&set);
+       client = i_new(struct imapc_storage_client, 1);
+       client->refcount = 1;
+       i_array_init(&client->untagged_callbacks, 16);
+       client->client = imapc_client_init(&set);
+       imapc_client_register_untagged(client->client,
+                                      imapc_storage_client_untagged_cb, client);
+       /* start logging in immediately */
+       imapc_client_login(client->client, NULL, NULL);
+
+       *client_r = client;
        return 0;
 }
 
+void imapc_storage_client_unref(struct imapc_storage_client **_client)
+{
+       struct imapc_storage_client *client = *_client;
+       struct imapc_storage_event_callback *cb;
+
+       *_client = NULL;
+
+       i_assert(client->refcount > 0);
+       if (--client->refcount > 0)
+               return;
+       imapc_client_deinit(&client->client);
+       array_foreach_modifiable(&client->untagged_callbacks, cb)
+               i_free(cb->name);
+       array_free(&client->untagged_callbacks);
+       i_free(client);
+}
+
 static int
 imapc_storage_create(struct mail_storage *_storage,
                     struct mail_namespace *ns,
                     const char **error_r)
 {
        struct imapc_storage *storage = (struct imapc_storage *)_storage;
-       char sep;
+       struct imapc_mailbox_list *imapc_list = NULL;
 
        storage->set = mail_storage_get_driver_settings(_storage);
-       if (imapc_client_create(ns, storage->set, _storage->set,
-                               &storage->client, error_r) < 0)
-               return -1;
-
-       p_array_init(&storage->remote_namespaces, _storage->pool, 4);
-       p_array_init(&storage->untagged_callbacks, _storage->pool, 16);
        if (strcmp(ns->list->name, MAILBOX_LIST_NAME_IMAPC) == 0) {
-               storage->list = (struct imapc_mailbox_list *)ns->list;
-               storage->list->storage = storage;
-               imapc_list_register_callbacks(storage->list);
-       }
-
-       imapc_client_register_untagged(storage->client,
-                                      imapc_storage_untagged_cb, storage);
-       imapc_storage_register_untagged(storage, "STATUS",
-                                       imapc_untagged_status);
-       imapc_storage_register_untagged(storage, "NAMESPACE",
-                                       imapc_untagged_namespace);
-       /* start connecting to imap server and get the hierarchy separator. */
-       imapc_client_login(storage->client, NULL, NULL);
-       if (storage->list != NULL)
-               imapc_storage_send_hierarcy_sep_lookup(storage);
-       if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
-           storage->list != NULL) {
-               /* 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";
+               imapc_list = (struct imapc_mailbox_list *)ns->list;
+               storage->client = imapc_list->client;
+               storage->client->refcount++;
+       } else {
+               if (imapc_storage_client_create(ns, storage->set, _storage->set,
+                                               &storage->client, error_r) < 0)
                        return -1;
-               }
        }
+       storage->client->_storage = storage;
+       p_array_init(&storage->remote_namespaces, _storage->pool, 4);
+
+       imapc_storage_client_register_untagged(storage->client, "STATUS",
+                                              imapc_untagged_status);
+       imapc_storage_client_register_untagged(storage->client, "NAMESPACE",
+                                              imapc_untagged_namespace);
        return 0;
 }
 
@@ -344,30 +295,18 @@ static void imapc_storage_destroy(struct mail_storage *_storage)
 {
        struct imapc_storage *storage = (struct imapc_storage *)_storage;
 
-       imapc_client_deinit(&storage->client);
+       imapc_storage_client_unref(&storage->client);
        index_storage_destroy(_storage);
 }
 
-static void imapc_storage_add_list(struct mail_storage *_storage,
-                                  struct mailbox_list *_list)
-{
-       struct imapc_storage *storage = (struct imapc_storage *)_storage;
-       struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list;
-
-       if (strcmp(_list->name, MAILBOX_LIST_NAME_IMAPC) == 0) {
-               i_assert(storage->list != NULL);
-               list->storage = storage;
-       }
-}
-
-void imapc_storage_register_untagged(struct imapc_storage *storage,
-                                    const char *name,
-                                    imapc_storage_callback_t *callback)
+void imapc_storage_client_register_untagged(struct imapc_storage_client *client,
+                                           const char *name,
+                                           imapc_storage_callback_t *callback)
 {
        struct imapc_storage_event_callback *cb;
 
-       cb = array_append_space(&storage->untagged_callbacks);
-       cb->name = p_strdup(storage->storage.pool, name);
+       cb = array_append_space(&client->untagged_callbacks);
+       cb->name = i_strdup(name);
        cb->callback = callback;
 }
 
@@ -446,7 +385,7 @@ imapc_mailbox_reopen_callback(const struct imapc_command_reply *reply,
                        mbox->box.name, reply->text_full);
                imapc_client_mailbox_reconnect(mbox->client_box);
        }
-       imapc_client_stop(mbox->storage->client);
+       imapc_client_stop(mbox->storage->client->client);
 }
 
 static void imapc_mailbox_reopen(void *context)
@@ -494,13 +433,13 @@ imapc_mailbox_open_callback(const struct imapc_command_reply *reply,
                        ctx->mbox->box.name, reply->text_full);
                ctx->ret = -1;
        }
-       imapc_client_stop(ctx->mbox->storage->client);
+       imapc_client_stop(ctx->mbox->storage->client->client);
 }
 
 static void imapc_mailbox_get_extensions(struct imapc_mailbox *mbox)
 {
        enum imapc_capability capa =
-               imapc_client_get_capabilities(mbox->storage->client);
+               imapc_client_get_capabilities(mbox->storage->client->client);
 
        if (mbox->guid_fetch_field_name == NULL) {
                /* see if we can get message GUIDs somehow */
@@ -519,7 +458,7 @@ int imapc_mailbox_select(struct imapc_mailbox *mbox)
        i_assert(mbox->client_box == NULL);
 
        mbox->client_box =
-               imapc_client_mailbox_open(mbox->storage->client, mbox);
+               imapc_client_mailbox_open(mbox->storage->client->client, mbox);
        imapc_client_mailbox_set_reopen_cb(mbox->client_box,
                                           imapc_mailbox_reopen, mbox);
 
@@ -618,8 +557,8 @@ imapc_mailbox_create(struct mailbox *box,
                name = t_strdup_printf("%s%c", name,
                                mailbox_list_get_hierarchy_sep(box->list));
        }
-       imapc_simple_context_init(&sctx, mbox->storage);
-       cmd = imapc_client_cmd(mbox->storage->client,
+       imapc_simple_context_init(&sctx, mbox->storage->client);
+       cmd = imapc_client_cmd(mbox->storage->client->client,
                               imapc_simple_callback, &sctx);
        imapc_command_sendf(cmd, "CREATE %s", name);
        imapc_simple_run(&sctx);
@@ -639,8 +578,9 @@ static int imapc_mailbox_update(struct mailbox *box,
 }
 
 static void imapc_untagged_status(const struct imapc_untagged_reply *reply,
-                                 struct imapc_storage *storage)
+                                 struct imapc_storage_client *client)
 {
+       struct imapc_storage *storage = client->_storage;
        struct mailbox_status *status;
        const struct imap_arg *list;
        const char *name, *key, *value;
@@ -676,8 +616,9 @@ static void imapc_untagged_status(const struct imapc_untagged_reply *reply,
 }
 
 static void imapc_untagged_namespace(const struct imapc_untagged_reply *reply,
-                                    struct imapc_storage *storage)
+                                    struct imapc_storage_client *client)
 {
+       struct imapc_storage *storage = client->_storage;
        static enum mail_namespace_type ns_types[] = {
                MAIL_NAMESPACE_TYPE_PRIVATE,
                MAIL_NAMESPACE_TYPE_SHARED,
@@ -769,10 +710,10 @@ static int imapc_mailbox_get_status(struct mailbox *box,
                return 0;
        }
 
-       imapc_simple_context_init(&sctx, mbox->storage);
+       imapc_simple_context_init(&sctx, mbox->storage->client);
        mbox->storage->cur_status_box = mbox;
        mbox->storage->cur_status = status_r;
-       cmd = imapc_client_cmd(mbox->storage->client,
+       cmd = imapc_client_cmd(mbox->storage->client->client,
                               imapc_simple_callback, &sctx);
        imapc_command_sendf(cmd, "STATUS %s (%1s)", box->name, str_c(str)+1);
        imapc_simple_run(&sctx);
@@ -790,14 +731,14 @@ static int imapc_mailbox_get_namespaces(struct imapc_storage *storage)
        if (storage->namespaces_requested)
                return 0;
 
-       capa = imapc_client_get_capabilities(storage->client);
+       capa = imapc_client_get_capabilities(storage->client->client);
        if ((capa & IMAPC_CAPABILITY_NAMESPACE) == 0) {
                /* NAMESPACE capability not supported */
                return 0;
        }
 
-       imapc_simple_context_init(&sctx, storage);
-       cmd = imapc_client_cmd(storage->client,
+       imapc_simple_context_init(&sctx, storage->client);
+       cmd = imapc_client_cmd(storage->client->client,
                               imapc_simple_callback, &sctx);
        imapc_command_send(cmd, "NAMESPACE");
        imapc_simple_run(&sctx);
@@ -908,7 +849,7 @@ static void imapc_notify_changes(struct mailbox *box)
                return;
        }
 
-       capa = imapc_client_get_capabilities(mbox->storage->client);
+       capa = imapc_client_get_capabilities(mbox->storage->client->client);
        if ((capa & IMAPC_CAPABILITY_IDLE) != 0) {
                /* remote server is already in IDLE. but since some servers
                   don't notice changes immediately, we'll force them to check
@@ -920,7 +861,7 @@ static void imapc_notify_changes(struct mailbox *box)
        } else {
                /* remote server doesn't support IDLE.
                   check for changes with NOOP every once in a while. */
-               i_assert(!imapc_client_is_running(mbox->storage->client));
+               i_assert(!imapc_client_is_running(mbox->storage->client->client));
                mbox->to_idle_check =
                        timeout_add(set->mailbox_idle_check_interval * 1000,
                                    imapc_idle_timeout, mbox);
@@ -946,7 +887,7 @@ struct mail_storage imapc_storage = {
                imapc_storage_alloc,
                imapc_storage_create,
                imapc_storage_destroy,
-               imapc_storage_add_list,
+               NULL,
                imapc_storage_get_list_settings,
                NULL,
                imapc_mailbox_alloc,
index 77485cfc6550fc127f25bfbb55949614884a2cbb..e811f85dbb4e72dc3fb75fafa0c3b28fbfb17e7c 100644 (file)
@@ -12,15 +12,15 @@ struct imap_arg;
 struct imapc_untagged_reply;
 struct imapc_command_reply;
 struct imapc_mailbox;
-struct imapc_storage;
+struct imapc_storage_client;
 
 typedef void imapc_storage_callback_t(const struct imapc_untagged_reply *reply,
-                                     struct imapc_storage *storage);
+                                     struct imapc_storage_client *client);
 typedef void imapc_mailbox_callback_t(const struct imapc_untagged_reply *reply,
                                      struct imapc_mailbox *mbox);
 
 struct imapc_storage_event_callback {
-       const char *name;
+       char *name;
        imapc_storage_callback_t *callback;
 };
 
@@ -40,24 +40,32 @@ struct imapc_namespace {
        enum mail_namespace_type type;
 };
 
+struct imapc_storage_client {
+       int refcount;
+
+       /* either one of these may not be available: */
+       struct imapc_storage *_storage;
+       struct imapc_mailbox_list *_list;
+
+       struct imapc_client *client;
+
+       ARRAY(struct imapc_storage_event_callback) untagged_callbacks;
+};
+
 struct imapc_storage {
        struct mail_storage storage;
        const struct imapc_settings *set;
 
        struct ioloop *root_ioloop;
-       struct imapc_mailbox_list *list;
-       struct imapc_client *client;
-       char root_sep;
+       struct imapc_storage_client *client;
 
        struct imapc_mailbox *cur_status_box;
        struct mailbox_status *cur_status;
        unsigned int reopen_count;
 
        ARRAY(struct imapc_namespace) remote_namespaces;
-       ARRAY(struct imapc_storage_event_callback) untagged_callbacks;
 
        unsigned int namespaces_requested:1;
-       unsigned int root_sep_pending:1;
 };
 
 struct imapc_mail_cache {
@@ -110,10 +118,17 @@ struct imapc_mailbox {
 };
 
 struct imapc_simple_context {
-       struct imapc_storage *storage;
+       struct imapc_storage_client *client;
        int ret;
 };
 
+int imapc_storage_client_create(struct mail_namespace *ns,
+                               const struct imapc_settings *imapc_set,
+                               const struct mail_storage_settings *mail_set,
+                               struct imapc_storage_client **client_r,
+                               const char **error_r);
+void imapc_storage_client_unref(struct imapc_storage_client **client);
+
 struct mail_save_context *
 imapc_save_alloc(struct mailbox_transaction_context *_t);
 int imapc_save_begin(struct mail_save_context *ctx, struct istream *input);
@@ -130,13 +145,13 @@ 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);
 
+bool imap_resp_text_code_parse(const char *str, enum mail_error *error_r);
 void imapc_copy_error_from_reply(struct imapc_storage *storage,
                                 enum mail_error default_error,
                                 const struct imapc_command_reply *reply);
 void imapc_simple_context_init(struct imapc_simple_context *sctx,
-                              struct imapc_storage *storage);
+                              struct imapc_storage_client *client);
 void imapc_simple_run(struct imapc_simple_context *sctx);
 void imapc_simple_callback(const struct imapc_command_reply *reply,
                           void *context);
@@ -146,9 +161,9 @@ void imapc_mailbox_noop(struct imapc_mailbox *mbox);
 void imapc_mailbox_set_corrupted(struct imapc_mailbox *mbox,
                                 const char *reason, ...) ATTR_FORMAT(2, 3);
 
-void imapc_storage_register_untagged(struct imapc_storage *storage,
-                                    const char *name,
-                                    imapc_storage_callback_t *callback);
+void imapc_storage_client_register_untagged(struct imapc_storage_client *client,
+                                           const char *name,
+                                           imapc_storage_callback_t *callback);
 void imapc_mailbox_register_untagged(struct imapc_mailbox *mbox,
                                     const char *name,
                                     imapc_mailbox_callback_t *callback);
index 96b78b5bb390645c83ed48153670387284ce9809..9ce2f2baf1e131b67647f6c52d27199b3d01e063 100644 (file)
@@ -34,7 +34,7 @@ static void imapc_sync_callback(const struct imapc_command_reply *reply,
        }
        
        if (--ctx->sync_command_count == 0)
-               imapc_client_stop(ctx->mbox->storage->client);
+               imapc_client_stop(ctx->mbox->storage->client->client);
 }
 
 static void imapc_sync_cmd(struct imapc_sync_context *ctx, const char *cmd_str)
@@ -136,7 +136,7 @@ static void imapc_sync_expunge_finish(struct imapc_sync_context *ctx)
        if (array_count(&ctx->expunged_uids) == 0)
                return;
 
-       caps = imapc_client_get_capabilities(ctx->mbox->storage->client);
+       caps = imapc_client_get_capabilities(ctx->mbox->storage->client->client);
        if ((caps & IMAPC_CAPABILITY_UIDPLUS) == 0) {
                /* just expunge everything */
                imapc_sync_cmd(ctx, "EXPUNGE");
@@ -457,7 +457,7 @@ imapc_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
                        ret = -1;
        }
 
-       capabilities = imapc_client_get_capabilities(mbox->storage->client);
+       capabilities = imapc_client_get_capabilities(mbox->storage->client->client);
        if ((capabilities & IMAPC_CAPABILITY_IDLE) == 0) {
                /* IDLE not supported. do NOOP to get latest changes
                   before starting sync. */