imapc-mail-fetch.c revision d81b80bac97040d5e737f23ce1ee2eb4d7cc16cf
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2011-2013 Dovecot authors, see the included COPYING file */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "lib.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "str.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "istream.h"
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen#include "istream-header-filter.h"
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen#include "message-header-parser.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "imap-arg.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "imap-date.h"
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen#include "imap-quote.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "imapc-client.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "imapc-mail.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "imapc-storage.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic void
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenimapc_mail_prefetch_callback(const struct imapc_command_reply *reply,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen void *context)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct imapc_mail *mail = context;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct imapc_mailbox *mbox =
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen (struct imapc_mailbox *)mail->imail.mail.mail.box;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen i_assert(mail->fetch_count > 0);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (--mail->fetch_count == 0) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct imapc_mail *const *fetch_mails;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen unsigned int i, count;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen fetch_mails = array_get(&mbox->fetch_mails, &count);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen for (i = 0; i < count; i++) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (fetch_mails[i] == mail) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen array_delete(&mbox->fetch_mails, i, 1);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen break;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen i_assert(i != count);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail->fetching_fields = 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (reply->state == IMAPC_COMMAND_STATE_OK)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen ;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen else if (reply->state == IMAPC_COMMAND_STATE_NO) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen imapc_copy_error_from_reply(mbox->storage, MAIL_ERROR_PARAMS,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen reply);
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);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
e809db9220c804b16d4d74782433a1075da12274Timo Sirainen "imapc: Mail prefetch failed: %s", reply->text_full);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
6ac48a4295edbeb6b962700be3c563ad015c0a4eTimo Sirainen pool_unref(&mail->imail.mail.pool);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_client_stop(mbox->storage->client->client);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenstatic bool
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenheaders_have_subset(const char *const *superset, const char *const *subset)
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen{
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen unsigned int i;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (superset == NULL)
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen return FALSE;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (subset != NULL) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen for (i = 0; subset[i] != NULL; i++) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (!str_array_icase_find(superset, subset[i]))
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen return FALSE;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen return TRUE;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen}
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenstatic const char *const *
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenheaders_merge(pool_t pool, const char *const *h1, const char *const *h2)
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen{
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen ARRAY_TYPE(const_string) headers;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const char *value;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen unsigned int i;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen p_array_init(&headers, pool, 16);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (h1 != NULL) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen for (i = 0; h1[i] != NULL; i++) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen value = p_strdup(pool, h1[i]);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen array_append(&headers, &value, 1);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (h2 != NULL) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen for (i = 0; h2[i] != NULL; i++) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (h1 == NULL || !str_array_icase_find(h1, h2[i])) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen value = p_strdup(pool, h2[i]);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen array_append(&headers, &value, 1);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen array_append_zero(&headers);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen return array_idx(&headers, 0);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen}
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenimapc_mail_send_fetch(struct mail *_mail, enum mail_fetch_field fields,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const char *const *headers)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct imapc_mail *mail = (struct imapc_mail *)_mail;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
81d3c215bb1fdbda2cf7ccd9519f6b4fd03c3791Timo Sirainen struct imapc_command *cmd;
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen struct mail_index_view *view;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen string_t *str;
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen uint32_t seq;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen unsigned int i;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (_mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* drop any fields that we may already be fetching currently */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen fields &= ~mail->fetching_fields;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (headers_have_subset(mail->fetching_headers, headers))
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen headers = NULL;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (fields == 0 && headers == NULL)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen if (!_mail->saving) {
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen /* if we already know that the mail is expunged,
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen don't try to FETCH it */
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen view = mbox->delayed_sync_view != NULL ?
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen mbox->delayed_sync_view : mbox->box.view;
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen if (!mail_index_lookup_seq(view, _mail->uid, &seq) ||
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen mail_index_is_expunged(view, seq)) {
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen mail_set_expunged(_mail);
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen return -1;
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen }
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen } else if (mbox->client_box == NULL) {
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen /* opened as save-only. we'll need to fetch the mail,
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen so actually SELECT/EXAMINE the mailbox */
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen i_assert(mbox->box.opened);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen if (imapc_mailbox_select(mbox) < 0)
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen return -1;
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen }
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if ((fields & MAIL_FETCH_STREAM_BODY) != 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen fields |= MAIL_FETCH_STREAM_HEADER;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen str = t_str_new(64);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen str_printfa(str, "UID FETCH %u (", _mail->uid);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if ((fields & MAIL_FETCH_RECEIVED_DATE) != 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen str_append(str, "INTERNALDATE ");
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen if ((fields & MAIL_FETCH_PHYSICAL_SIZE) != 0)
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen str_append(str, "RFC822.SIZE ");
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen if ((fields & MAIL_FETCH_GUID) != 0) {
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen str_append(str, mbox->guid_fetch_field_name);
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen str_append_c(str, ' ');
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen }
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if ((fields & MAIL_FETCH_STREAM_BODY) != 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen str_append(str, "BODY.PEEK[] ");
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen else if ((fields & MAIL_FETCH_STREAM_HEADER) != 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen str_append(str, "BODY.PEEK[HEADER] ");
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen else if (headers != NULL) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen mail->fetching_headers =
d81b80bac97040d5e737f23ce1ee2eb4d7cc16cfTimo Sirainen headers_merge(mail->imail.mail.data_pool, headers,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen mail->fetching_headers);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen str_append(str, "BODY.PEEK[HEADER.FIELDS (");
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen for (i = 0; mail->fetching_headers[i] != NULL; i++) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (i > 0)
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen str_append_c(str, ' ');
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen imap_append_astring(str, mail->fetching_headers[i]);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen str_append(str, ")] ");
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen mail->header_list_fetched = FALSE;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen str_truncate(str, str_len(str)-1);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen str_append_c(str, ')');
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen pool_ref(mail->imail.mail.pool);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail->fetching_fields |= fields;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (mail->fetch_count++ == 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen array_append(&mbox->fetch_mails, &mail, 1);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
81d3c215bb1fdbda2cf7ccd9519f6b4fd03c3791Timo Sirainen cmd = imapc_client_mailbox_cmd(mbox->client_box,
81d3c215bb1fdbda2cf7ccd9519f6b4fd03c3791Timo Sirainen imapc_mail_prefetch_callback, mail);
f87844c400cf9741abad57d9815121d0738a738fTimo Sirainen imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
81d3c215bb1fdbda2cf7ccd9519f6b4fd03c3791Timo Sirainen imapc_command_send(cmd, str_c(str));
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail->imail.data.prefetch_sent = TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainenstatic void imapc_mail_cache_get(struct imapc_mail *mail,
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen struct imapc_mail_cache *cache)
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen{
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if (mail->body_fetched)
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen return;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if (cache->fd != -1) {
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->fd = cache->fd;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->imail.data.stream =
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen i_stream_create_fd(mail->fd, 0, FALSE);
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen cache->fd = -1;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen } else if (cache->buf != NULL) {
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->body = cache->buf;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->imail.data.stream =
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen i_stream_create_from_data(mail->body->data,
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->body->used);
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen cache->buf = NULL;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen } else {
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen return;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen }
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->body_fetched = TRUE;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen imapc_mail_init_stream(mail, TRUE);
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen}
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainenstatic enum mail_fetch_field
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainenimapc_mail_get_wanted_fetch_fields(struct imapc_mail *mail)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen struct imapc_mailbox *mbox =
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen (struct imapc_mailbox *)mail->imail.mail.mail.box;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct index_mail_data *data = &mail->imail.data;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen enum mail_fetch_field fields = 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen if ((data->wanted_fields & MAIL_FETCH_RECEIVED_DATE) != 0 &&
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen data->received_date == (time_t)-1)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen fields |= MAIL_FETCH_RECEIVED_DATE;
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)
bf611d43256ef8ee3e1c1ce8e1257920f2075278Timo Sirainen fields |= MAIL_FETCH_RECEIVED_DATE;
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen if ((data->wanted_fields & MAIL_FETCH_PHYSICAL_SIZE) != 0 &&
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen data->physical_size == (uoff_t)-1 &&
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE))
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen fields |= MAIL_FETCH_PHYSICAL_SIZE;
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen if ((data->wanted_fields & MAIL_FETCH_GUID) != 0 &&
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen data->guid == NULL && mbox->guid_fetch_field_name != NULL)
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen fields |= MAIL_FETCH_GUID;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (data->stream == NULL && data->access_part != 0) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if ((data->access_part & (READ_BODY | PARSE_BODY)) != 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen fields |= MAIL_FETCH_STREAM_BODY;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen else
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen fields |= MAIL_FETCH_STREAM_HEADER;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen return fields;
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen}
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainenbool imapc_mail_prefetch(struct mail *_mail)
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen{
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen struct imapc_mail *mail = (struct imapc_mail *)_mail;
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen struct index_mail_data *data = &mail->imail.data;
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen enum mail_fetch_field fields;
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen if (mbox->prev_mail_cache.uid == _mail->uid)
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen imapc_mail_cache_get(mail, &mbox->prev_mail_cache);
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen /* try to get as much from cache as possible */
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen imapc_mail_update_access_parts(&mail->imail);
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen fields = imapc_mail_get_wanted_fetch_fields(mail);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (fields != 0) T_BEGIN {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen (void)imapc_mail_send_fetch(_mail, fields,
0f641fb49bf0a934556717a2c209566ac387d7bbTimo Sirainen data->wanted_headers == NULL ? NULL :
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen data->wanted_headers->name);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } T_END;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return !mail->imail.data.prefetch_sent;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainenstatic bool
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainenimapc_mail_have_fields(struct imapc_mail *imail, enum mail_fetch_field fields)
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen{
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if ((fields & MAIL_FETCH_RECEIVED_DATE) != 0) {
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (imail->imail.data.received_date == (time_t)-1)
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return FALSE;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen fields &= ~MAIL_FETCH_RECEIVED_DATE;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen }
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen if ((fields & MAIL_FETCH_PHYSICAL_SIZE) != 0) {
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen if (imail->imail.data.physical_size == (uoff_t)-1)
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen return FALSE;
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen fields &= ~MAIL_FETCH_PHYSICAL_SIZE;
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen }
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen if ((fields & MAIL_FETCH_GUID) != 0) {
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen if (imail->imail.data.guid == NULL)
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen return FALSE;
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen fields &= ~MAIL_FETCH_GUID;
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen }
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if ((fields & (MAIL_FETCH_STREAM_HEADER |
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen MAIL_FETCH_STREAM_BODY)) != 0) {
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (imail->imail.data.stream == NULL)
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return FALSE;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen fields &= ~(MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY);
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen }
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen i_assert(fields == 0);
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return TRUE;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen}
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenint imapc_mail_fetch(struct mail *_mail, enum mail_fetch_field fields,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const char *const *headers)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct imapc_mail *imail = (struct imapc_mail *)_mail;
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen struct imapc_mailbox *mbox =
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen (struct imapc_mailbox *)_mail->box;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen int ret;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen if ((fields & MAIL_FETCH_GUID) != 0 &&
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen mbox->guid_fetch_field_name == NULL) {
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen mail_storage_set_error(_mail->box->storage,
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen MAIL_ERROR_NOTPOSSIBLE,
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen "Message GUID not available in this server");
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen return -1;
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen }
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen fields |= imapc_mail_get_wanted_fetch_fields(imail);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen T_BEGIN {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen ret = imapc_mail_send_fetch(_mail, fields, headers);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } T_END;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (ret < 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
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
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen failed) */
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen while (imail->fetch_count > 0 &&
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen (!imapc_mail_have_fields(imail, fields) ||
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen !imail->header_list_fetched))
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen imapc_storage_run(mbox->storage);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic bool imapc_find_lfile_arg(const struct imapc_untagged_reply *reply,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const struct imap_arg *arg, int *fd_r)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const struct imap_arg *list;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen unsigned int i, count;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
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
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (farg->parent_arg == arg->parent &&
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen imap_arg_get_list_full(arg->parent, &list, &count) &&
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen farg->list_idx < count && &list[farg->list_idx] == arg) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen *fd_r = farg->fd;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return FALSE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainenstatic void imapc_stream_filter(struct istream **input)
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen{
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen static const char *imapc_hide_headers[] = {
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 };
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen struct istream *filter_input;
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen filter_input = i_stream_create_header_filter(*input,
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen HEADER_FILTER_EXCLUDE,
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen imapc_hide_headers, N_ELEMENTS(imapc_hide_headers),
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen *null_header_filter_callback, (void *)NULL);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen i_stream_unref(input);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen *input = filter_input;
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen}
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainenvoid imapc_mail_init_stream(struct imapc_mail *mail, bool have_body)
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen{
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen struct index_mail *imail = &mail->imail;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen struct mail *_mail = &imail->mail.mail;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen struct istream *input;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen uoff_t size;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen int ret;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen i_stream_set_name(imail->data.stream,
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen t_strdup_printf("imapc mail uid=%u", _mail->uid));
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen index_mail_set_read_buffer_size(_mail, imail->data.stream);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen imapc_stream_filter(&imail->data.stream);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (imail->mail.v.istream_opened != NULL) {
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (imail->mail.v.istream_opened(_mail,
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen &imail->data.stream) < 0) {
2ed248fba21fdd3abcc4bb4d07c2822b9ba3f66fTimo Sirainen index_mail_close_streams(imail);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen return;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen }
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen } else if (have_body) {
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen ret = i_stream_get_size(imail->data.stream, TRUE, &size);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (ret < 0) {
2ed248fba21fdd3abcc4bb4d07c2822b9ba3f66fTimo Sirainen index_mail_close_streams(imail);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen return;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen }
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen i_assert(ret != 0);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen imail->data.physical_size = size;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen /* we'll assume that the remote server is working properly and
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen sending CRLF linefeeds */
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen imail->data.virtual_size = size;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen }
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
7c3f90095b4168d89a268ac1ec820c5925d48fd3Timo Sirainen imail->data.stream_has_only_header = !have_body;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (index_mail_init_stream(imail, NULL, NULL, &input) < 0)
2ed248fba21fdd3abcc4bb4d07c2822b9ba3f66fTimo Sirainen index_mail_close_streams(imail);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen}
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic void
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenimapc_fetch_stream(struct imapc_mail *mail,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const struct imapc_untagged_reply *reply,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const struct imap_arg *arg, bool body)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct index_mail *imail = &mail->imail;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const char *value;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen int fd;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (imail->data.stream != NULL) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (!body)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* maybe the existing stream has no body. replace it. */
2ed248fba21fdd3abcc4bb4d07c2822b9ba3f66fTimo Sirainen index_mail_close_streams(imail);
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if (mail->fd != -1) {
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if (close(mail->fd) < 0)
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen i_error("close(imapc mail) failed: %m");
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->fd = -1;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (arg->type == IMAP_ARG_LITERAL_SIZE) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (!imapc_find_lfile_arg(reply, arg, &fd))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if ((fd = dup(fd)) == -1) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen i_error("dup() failed: %m");
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->fd = fd;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen imail->data.stream = i_stream_create_fd(fd, 0, FALSE);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (!imap_arg_get_nstring(arg, &value))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (value == NULL) {
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen mail_set_expunged(&imail->mail.mail);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (mail->body == NULL) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail->body = buffer_create_dynamic(default_pool,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen arg->str_len + 1);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen buffer_set_used_size(mail->body, 0);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen buffer_append(mail->body, value, arg->str_len);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen imail->data.stream = i_stream_create_from_data(mail->body->data,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail->body->used);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->body_fetched = body;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen imapc_mail_init_stream(mail, body);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenstatic void
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainenimapc_fetch_header_stream(struct imapc_mail *mail,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const struct imapc_untagged_reply *reply,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const struct imap_arg *args)
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen{
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const enum message_header_parser_flags hdr_parser_flags =
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP |
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen MESSAGE_HEADER_PARSER_FLAG_DROP_CR;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const struct imap_arg *hdr_list;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen struct mailbox_header_lookup_ctx *headers_ctx;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen struct message_header_parser_ctx *parser;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen struct message_header_line *hdr;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen struct istream *input;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen ARRAY_TYPE(const_string) hdr_arr;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen const char *value;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen int ret, fd;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (!imap_arg_get_list(args, &hdr_list))
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen return;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (!imap_arg_atom_equals(args+1, "]"))
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen return;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen args += 2;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen /* see if this is reply to the latest headers list request
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen (parse it even if it's not) */
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen t_array_init(&hdr_arr, 16);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen while (imap_arg_get_astring(hdr_list, &value)) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen array_append(&hdr_arr, &value, 1);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen hdr_list++;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (hdr_list->type != IMAP_ARG_EOL)
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen return;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen array_append_zero(&hdr_arr);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (headers_have_subset(array_idx(&hdr_arr, 0), mail->fetching_headers))
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen mail->header_list_fetched = TRUE;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (args->type == IMAP_ARG_LITERAL_SIZE) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (!imapc_find_lfile_arg(reply, args, &fd))
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen return;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen input = i_stream_create_fd(fd, 0, FALSE);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen } else {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (!imap_arg_get_nstring(args, &value))
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen return;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen if (value == NULL) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen mail_set_expunged(&mail->imail.mail.mail);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen return;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen input = i_stream_create_from_data(value, args->str_len);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen }
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen headers_ctx = mailbox_header_lookup_init(mail->imail.mail.mail.box,
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen array_idx(&hdr_arr, 0));
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen index_mail_parse_header_init(&mail->imail, headers_ctx);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
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 i_assert(ret != 0);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen index_mail_parse_header(NULL, NULL, &mail->imail);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen message_parse_header_deinit(&parser);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen mailbox_header_lookup_unref(&headers_ctx);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen i_stream_destroy(&input);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen}
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenvoid imapc_mail_fetch_update(struct imapc_mail *mail,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const struct imapc_untagged_reply *reply,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const struct imap_arg *args)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct imapc_mailbox *mbox =
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen (struct imapc_mailbox *)mail->imail.mail.mail.box;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const char *key, *value;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen unsigned int i;
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen uoff_t size;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time_t t;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen int tz;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen bool match = FALSE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen for (i = 0; args[i].type != IMAP_ARG_EOL; i += 2) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (!imap_arg_get_atom(&args[i], &key) ||
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen args[i+1].type == IMAP_ARG_EOL)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen break;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (strcasecmp(key, "BODY[]") == 0) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen imapc_fetch_stream(mail, reply, &args[i+1], TRUE);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen match = TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else if (strcasecmp(key, "BODY[HEADER]") == 0) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen imapc_fetch_stream(mail, reply, &args[i+1], FALSE);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen match = TRUE;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen } else if (strcasecmp(key, "BODY[HEADER.FIELDS") == 0) {
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen imapc_fetch_header_stream(mail, reply, &args[i+1]);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen match = TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else if (strcasecmp(key, "INTERNALDATE") == 0) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (imap_arg_get_astring(&args[i+1], &value) &&
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen imap_parse_datetime(value, &t, &tz))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail->imail.data.received_date = t;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen match = TRUE;
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen } else if (strcasecmp(key, "RFC822.SIZE") == 0) {
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen if (imap_arg_get_atom(&args[i+1], &value) &&
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen str_to_uoff(value, &size) == 0 &&
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE))
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen mail->imail.data.physical_size = size;
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen match = TRUE;
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen } else if (strcasecmp(key, "X-GM-MSGID") == 0 ||
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen strcasecmp(key, "X-GUID") == 0) {
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen if (imap_arg_get_astring(&args[i+1], &value)) {
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen mail->imail.data.guid =
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen p_strdup(mail->imail.mail.pool, value);
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen }
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen match = TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (!match) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* this is only a FETCH FLAGS update for the wanted mail */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else {
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen imapc_client_stop(mbox->storage->client->client);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}