bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstatic struct imapc_resp_code_map imapc_resp_code_map[] = {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_UNAVAILABLE, MAIL_ERROR_TEMP },
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_AUTHFAILED, MAIL_ERROR_PERM },
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_AUTHZFAILED, MAIL_ERROR_PERM },
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_PRIVACYREQUIRED, MAIL_ERROR_PERM },
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_CONTACTADMIN, MAIL_ERROR_PERM },
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_EXPUNGEISSUED, MAIL_ERROR_EXPUNGED },
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_CORRUPTION, MAIL_ERROR_TEMP },
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_SERVERBUG, MAIL_ERROR_TEMP },
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen /* { IMAP_RESP_CODE_CLIENTBUG, 0 }, */
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_CANNOT, MAIL_ERROR_NOTPOSSIBLE },
2ed2459dbd183bb371da4a0aecb2d2b74ae7c815Timo Sirainen { IMAP_RESP_CODE_OVERQUOTA, MAIL_ERROR_NOQUOTA },
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_ALREADYEXISTS, MAIL_ERROR_EXISTS },
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen { IMAP_RESP_CODE_NONEXISTENT, MAIL_ERROR_NOTFOUND }
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainenstatic void imapc_untagged_status(const struct imapc_untagged_reply *reply,
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainenstatic void imapc_untagged_namespace(const struct imapc_untagged_reply *reply,
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainenstatic int imapc_mailbox_run_status(struct mailbox *box,
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainenbool imap_resp_text_code_parse(const char *str, enum mail_error *error_r)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen unsigned int i;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen for (i = 0; i < N_ELEMENTS(imapc_resp_code_map); i++) {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (strcmp(imapc_resp_code_map[i].code, str) == 0) {
6e40a39f6886edbba5ad498391c299983f8f94e9Timo Sirainenbool imapc_mailbox_has_modseqs(struct imapc_mailbox *mbox)
150542702397445873dca327c82c5c7f09322437Timo Sirainen return (mbox->capabilities & (IMAPC_CAPABILITY_CONDSTORE |
6e40a39f6886edbba5ad498391c299983f8f94e9Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_MODSEQ);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstatic struct mail_storage *imapc_storage_alloc(void)
df48643c3c240ad5b8a3e2e2132c46f7dc541b5eTimo Sirainen pool = pool_alloconly_create("imapc storage", 2048);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen storage = p_new(pool, struct imapc_storage, 1);
689b06e33729491b593fe34ad3267d65b79be149Timo Sirainenvoid imapc_copy_error_from_reply(struct imapc_storage *storage,
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen if (imap_resp_text_code_parse(reply->resp_text_key, &error)) {
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen mail_storage_set_error(&storage->storage, error,
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen mail_storage_set_error(&storage->storage, default_error,
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainenvoid imapc_simple_context_init(struct imapc_simple_context *sctx,
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainenvoid imapc_simple_run(struct imapc_simple_context *sctx)
be21b9e65a37c29995899f7923f6d7e5771dc3adTimo Sirainen if (imapc_storage_client_handle_auth_failure(sctx->client)) {
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenvoid imapc_mailbox_run(struct imapc_mailbox *mbox)
fda7b3649d2ccdb4a95f5bf09eb8cf5435d57261Timo Sirainenvoid imapc_mailbox_run_nofetch(struct imapc_mailbox *mbox)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen imapc_client_run(mbox->storage->client->client);
90de49eb151c2be7655ce6aef5aa3b58295d5c84Timo Sirainenvoid imapc_simple_callback(const struct imapc_command_reply *reply,
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen else if (reply->state == IMAPC_COMMAND_STATE_NO) {
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_copy_error_from_reply(ctx->client->_storage,
be21b9e65a37c29995899f7923f6d7e5771dc3adTimo Sirainen } else if (imapc_storage_client_handle_auth_failure(ctx->client)) {
b80e0097ab96ca62d1b9ddf4b2d7b7c77c745307Timo Sirainen } else if (reply->state == IMAPC_COMMAND_STATE_DISCONNECTED) {
b80e0097ab96ca62d1b9ddf4b2d7b7c77c745307Timo Sirainen mail_storage_set_internal_error(&ctx->client->_storage->storage);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen mail_storage_set_critical(&ctx->client->_storage->storage,
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen "imapc: Command failed: %s", reply->text_full);
b50e80d237435686c4ea525643f266731a600981Timo Sirainenvoid imapc_mailbox_noop(struct imapc_mailbox *mbox)
ad9403d54b5a0f312de6fa22abda6c120988d3deTimo Sirainen /* mailbox opening hasn't finished yet */
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_simple_context_init(&sctx, mbox->storage->client);
b50e80d237435686c4ea525643f266731a600981Timo Sirainen cmd = imapc_client_mailbox_cmd(mbox->client_box,
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainenimapc_storage_client_untagged_cb(const struct imapc_untagged_reply *reply,
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen struct imapc_storage_client *client = context;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen struct imapc_mailbox *mbox = reply->untagged_box_context;
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen const struct imapc_storage_event_callback *cb;
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen const struct imapc_mailbox_event_callback *mcb;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen array_foreach(&client->untagged_callbacks, cb) {
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen array_foreach(&mbox->untagged_callbacks, mcb) {
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen array_foreach(&mbox->resp_text_callbacks, mcb) {
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen if (strcasecmp(reply->resp_text_key, mcb->name) == 0)
92cd929df2ebf3291886a11542b2815a426e906dTimo Sirainenimapc_storage_client_login_callback(const struct imapc_command_reply *reply,
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen struct imapc_storage_client *client = context;
9a717bf84366bdd2ee25f95c49ffc911999dbd1fTimo Sirainen reply->state == IMAPC_COMMAND_STATE_DISCONNECTED) {
9a717bf84366bdd2ee25f95c49ffc911999dbd1fTimo Sirainen /* user's work was finished before imapc login finished -
9a717bf84366bdd2ee25f95c49ffc911999dbd1fTimo Sirainen it's not an error */
28576b6283287ef3ca6ae0d818ebd4ce6c879107Timo Sirainen client->auth_failed_reason = i_strdup(reply->text_full);
ab838f1555795d5766bdaef795a14c98a5437c9eTimo Sirainen if (!imapc_storage_client_handle_auth_failure(client))
ab838f1555795d5766bdaef795a14c98a5437c9eTimo Sirainenbool imapc_storage_client_handle_auth_failure(struct imapc_storage_client *client)
ab838f1555795d5766bdaef795a14c98a5437c9eTimo Sirainen if (client->auth_failed_state == IMAPC_COMMAND_STATE_OK)
ab838f1555795d5766bdaef795a14c98a5437c9eTimo Sirainen /* We need to set the error to either storage or to list, depending on
ab838f1555795d5766bdaef795a14c98a5437c9eTimo Sirainen whether the caller is from mail-storage.h API or mailbox-list.h API.
ab838f1555795d5766bdaef795a14c98a5437c9eTimo Sirainen We don't know here what the caller is though, so just set the error
ab838f1555795d5766bdaef795a14c98a5437c9eTimo Sirainen to both of them. */
ab838f1555795d5766bdaef795a14c98a5437c9eTimo Sirainen if (client->auth_failed_state == IMAPC_COMMAND_STATE_DISCONNECTED)
014cfdf92b145bc7ff4d1393ca24dfef5c109b0fTimo Sirainen mail_storage_set_internal_error(&client->_storage->storage);
014cfdf92b145bc7ff4d1393ca24dfef5c109b0fTimo Sirainen mail_storage_set_error(&client->_storage->storage,
ab838f1555795d5766bdaef795a14c98a5437c9eTimo Sirainen if (client->auth_failed_state == IMAPC_COMMAND_STATE_DISCONNECTED)
014cfdf92b145bc7ff4d1393ca24dfef5c109b0fTimo Sirainen mailbox_list_set_internal_error(&client->_list->list);
92cd929df2ebf3291886a11542b2815a426e906dTimo Sirainenstatic void imapc_storage_client_login(struct imapc_storage_client *client,
92cd929df2ebf3291886a11542b2815a426e906dTimo Sirainen /* we're still initializing the user. wait for the
92cd929df2ebf3291886a11542b2815a426e906dTimo Sirainen login to finish, so we can fail the user creation
92cd929df2ebf3291886a11542b2815a426e906dTimo Sirainen if it fails. */
be21b9e65a37c29995899f7923f6d7e5771dc3adTimo Sirainen if (imapc_storage_client_handle_auth_failure(client)) {
92cd929df2ebf3291886a11542b2815a426e906dTimo Sirainen "imapc: Login to %s failed: %s",
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainenint imapc_storage_client_create(struct mail_namespace *ns,
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen const char **error_r)
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen set.master_user = imapc_set->imapc_master_user;
c6033074ada5c7441ff7bb12c4b433cae737fea2Timo Sirainen set.sasl_mechanisms = imapc_set->imapc_sasl_mechanisms;
bd06c77a12bb02871b25dceb749fa955f4a272ffTimo Sirainen set.use_proxyauth = (imapc_set->parsed_features & IMAPC_FEATURE_PROXYAUTH) != 0;
cff23ec51177f11902c99b727268eb05ea7c97c7Timo Sirainen set.cmd_timeout_msecs = imapc_set->imapc_cmd_timeout * 1000;
c515f5c969f7a3a5b525ab15bde2f116cbe932deAki Tuomi set.connect_retry_count = imapc_set->imapc_connection_retry_count;
efd4de737ee4febffced006511f357959234a6caTimo Sirainen set.connect_retry_interval_msecs = imapc_set->imapc_connection_retry_interval;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen set.max_idle_time = imapc_set->imapc_max_idle_time;
c23ebb9b0e0b760ca8da16fde34ff33f5ece5e07Timo Sirainen set.max_line_length = imapc_set->imapc_max_line_length;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen set.dns_client_socket_path = *ns->user->set->base_dir == '\0' ? "" :
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen set.rawlog_dir = mail_user_home_expand(ns->user,
3c8055b25beef96e7be25895bac34f3eda7ceca1Timo Sirainen if ((imapc_set->parsed_features & IMAPC_FEATURE_SEND_ID) != 0)
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen mail_user_set_get_temp_prefix(str, ns->user->set);
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen set.ssl_ca_file = mail_set->ssl_client_ca_file;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen if (strcmp(imapc_set->imapc_ssl, "imaps") == 0)
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen set.ssl_mode = IMAPC_CLIENT_SSL_MODE_IMMEDIATE;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen else if (strcmp(imapc_set->imapc_ssl, "starttls") == 0)
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen set.ssl_mode = IMAPC_CLIENT_SSL_MODE_STARTTLS;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen set.ssl_crypto_device = mail_set->ssl_crypto_device;
de26c21cfadf24c1fa59f06414854d58b3d8baadTimo Sirainen set.throttle_set.init_msecs = imapc_set->throttle_init_msecs;
de26c21cfadf24c1fa59f06414854d58b3d8baadTimo Sirainen set.throttle_set.max_msecs = imapc_set->throttle_max_msecs;
de26c21cfadf24c1fa59f06414854d58b3d8baadTimo Sirainen set.throttle_set.shrink_min_msecs = imapc_set->throttle_shrink_min_msecs;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen client = i_new(struct imapc_storage_client, 1);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen i_array_init(&client->untagged_callbacks, 16);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_client_register_untagged(client->client,
276c62e4538faf5bf3ae127a7b7c246c5d37add2Aki Tuomi imapc_client_set_login_callback(client->client, imapc_storage_client_login_callback, client);
30871b77e627d3d6b244305fbea7aeee578f2927Timo Sirainen if ((ns->flags & NAMESPACE_FLAG_LIST_PREFIX) != 0 &&
30871b77e627d3d6b244305fbea7aeee578f2927Timo Sirainen (imapc_set->parsed_features & IMAPC_FEATURE_DELAY_LOGIN) == 0) {
c1a2ab40974dc48ca68b9fc58799b01bbcb9520bTimo Sirainen /* start logging in immediately */
92cd929df2ebf3291886a11542b2815a426e906dTimo Sirainen imapc_storage_client_login(client, ns->user, set.host);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainenvoid imapc_storage_client_unref(struct imapc_storage_client **_client)
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen struct imapc_storage_client *client = *_client;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen array_foreach_modifiable(&client->untagged_callbacks, cb)
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainenimapc_storage_create(struct mail_storage *_storage,
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen const char **error_r)
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_storage *storage = IMAPC_STORAGE(_storage);
46e917c9fa05cbe7bddf805d3a9838b61e3960e1Timo Sirainen storage->set = mail_namespace_get_driver_settings(ns, _storage);
1f4d459111419a47021e677839439f2e2ca78ad5Josef 'Jeff' Sipek /* serialize all the settings */
1f4d459111419a47021e677839439f2e2ca78ad5Josef 'Jeff' Sipek _storage->unique_root_dir = p_strdup_printf(_storage->pool,
1f4d459111419a47021e677839439f2e2ca78ad5Josef 'Jeff' Sipek "%s%s://(%s|%s):%s@%s:%u/%s mechs:%s features:%s "
2f26f75219804e775c44f6b45a201a941d5590c3Timo Sirainen "rawlog:%s cmd_timeout:%u maxidle:%u maxline:%"PRIuSIZE_T"u "
1f4d459111419a47021e677839439f2e2ca78ad5Josef 'Jeff' Sipek "pop3delflg:%s root_dir:%s",
1f4d459111419a47021e677839439f2e2ca78ad5Josef 'Jeff' Sipek storage->set->imapc_ssl_verify ? "(verify)" : "",
1f4d459111419a47021e677839439f2e2ca78ad5Josef 'Jeff' Sipek (size_t) storage->set->imapc_max_line_length,
af466fd3ee9d17f2e7b264079d25306c5598b200Timo Sirainen if (strcmp(ns->list->name, MAILBOX_LIST_NAME_IMAPC) == 0) {
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_list = (struct imapc_mailbox_list *)ns->list;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen if (imapc_storage_client_create(ns, storage->set, _storage->set,
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen p_array_init(&storage->remote_namespaces, _storage->pool, 4);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if (IMAPC_HAS_FEATURE(storage, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen MAIL_FETCH_IMAP_BODY | MAIL_FETCH_IMAP_BODYSTRUCTURE;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_storage_client_register_untagged(storage->client, "STATUS",
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_storage_client_register_untagged(storage->client, "NAMESPACE",
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstatic void imapc_storage_destroy(struct mail_storage *_storage)
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_storage *storage = IMAPC_STORAGE(_storage);
9a7f22e2c14b507e6044e5534df978a0c3b638d0Timo Sirainen /* make sure all pending commands are aborted before anything is
9a7f22e2c14b507e6044e5534df978a0c3b638d0Timo Sirainen deinitialized */
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainenvoid imapc_storage_client_register_untagged(struct imapc_storage_client *client,
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen cb = array_append_space(&client->untagged_callbacks);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenimapc_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstatic struct mailbox *
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenimapc_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
feccf3f8679807f25d105521d5f6ddce6df7cdceTimo Sirainen pool = pool_alloconly_create("imapc mailbox", 1024*4);
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen index_storage_mailbox_alloc(&mbox->box, vname, flags, MAIL_INDEX_PREFIX);
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen p_array_init(&mbox->untagged_callbacks, pool, 16);
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen p_array_init(&mbox->resp_text_callbacks, pool, 16);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen p_array_init(&mbox->fetch_requests, pool, 16);
d30c35e25ea6d935393e031509e6e22422b1e006Timo Sirainen p_array_init(&mbox->delayed_expunged_uids, pool, 16);
f97b503210435b74de3b26cba07315cbc9ea1dfcTimo Sirainenconst char *imapc_mailbox_get_remote_name(struct imapc_mailbox *mbox)
f97b503210435b74de3b26cba07315cbc9ea1dfcTimo Sirainen if (strcmp(mbox->box.list->name, MAILBOX_LIST_NAME_IMAPC) != 0)
f97b503210435b74de3b26cba07315cbc9ea1dfcTimo Sirainen return imapc_list_to_remote((struct imapc_mailbox_list *)mbox->box.list,
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainenimapc_mailbox_exists(struct mailbox *box, bool auto_boxes ATTR_UNUSED,
378653a02a5a673e995f47e48a3371804171f964Timo Sirainen if (strcmp(box->list->name, MAILBOX_LIST_NAME_IMAPC) != 0) {
1f31b38b6668439f0ee135c150dd2a71c2fa54c9Aki Tuomi struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)box->list;
be21b9e65a37c29995899f7923f6d7e5771dc3adTimo Sirainen if (imapc_storage_client_handle_auth_failure(list->client)) {
1f31b38b6668439f0ee135c150dd2a71c2fa54c9Aki Tuomi mail_storage_copy_list_error(box->storage, box->list);
e74f4afdd0cdeeb9a5cebd7973dfc9adbe6cb426Timo Sirainen if (imapc_list_get_mailbox_flags(box->list, box->name, &flags) < 0) {
e74f4afdd0cdeeb9a5cebd7973dfc9adbe6cb426Timo Sirainen mail_storage_copy_list_error(box->storage, box->list);
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainenstatic bool imapc_mailbox_want_examine(struct imapc_mailbox *mbox)
df596e34b604e6ac873de9ca92fb5df2a5fed45fTimo Sirainen if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_NO_EXAMINE)) {
df596e34b604e6ac873de9ca92fb5df2a5fed45fTimo Sirainen /* mainly a Courier-workaround: With POP3-only Maildir that
df596e34b604e6ac873de9ca92fb5df2a5fed45fTimo Sirainen doesn't have UIDVALIDITY set, EXAMINE won't generate a
df596e34b604e6ac873de9ca92fb5df2a5fed45fTimo Sirainen permanent UIDVALIDITY while SELECT will. */
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen return (mbox->box.flags & MAILBOX_FLAG_DROP_RECENT) == 0 &&
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen ((mbox->box.flags & MAILBOX_FLAG_READONLY) != 0 ||
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen (mbox->box.flags & MAILBOX_FLAG_SAVEONLY) != 0);
6e853fdf3a5670a2eb2d57b059afcee7fb6cbd47Timo Sirainenimapc_mailbox_verify_select(struct imapc_mailbox *mbox, const char **error_r)
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainenimapc_mailbox_reopen_callback(const struct imapc_command_reply *reply,
2352ce293bab6bb5371805d8c58a09f15a11e0c9Timo Sirainen else if (imapc_mailbox_verify_select(mbox, &errmsg)) {
6e853fdf3a5670a2eb2d57b059afcee7fb6cbd47Timo Sirainen imapc_client_mailbox_reconnect(mbox->client_box,
6e853fdf3a5670a2eb2d57b059afcee7fb6cbd47Timo Sirainen t_strdup_printf("Reopening mailbox '%s' failed: %s",
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_client_stop(mbox->storage->client->client);
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainenstatic void imapc_mailbox_reopen(void *context)
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen /* we're reconnecting and need to reopen the mailbox */
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen imapc_msgmap_reset(imapc_client_mailbox_get_msgmap(mbox->client_box));
bc3309d262b7e38e20446d302caea9a05888f6c1Timo Sirainen /* We reconnected during the initial SELECT/EXAMINE. It'll be
bc3309d262b7e38e20446d302caea9a05888f6c1Timo Sirainen automatically resent by lib-imap-client, so we don't need to
bc3309d262b7e38e20446d302caea9a05888f6c1Timo Sirainen send it again here. */
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen cmd = imapc_client_mailbox_cmd(mbox->client_box,
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_SELECT);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenimapc_mailbox_open_callback(const struct imapc_command_reply *reply,
6e853fdf3a5670a2eb2d57b059afcee7fb6cbd47Timo Sirainen if (!imapc_mailbox_verify_select(ctx->mbox, &error)) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi "imapc: Opening mailbox failed: %s", error);
6e853fdf3a5670a2eb2d57b059afcee7fb6cbd47Timo Sirainen } else if (reply->state == IMAPC_COMMAND_STATE_NO) {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen imapc_copy_error_from_reply(ctx->mbox->storage,
be21b9e65a37c29995899f7923f6d7e5771dc3adTimo Sirainen } else if (imapc_storage_client_handle_auth_failure(ctx->mbox->storage->client)) {
b80e0097ab96ca62d1b9ddf4b2d7b7c77c745307Timo Sirainen } else if (reply->state == IMAPC_COMMAND_STATE_DISCONNECTED) {
b80e0097ab96ca62d1b9ddf4b2d7b7c77c745307Timo Sirainen mail_storage_set_internal_error(ctx->mbox->box.storage);
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi "imapc: Opening mailbox failed: %s", reply->text_full);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_client_stop(ctx->mbox->storage->client->client);
e00612b245b41cc47a5c6214794c415aaa8c91b7Timo Sirainenstatic int imapc_mailbox_get_capabilities(struct imapc_mailbox *mbox)
f94abb02d228a078defac6d457f15cb6d8f82ddaTimo Sirainen /* If authentication failed, don't check again. */
f94abb02d228a078defac6d457f15cb6d8f82ddaTimo Sirainen if (imapc_storage_client_handle_auth_failure(mbox->storage->client))
e00612b245b41cc47a5c6214794c415aaa8c91b7Timo Sirainen return imapc_client_get_capabilities(mbox->storage->client->client,
150542702397445873dca327c82c5c7f09322437Timo Sirainenstatic void imapc_mailbox_get_extensions(struct imapc_mailbox *mbox)
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen /* see if we can get message GUIDs somehow */
150542702397445873dca327c82c5c7f09322437Timo Sirainen if ((mbox->capabilities & IMAPC_CAPABILITY_X_GM_EXT_1) != 0) {
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainenint imapc_mailbox_select(struct imapc_mailbox *mbox)
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_client_mailbox_open(mbox->storage->client->client, mbox);
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen imapc_client_mailbox_set_reopen_cb(mbox->client_box,
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen cmd = imapc_client_mailbox_cmd(mbox->client_box,
e82efb347c91c199218e41065c2acb3464247b1aTimo Sirainen imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_SELECT |
f8f30bd27e41e1041a8de0b97f35d7d75e0a412eTimo Sirainen while (ctx.ret == -2 || mbox->state_fetching_uid1)
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainenstatic int imapc_mailbox_open(struct mailbox *box)
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(box);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (index_storage_mailbox_open(box, FALSE) < 0)
689b06e33729491b593fe34ad3267d65b79be149Timo Sirainen if (box->deleting || (box->flags & MAILBOX_FLAG_SAVEONLY) != 0) {
51130f00bbd1e119ec042d63c148a78ac06ab85eTimo Sirainen /* We don't actually want to SELECT the mailbox. */
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen (box->list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0) {
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen /* trying to open INBOX as the namespace prefix.
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen Don't allow this. */
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen "Mailbox isn't selectable");
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainenvoid imapc_mail_cache_free(struct imapc_mail_cache *cache)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstatic void imapc_mailbox_close(struct mailbox *box)
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(box);
e709efb3dc325b2badbefdf140c940281d415d14Timo Sirainen (void)imapc_mailbox_commit_delayed_trans(mbox, &changes);
51130f00bbd1e119ec042d63c148a78ac06ab85eTimo Sirainen imapc_client_mailbox_close(&mbox->client_box);
97ff916ad7977bb8147750b8cf40d0d25d0730f6Timo Sirainen imapc_mail_cache_free(&mbox->prev_mail_cache);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen const struct mailbox_update *update ATTR_UNUSED,
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(box);
6e2bb07ff164bbac054cc53a4b4ca0d8aee909d1Timo Sirainen const char *name = imapc_mailbox_get_remote_name(mbox);
6e2bb07ff164bbac054cc53a4b4ca0d8aee909d1Timo Sirainen else if (strcmp(box->list->name, MAILBOX_LIST_NAME_IMAPC) == 0) {
6e2bb07ff164bbac054cc53a4b4ca0d8aee909d1Timo Sirainen name = t_strdup_printf("%s%c", name, imapc_list->root_sep);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_simple_context_init(&sctx, mbox->storage->client);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen cmd = imapc_client_cmd(mbox->storage->client->client,
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstatic int imapc_mailbox_update(struct mailbox *box,
6bb12832eb490920803b5ad184b1759c63f455bfTimo Sirainen if (!guid_128_is_empty(update->mailbox_guid) ||
6bb12832eb490920803b5ad184b1759c63f455bfTimo Sirainen update->uid_validity != 0 || update->min_next_uid != 0 ||
6bb12832eb490920803b5ad184b1759c63f455bfTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
6bb12832eb490920803b5ad184b1759c63f455bfTimo Sirainen "Not supported");
6bb12832eb490920803b5ad184b1759c63f455bfTimo Sirainen return index_storage_mailbox_update(box, update);
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainenstatic void imapc_untagged_status(const struct imapc_untagged_reply *reply,
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen struct imapc_storage *storage = client->_storage;
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainen unsigned int i;
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainen if (!imap_arg_get_astring(&reply->args[0], &name) ||
d78eb0a68297f3588a9ffe5a78e496ad500fb1e0Timo Sirainen if (strcmp(storage->cur_status_box->box.name, name) == 0) {
d78eb0a68297f3588a9ffe5a78e496ad500fb1e0Timo Sirainen } else if (strcasecmp(storage->cur_status_box->box.name, "INBOX") == 0 &&
d78eb0a68297f3588a9ffe5a78e496ad500fb1e0Timo Sirainen /* case-insensitive INBOX */
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainen for (i = 0; list[i].type != IMAP_ARG_EOL; i += 2) {
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainen else if (strcasecmp(key, "HIGHESTMODSEQ") == 0 &&
6e40a39f6886edbba5ad498391c299983f8f94e9Timo Sirainen imapc_mailbox_has_modseqs(storage->cur_status_box))
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainenstatic void imapc_untagged_namespace(const struct imapc_untagged_reply *reply,
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen struct imapc_storage *storage = client->_storage;
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen static enum mail_namespace_type ns_types[] = {
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen unsigned int i;
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen if (!imap_arg_get_list(&reply->args[i], &list))
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen ns = array_append_space(&storage->remote_namespaces);
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen ns->prefix = p_strdup(storage->storage.pool, prefix);
67445e2ac5a75d361d3c68eedcb9e1a3655440b8Timo Sirainenstatic void imapc_mailbox_get_selected_status(struct imapc_mailbox *mbox,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen index_storage_get_open_status(&mbox->box, items, status_r);
d1b3f17d857237ea9a27bb58785bd5c6f0d3a185Timo Sirainen status_r->permanent_flags = mbox->permanent_flags;
acfdd1b1625fae310faee8e5e2480c4f224fb648Timo Sirainen status_r->first_recent_uid = mbox->highest_nonrecent_uid + 1;
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainen /* FIXME: this doesn't work perfectly. we're now just returning
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainen the HIGHESTMODSEQ from the current index, which may or may
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainen not be correct. with QRESYNC enabled we could be returning
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainen sync_highestmodseq, but that would require implementing
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainen VANISHED replies. and without QRESYNC we'd have to issue
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainen STATUS (HIGHESTMODSEQ), which isn't efficient since we get
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainen here constantly (after every IMAP command). */
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainen /* even if local indexes are only in memory, we still
90355e35d1139e446a99733986a9181bd7f05dd4Timo Sirainen have modseqs on the IMAP server itself. */
58ba0fe5a6904d3a65cfe268411f4cbb881234eeTimo Sirainenstatic int imapc_mailbox_delete(struct mailbox *box)
b5d2b15b763729a19a03b905d5ae341f759c7db2Timo Sirainenstatic int imapc_mailbox_run_status(struct mailbox *box,
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(box);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen /* nothing requested */
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_simple_context_init(&sctx, mbox->storage->client);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen cmd = imapc_client_cmd(mbox->storage->client->client,
06116e6a19bc4916ddf349108e59e38eda83d533Timo Sirainen imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
e21baa33b4f1e7ad095566341515e65f51acadf6Timo Sirainen imapc_mailbox_get_remote_name(mbox), str_c(str)+1);
b5d2b15b763729a19a03b905d5ae341f759c7db2Timo Sirainenstatic int imapc_mailbox_get_status(struct mailbox *box,
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(box);
b5d2b15b763729a19a03b905d5ae341f759c7db2Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_GUID_FORCED))
67445e2ac5a75d361d3c68eedcb9e1a3655440b8Timo Sirainen imapc_mailbox_get_selected_status(mbox, items, status_r);
b5d2b15b763729a19a03b905d5ae341f759c7db2Timo Sirainen } else if ((items & (STATUS_FIRST_UNSEEN_SEQ | STATUS_KEYWORDS |
b5d2b15b763729a19a03b905d5ae341f759c7db2Timo Sirainen /* getting these requires opening the mailbox */
67445e2ac5a75d361d3c68eedcb9e1a3655440b8Timo Sirainen imapc_mailbox_get_selected_status(mbox, items, status_r);
b5d2b15b763729a19a03b905d5ae341f759c7db2Timo Sirainen if (imapc_mailbox_run_status(box, items, status_r) < 0)
08b9350b17bb0abd822dd1f11452df1476077747Timo Sirainen if (box->opened && !box->deleting && (items & STATUS_UIDNEXT) != 0 &&
b5d2b15b763729a19a03b905d5ae341f759c7db2Timo Sirainen /* Courier-workaround, it doesn't send UIDNEXT on SELECT */
b5d2b15b763729a19a03b905d5ae341f759c7db2Timo Sirainen if (imapc_mailbox_run_status(box, STATUS_UIDNEXT, status_r) < 0)
150542702397445873dca327c82c5c7f09322437Timo Sirainenstatic int imapc_mailbox_get_namespaces(struct imapc_mailbox *mbox)
150542702397445873dca327c82c5c7f09322437Timo Sirainen struct imapc_storage *storage = mbox->storage;
150542702397445873dca327c82c5c7f09322437Timo Sirainen if ((mbox->capabilities & IMAPC_CAPABILITY_NAMESPACE) == 0) {
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen /* NAMESPACE capability not supported */
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_simple_context_init(&sctx, storage->client);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen cmd = imapc_client_cmd(storage->client->client,
06116e6a19bc4916ddf349108e59e38eda83d533Timo Sirainen imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainenstatic const struct imapc_namespace *
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainenimapc_namespace_find_mailbox(struct imapc_storage *storage, const char *name)
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen const struct imapc_namespace *ns, *best_ns = NULL;
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen array_foreach(&storage->remote_namespaces, ns) {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstatic int imapc_mailbox_get_metadata(struct mailbox *box,
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(box);
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainen /* a bit ugly way to do this, but better than nothing for now.
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainen FIXME: if indexes are enabled, keep this there. */
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainen mail_generate_guid_128_hash(box->name, metadata_r->guid);
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen if ((items & MAILBOX_METADATA_BACKEND_NAMESPACE) != 0) {
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen ns = imapc_namespace_find_mailbox(mbox->storage, box->name);
40c0aad390ce459959f5e26bab8a2ea7818d1addTimo Sirainen if (index_mailbox_get_metadata(box, items, metadata_r) < 0)
b50e80d237435686c4ea525643f266731a600981Timo Sirainenstatic void imapc_noop_callback(const struct imapc_command_reply *reply,
b50e80d237435686c4ea525643f266731a600981Timo Sirainen else if (reply->state == IMAPC_COMMAND_STATE_NO)
b50e80d237435686c4ea525643f266731a600981Timo Sirainen imapc_copy_error_from_reply(storage, MAIL_ERROR_PARAMS, reply);
b50e80d237435686c4ea525643f266731a600981Timo Sirainen else if (reply->state == IMAPC_COMMAND_STATE_DISCONNECTED)
b50e80d237435686c4ea525643f266731a600981Timo Sirainen mail_storage_set_internal_error(&storage->storage);
8c98b8adba0e70743d5d8c35ae922038881b1f47Timo Sirainenstatic void imapc_idle_timeout(struct imapc_mailbox *mbox)
81d3c215bb1fdbda2cf7ccd9519f6b4fd03c3791Timo Sirainen cmd = imapc_client_mailbox_cmd(mbox->client_box,
6021cfec086e455d5bf5db35522953e13a97bb61Timo Sirainenstatic void imapc_idle_noop_callback(const struct imapc_command_reply *reply,
e809db9220c804b16d4d74782433a1075da12274Timo Sirainen imapc_noop_callback(reply, mbox->box.storage);
8c98b8adba0e70743d5d8c35ae922038881b1f47Timo Sirainenstatic void imapc_notify_changes(struct mailbox *box)
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(box);
9438ecaf1caee1bb33c8d7f638742875ac42c4e5Timo Sirainen const struct mail_storage_settings *set = box->storage->set;
150542702397445873dca327c82c5c7f09322437Timo Sirainen if ((mbox->capabilities & IMAPC_CAPABILITY_IDLE) != 0) {
847112173a65f36251cf39a7fd7d86eba6739953Timo Sirainen /* remote server is already in IDLE. but since some servers
847112173a65f36251cf39a7fd7d86eba6739953Timo Sirainen don't notice changes immediately, we'll force them to check
847112173a65f36251cf39a7fd7d86eba6739953Timo Sirainen here by sending a NOOP. this helps with clients that break
847112173a65f36251cf39a7fd7d86eba6739953Timo Sirainen IDLE when clicking "get mail". */
81d3c215bb1fdbda2cf7ccd9519f6b4fd03c3791Timo Sirainen cmd = imapc_client_mailbox_cmd(mbox->client_box,
8c98b8adba0e70743d5d8c35ae922038881b1f47Timo Sirainen /* remote server doesn't support IDLE.
8c98b8adba0e70743d5d8c35ae922038881b1f47Timo Sirainen check for changes with NOOP every once in a while. */
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen i_assert(!imapc_client_is_running(mbox->storage->client->client));
9438ecaf1caee1bb33c8d7f638742875ac42c4e5Timo Sirainen timeout_add(set->mailbox_idle_check_interval * 1000,
df48643c3c240ad5b8a3e2e2132c46f7dc541b5eTimo Sirainenstatic bool imapc_is_inconsistent(struct mailbox *box)
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(box);
4733d3729d64480179a30698bb3412d0a074b6ebTimo Sirainen !imapc_client_mailbox_is_opened(mbox->client_box);