Mercurial > dovecot > core-2.2
changeset 16586:620876853f6f
imapc: Reorganize code so that imapc_list works without imapc_storage.
Most importantly fixes crashes when imapc_list is trying to lookup hierarchy
separator before storage is created.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 10 Jul 2013 06:54:57 +0300 |
parents | e45ad5524f1a |
children | 331d0a4fe772 |
files | 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 |
diffstat | 7 files changed, 259 insertions(+), 203 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/imapc/imapc-list.c Wed Jul 10 06:05:20 2013 +0300 +++ b/src/lib-storage/index/imapc/imapc-list.c Wed Jul 10 06:54:57 2013 +0300 @@ -41,6 +41,12 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ } } -void imapc_list_register_callbacks(struct imapc_mailbox_list *list) +static void imapc_list_sep_verify(struct imapc_mailbox_list *list) +{ + 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) { - imapc_storage_register_untagged(list->storage, "LIST", - imapc_untagged_list); - imapc_storage_register_untagged(list->storage, "LSUB", - imapc_untagged_lsub); + 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 @@ 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 @@ 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 @@ 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);
--- a/src/lib-storage/index/imapc/imapc-list.h Wed Jul 10 06:05:20 2013 +0300 +++ b/src/lib-storage/index/imapc/imapc-list.h Wed Jul 10 06:54:57 2013 +0300 @@ -10,21 +10,22 @@ 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
--- a/src/lib-storage/index/imapc/imapc-mail-fetch.c Wed Jul 10 06:05:20 2013 +0300 +++ b/src/lib-storage/index/imapc/imapc-mail-fetch.c Wed Jul 10 06:54:57 2013 +0300 @@ -48,7 +48,7 @@ "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 @@ 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); } }
--- a/src/lib-storage/index/imapc/imapc-save.c Wed Jul 10 06:05:20 2013 +0300 +++ b/src/lib-storage/index/imapc/imapc-save.c Wed Jul 10 06:54:57 2013 +0300 @@ -66,7 +66,8 @@ 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 @@ "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 @@ /* 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 @@ 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 @@ 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 @@ "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)
--- a/src/lib-storage/index/imapc/imapc-storage.c Wed Jul 10 06:05:20 2013 +0300 +++ b/src/lib-storage/index/imapc/imapc-storage.c Wed Jul 10 06:54:57 2013 +0300 @@ -51,12 +51,11 @@ }; 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_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 @@ 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 @@ 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_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) +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_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) -{ + struct imapc_storage_client *client; struct imapc_client_settings set; string_t *str; @@ -290,53 +233,61 @@ 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; - + if (strcmp(ns->list->name, MAILBOX_LIST_NAME_IMAPC) == 0) { + 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); - 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"; - return -1; - } - } + 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 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_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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ imapc_storage_alloc, imapc_storage_create, imapc_storage_destroy, - imapc_storage_add_list, + NULL, imapc_storage_get_list_settings, NULL, imapc_mailbox_alloc,
--- a/src/lib-storage/index/imapc/imapc-storage.h Wed Jul 10 06:05:20 2013 +0300 +++ b/src/lib-storage/index/imapc/imapc-storage.h Wed Jul 10 06:54:57 2013 +0300 @@ -12,15 +12,15 @@ 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 @@ 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_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_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_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);
--- a/src/lib-storage/index/imapc/imapc-sync.c Wed Jul 10 06:05:20 2013 +0300 +++ b/src/lib-storage/index/imapc/imapc-sync.c Wed Jul 10 06:54:57 2013 +0300 @@ -34,7 +34,7 @@ } 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 @@ 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 @@ 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. */