bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
638734376d265a1529985755da671c09cfc22e06Timo Sirainenstatic void imapc_mail_set_failure(struct imapc_mail *mail,
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(mail->imail.mail.mail.box);
14fb3a2f6af1d75aeec6deb766026b4ea6a4db53Timo Sirainen mail->last_fetch_reply = p_strdup(mail->imail.mail.pool, reply->text_full);
638734376d265a1529985755da671c09cfc22e06Timo Sirainen if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_FIX_BROKEN_MAILS)) {
638734376d265a1529985755da671c09cfc22e06Timo Sirainen /* fetch-fix-broken-mails feature disabled -
638734376d265a1529985755da671c09cfc22e06Timo Sirainen fail any mails with missing replies */
740e369c027c3589f4074e7ea0a51204082853cbTimo Sirainen (strcasecmp(reply->resp_text_key, IMAP_RESP_CODE_SERVERBUG) == 0 ||
740e369c027c3589f4074e7ea0a51204082853cbTimo Sirainen strcasecmp(reply->resp_text_key, IMAP_RESP_CODE_LIMIT) == 0)) {
740e369c027c3589f4074e7ea0a51204082853cbTimo Sirainen /* this is a temporary error, retrying should work.
740e369c027c3589f4074e7ea0a51204082853cbTimo Sirainen Yahoo sends * BYE +
740e369c027c3589f4074e7ea0a51204082853cbTimo Sirainen NO [LIMIT] UID FETCH Rate limit hit. */
638734376d265a1529985755da671c09cfc22e06Timo Sirainen /* hopefully this is a permanent failure */
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenimapc_mail_fetch_callback(const struct imapc_command_reply *reply,
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen struct imapc_fetch_request *request = context;
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek mbox = IMAPC_MAILBOX(mail->imail.mail.mail.box);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen requests = array_get(&mbox->fetch_requests, &count);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen for (i = 0; i < count; i++) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen else if (reply->state == IMAPC_COMMAND_STATE_NO) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen imapc_copy_error_from_reply(mbox->storage, MAIL_ERROR_PARAMS,
063254ba79239f1c0a78ea08d4aa22f8f11d984cTimo Sirainen } else if (reply->state == IMAPC_COMMAND_STATE_DISCONNECTED) {
063254ba79239f1c0a78ea08d4aa22f8f11d984cTimo Sirainen /* The disconnection message was already logged */
063254ba79239f1c0a78ea08d4aa22f8f11d984cTimo Sirainen mail_storage_set_internal_error(&mbox->storage->storage);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen "imapc: Mail FETCH failed: %s", reply->text_full);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_client_stop(mbox->storage->client->client);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenheaders_have_subset(const char *const *superset, const char *const *subset)
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen unsigned int i;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (!str_array_icase_find(superset, subset[i]))
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenstatic const char *const *
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenheaders_merge(pool_t pool, const char *const *h1, const char *const *h2)
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen unsigned int i;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (h1 == NULL || !str_array_icase_find(h1, h2[i])) {
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenimapc_mail_try_merge_fetch(struct imapc_mailbox *mbox, string_t *str)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen const char *s2 = str_c(mbox->pending_fetch_cmd);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen /* skip over UID range */
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen /* append the new UID to the pending FETCH UID range */
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen str_insert(mbox->pending_fetch_cmd, p2-s2, ",");
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen str_insert(mbox->pending_fetch_cmd, p2-s2+1, str_c(str) + 10);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenimapc_mail_delayed_send_or_merge(struct imapc_mail *mail, string_t *str)
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(mail->imail.mail.mail.box);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen /* send the previous FETCH and create a new one */
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_array_init(&mbox->pending_fetch_request->mails, 4);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen array_append(&mbox->pending_fetch_request->mails, &mail, 1);
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen array_count(&mbox->pending_fetch_request->mails) >
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen mbox->box.storage->set->mail_prefetch_count) {
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen /* we're now prefetching the maximum number of mails. this
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen most likely means that we need to flush out the command now
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen before sending anything else. delay it a little bit though
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen in case the sending code doesn't actually use
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen mail_prefetch_count and wants to fetch more.
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen note that we don't want to add this timeout too early,
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen because we want to optimize the maximum number of messages
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen placed into a single FETCH. even without timeout the command
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen gets flushed by imapc_mail_fetch() call. */
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen timeout_add_short(0, imapc_mail_fetch_flush, mbox);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenimapc_mail_send_fetch(struct mail *_mail, enum mail_fetch_field fields,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const char *const *headers)
7dd326f772ed4193e1bfdafdb46fea616970e1acJosef 'Jeff' Sipek struct imapc_mail *mail = IMAPC_MAIL(_mail);
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(_mail->box);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen unsigned int i;
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_HEADERS));
1b0b44348d1f94f1f0e418d80323646e1e335c2bTimo Sirainen if (_mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* drop any fields that we may already be fetching currently */
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (headers_have_subset(mail->fetching_headers, headers))
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen /* if we already know that the mail is expunged,
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen don't try to FETCH it */
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen if (!mail_index_lookup_seq(view, _mail->uid, &seq) ||
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen /* opened as save-only. we'll need to fetch the mail,
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen so actually SELECT/EXAMINE the mailbox */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen str_printfa(str, "UID FETCH %u (", _mail->uid);
50ffc12831eff618d35a8ee7537b61eaa95a4adeTimo Sirainen if ((fields & (MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE)) != 0)
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if ((fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0)
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_ZIMBRA_WORKAROUNDS))
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen /* BODY.PEEK[] can return different headers than
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen BODY.PEEK[HEADER] (e.g. invalid 8bit chars replaced
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen with '?' in HEADER) - this violates IMAP protocol
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen and messes up dsync since it sometimes fetches the
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen full body and sometimes only the headers. */
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen str_append(str, "BODY.PEEK[HEADER] BODY.PEEK[TEXT] ");
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen } else if ((fields & MAIL_FETCH_STREAM_HEADER) != 0)
d81b80bac97040d5e737f23ce1ee2eb4d7cc16cfTimo Sirainen headers_merge(mail->imail.mail.data_pool, headers,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen for (i = 0; mail->fetching_headers[i] != NULL; i++) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen imap_append_astring(str, mail->fetching_headers[i]);
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainenstatic void imapc_mail_cache_get(struct imapc_mail *mail,
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi mail->imail.data.stream = i_stream_create_fd(mail->fd, 0);
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainenimapc_mail_get_wanted_fetch_fields(struct imapc_mail *mail)
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(mail->imail.mail.mail.box);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct index_mail_data *data = &mail->imail.data;
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen if ((data->wanted_fields & MAIL_FETCH_RECEIVED_DATE) != 0 &&
bf611d43256ef8ee3e1c1ce8e1257920f2075278Timo Sirainen if ((data->wanted_fields & MAIL_FETCH_SAVE_DATE) != 0 &&
bf611d43256ef8ee3e1c1ce8e1257920f2075278Timo Sirainen data->save_date == (time_t)-1 && data->received_date == (time_t)-1)
50ffc12831eff618d35a8ee7537b61eaa95a4adeTimo Sirainen if ((data->wanted_fields & (MAIL_FETCH_PHYSICAL_SIZE |
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE))
50ffc12831eff618d35a8ee7537b61eaa95a4adeTimo Sirainen fields |= MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if ((data->wanted_fields & MAIL_FETCH_IMAP_BODY) != 0 &&
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE))
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if ((data->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0 &&
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE))
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen if ((data->wanted_fields & MAIL_FETCH_GUID) != 0 &&
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen data->guid == NULL && mbox->guid_fetch_field_name != NULL)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (data->stream == NULL && data->access_part != 0) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if ((data->access_part & (READ_BODY | PARSE_BODY)) != 0)
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainenvoid imapc_mail_try_init_stream_from_cache(struct imapc_mail *mail)
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(_mail->box);
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen imapc_mail_cache_get(mail, &mbox->prev_mail_cache);
7dd326f772ed4193e1bfdafdb46fea616970e1acJosef 'Jeff' Sipek struct imapc_mail *mail = IMAPC_MAIL(_mail);
6a384c0f8980bfdefe40c42bf39d43302e58ad14Josef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(_mail->box);
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen struct index_mail_data *data = &mail->imail.data;
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen /* try to get as much from cache as possible */
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen /* If mail is already cached we can avoid re-FETCHing the mail.
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen However, don't initialize the stream if we don't actually want to
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen access the mail. */
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen fields = imapc_mail_get_wanted_fetch_fields(mail);
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen if (data->wanted_headers != NULL && data->stream == NULL &&
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen !imapc_mail_has_headers_in_cache(&mail->imail, data->wanted_headers)) {
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen /* fetch specific headers */
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_HEADERS))
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen if (imapc_mail_send_fetch(_mail, fields, headers) > 0)
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainenimapc_mail_have_fields(struct imapc_mail *imail, enum mail_fetch_field fields)
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if ((fields & MAIL_FETCH_RECEIVED_DATE) != 0) {
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (imail->imail.data.received_date == (time_t)-1)
50ffc12831eff618d35a8ee7537b61eaa95a4adeTimo Sirainen if ((fields & (MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE)) != 0) {
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen if (imail->imail.data.physical_size == (uoff_t)-1)
50ffc12831eff618d35a8ee7537b61eaa95a4adeTimo Sirainen fields &= ~(MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if ((fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0) {
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen fields &= ~(MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenint imapc_mail_fetch(struct mail *_mail, enum mail_fetch_field fields,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const char *const *headers)
7dd326f772ed4193e1bfdafdb46fea616970e1acJosef 'Jeff' Sipek struct imapc_mail *imail = IMAPC_MAIL(_mail);
6a384c0f8980bfdefe40c42bf39d43302e58ad14Josef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(_mail->box);
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen "Message GUID not available in this server");
969f57f722570982a5febbaab2462b692aa68733Timo Sirainen "Attempting to issue FETCH for a mail not yet committed");
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen fields |= imapc_mail_get_wanted_fetch_fields(imail);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen ret = imapc_mail_send_fetch(_mail, fields, headers);
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen /* we'll continue waiting until we've got all the fields we wanted,
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen or until all FETCH replies have been received (i.e. some FETCHes
1b0b44348d1f94f1f0e418d80323646e1e335c2bTimo Sirainen mail_storage_set_internal_error(&mbox->storage->storage);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenvoid imapc_mail_fetch_flush(struct imapc_mailbox *mbox)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_assert(mbox->to_pending_fetch_send == NULL);
2a1d9dda6e05f596b70703b74721847308127e3eTimo Sirainen array_foreach(&mbox->pending_fetch_request->mails, mailp)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen cmd = imapc_client_mailbox_cmd(mbox->client_box,
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
b7a672661c5642d6e8db9e96f7028b1af1e3255aTimo Sirainen array_append(&mbox->fetch_requests, &mbox->pending_fetch_request, 1);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen imapc_command_send(cmd, str_c(mbox->pending_fetch_cmd));
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&mbox->to_pending_fetch_send);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic bool imapc_find_lfile_arg(const struct imapc_untagged_reply *reply,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen for (i = 0; i < reply->file_args_count; i++) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const struct imapc_arg_file *farg = &reply->file_args[i];
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen imap_arg_get_list_full(arg->parent, &list, &count) &&
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen farg->list_idx < count && &list[farg->list_idx] == arg) {
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainenstatic void imapc_stream_filter(struct istream **input)
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen /* Added by MS Exchange 2010 when \Flagged flag is set.
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen This violates IMAP guarantee of messages being immutable. */
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen "X-Message-Flag"
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen filter_input = i_stream_create_header_filter(*input,
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen imapc_hide_headers, N_ELEMENTS(imapc_hide_headers),
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainenvoid imapc_mail_init_stream(struct imapc_mail *mail)
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(_mail->box);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen t_strdup_printf("imapc mail uid=%u", _mail->uid));
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen index_mail_set_read_buffer_size(_mail, imail->data.stream);
b8947936e65a9b79ffe1a4f7a9835c946a9b635bTimo Sirainen if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE)) {
b8947936e65a9b79ffe1a4f7a9835c946a9b635bTimo Sirainen /* enable filtering only when we're not passing through
b8947936e65a9b79ffe1a4f7a9835c946a9b635bTimo Sirainen RFC822.SIZE. otherwise we'll get size mismatches. */
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen ret = i_stream_get_size(imail->data.stream, TRUE, &size);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen /* we'll assume that the remote server is working properly and
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen sending CRLF linefeeds */
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imail->data.stream_has_only_header = !mail->body_fetched;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (index_mail_init_stream(imail, NULL, NULL, &input) < 0)
e01ebd51ac369430ec81945e3c5317d6d6244138Timo Sirainen struct imapc_mailbox *mbox = IMAPC_MAILBOX(imail->mail.mail.box);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen /* replace the existing stream */
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen /* append this body stream to the existing
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen header stream */
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen /* append this body stream to the existing
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen header stream. we'll need to recreate the stream
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen with autoclosed fd. */
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen hdr_stream = i_stream_create_fd_autoclose(&mail->fd, 0);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen /* BODY.PEEK[TEXT] received - we can't currently handle
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen this before receiving BODY.PEEK[HEADER] reply */
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi imail->data.stream = i_stream_create_fd(fd, 0);
e01ebd51ac369430ec81945e3c5317d6d6244138Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_EMPTY_IS_EXPUNGED))) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail->body = buffer_create_dynamic(default_pool,
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen } else if (!have_header && hdr_stream != NULL) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen /* header is already in the buffer - add body now
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen without destroying the existing header data */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen buffer_append(mail->body, value, arg->str_len);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen imail->data.stream = i_stream_create_from_data(mail->body->data,
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imail->data.stream = i_stream_create_concat(inputs);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenimapc_fetch_header_stream(struct imapc_mail *mail,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const enum message_header_parser_flags hdr_parser_flags =
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP |
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen struct mailbox_header_lookup_ctx *headers_ctx;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen /* see if this is reply to the latest headers list request
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen (parse it even if it's not) */
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen while (imap_arg_get_astring(hdr_list, &value)) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (headers_have_subset(array_idx(&hdr_arr, 0), mail->fetching_headers))
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen input = i_stream_create_from_data(value, args->str_len);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen headers_ctx = mailbox_header_lookup_init(mail->imail.mail.mail.box,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen index_mail_parse_header_init(&mail->imail, headers_ctx);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen parser = message_parse_header_init(input, NULL, hdr_parser_flags);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen while ((ret = message_parse_header_next(parser, &hdr)) > 0)
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen index_mail_parse_header(NULL, hdr, &mail->imail);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen index_mail_parse_header(NULL, NULL, &mail->imail);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainenstatic const char *
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainenimapc_args_to_bodystructure(struct imapc_mail *mail,
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen const struct imap_arg *list_arg, bool extended)
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(&mail->imail.mail.mail,
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen "imapc: Server sent invalid BODYSTRUCTURE parameters");
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen pool = pool_alloconly_create("imap bodystructure", 1024);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if (imap_bodystructure_parse_args(args, pool, &parts, &error) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(&mail->imail.mail.mail,
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen "imapc: Server sent invalid BODYSTRUCTURE: %s", error);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen imap_bodystructure_write(parts, str, extended);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen ret = p_strdup(mail->imail.mail.data_pool, str_c(str));
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenvoid imapc_mail_fetch_update(struct imapc_mail *mail,
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(mail->imail.mail.mail.box);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen unsigned int i;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen for (i = 0; args[i].type != IMAP_ARG_EOL; i += 2) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imapc_fetch_stream(mail, reply, &args[i+1], TRUE, TRUE);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else if (strcasecmp(key, "BODY[HEADER]") == 0) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imapc_fetch_stream(mail, reply, &args[i+1], TRUE, FALSE);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen } else if (strcasecmp(key, "BODY[TEXT]") == 0) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imapc_fetch_stream(mail, reply, &args[i+1], FALSE, TRUE);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen } else if (strcasecmp(key, "BODY[HEADER.FIELDS") == 0) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen imapc_fetch_header_stream(mail, reply, &args[i+1]);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else if (strcasecmp(key, "INTERNALDATE") == 0) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (imap_arg_get_astring(&args[i+1], &value) &&
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen imapc_args_to_bodystructure(mail, &args[i+1], FALSE);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen } else if (strcasecmp(key, "BODYSTRUCTURE") == 0) {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen imapc_args_to_bodystructure(mail, &args[i+1], TRUE);
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen } else if (strcasecmp(key, "RFC822.SIZE") == 0) {
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE))
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen } else if (strcasecmp(key, "X-GM-MSGID") == 0 ||
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen if (imap_arg_get_astring(&args[i+1], &value)) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* this is only a FETCH FLAGS update for the wanted mail */