bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "lib.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "str.h"
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen#include "ioloop.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "istream.h"
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen#include "istream-concat.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"
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen#include "imap-bodystructure.h"
638734376d265a1529985755da671c09cfc22e06Timo Sirainen#include "imap-resp-code.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "imapc-mail.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "imapc-storage.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
638734376d265a1529985755da671c09cfc22e06Timo Sirainenstatic void imapc_mail_set_failure(struct imapc_mail *mail,
638734376d265a1529985755da671c09cfc22e06Timo Sirainen const struct imapc_command_reply *reply)
638734376d265a1529985755da671c09cfc22e06Timo Sirainen{
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(mail->imail.mail.mail.box);
638734376d265a1529985755da671c09cfc22e06Timo Sirainen
14fb3a2f6af1d75aeec6deb766026b4ea6a4db53Timo Sirainen mail->last_fetch_reply = p_strdup(mail->imail.mail.pool, reply->text_full);
14fb3a2f6af1d75aeec6deb766026b4ea6a4db53Timo Sirainen
638734376d265a1529985755da671c09cfc22e06Timo Sirainen switch (reply->state) {
638734376d265a1529985755da671c09cfc22e06Timo Sirainen case IMAPC_COMMAND_STATE_OK:
638734376d265a1529985755da671c09cfc22e06Timo Sirainen break;
638734376d265a1529985755da671c09cfc22e06Timo Sirainen case IMAPC_COMMAND_STATE_NO:
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 */
638734376d265a1529985755da671c09cfc22e06Timo Sirainen break;
638734376d265a1529985755da671c09cfc22e06Timo Sirainen }
638734376d265a1529985755da671c09cfc22e06Timo Sirainen if (reply->resp_text_key != NULL &&
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 } else {
638734376d265a1529985755da671c09cfc22e06Timo Sirainen /* hopefully this is a permanent failure */
638734376d265a1529985755da671c09cfc22e06Timo Sirainen mail->fetch_ignore_if_missing = TRUE;
638734376d265a1529985755da671c09cfc22e06Timo Sirainen }
638734376d265a1529985755da671c09cfc22e06Timo Sirainen break;
638734376d265a1529985755da671c09cfc22e06Timo Sirainen case IMAPC_COMMAND_STATE_BAD:
638734376d265a1529985755da671c09cfc22e06Timo Sirainen case IMAPC_COMMAND_STATE_DISCONNECTED:
fc1584e525d413183d37e1052081f3685a06c7fcAki Tuomi case IMAPC_COMMAND_STATE_AUTH_FAILED:
638734376d265a1529985755da671c09cfc22e06Timo Sirainen mail->fetch_failed = TRUE;
638734376d265a1529985755da671c09cfc22e06Timo Sirainen break;
638734376d265a1529985755da671c09cfc22e06Timo Sirainen }
638734376d265a1529985755da671c09cfc22e06Timo Sirainen}
638734376d265a1529985755da671c09cfc22e06Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic void
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenimapc_mail_fetch_callback(const struct imapc_command_reply *reply,
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen void *context)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen struct imapc_fetch_request *request = context;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen struct imapc_fetch_request *const *requests;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen struct imapc_mail *const *mailp;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen struct imapc_mailbox *mbox = NULL;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen unsigned int i, count;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen array_foreach(&request->mails, mailp) {
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen struct imapc_mail *mail = *mailp;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_assert(mail->fetch_count > 0);
638734376d265a1529985755da671c09cfc22e06Timo Sirainen imapc_mail_set_failure(mail, reply);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen if (--mail->fetch_count == 0)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen mail->fetching_fields = 0;
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek mbox = IMAPC_MAILBOX(mail->imail.mail.mail.box);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen }
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_assert(mbox != NULL);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen requests = array_get(&mbox->fetch_requests, &count);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen for (i = 0; i < count; i++) {
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen if (requests[i] == request) {
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen array_delete(&mbox->fetch_requests, i, 1);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen break;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_assert(i < count);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen array_free(&request->mails);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_free(request);
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 {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&mbox->box,
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen "imapc: Mail FETCH failed: %s", reply->text_full);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
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
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenstatic bool
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenimapc_mail_try_merge_fetch(struct imapc_mailbox *mbox, string_t *str)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen{
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen const char *s1 = str_c(str);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen const char *s2 = str_c(mbox->pending_fetch_cmd);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen const char *p1, *p2;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_assert(strncmp(s1, "UID FETCH ", 10) == 0);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_assert(strncmp(s2, "UID FETCH ", 10) == 0);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen /* skip over UID range */
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen p1 = strchr(s1+10, ' ');
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen p2 = strchr(s2+10, ' ');
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen if (null_strcmp(p1, p2) != 0)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen return FALSE;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen /* append the new UID to the pending FETCH UID range */
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen str_truncate(str, p1-s1);
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 Sirainen return TRUE;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen}
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenstatic void
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenimapc_mail_delayed_send_or_merge(struct imapc_mail *mail, string_t *str)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen{
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(mail->imail.mail.mail.box);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen if (mbox->pending_fetch_request != NULL &&
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen !imapc_mail_try_merge_fetch(mbox, str)) {
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen /* send the previous FETCH and create a new one */
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen imapc_mail_fetch_flush(mbox);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen }
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen if (mbox->pending_fetch_request == NULL) {
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen mbox->pending_fetch_request =
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_new(struct imapc_fetch_request, 1);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_array_init(&mbox->pending_fetch_request->mails, 4);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_assert(mbox->pending_fetch_cmd->used == 0);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen str_append_str(mbox->pending_fetch_cmd, str);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen }
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen array_append(&mbox->pending_fetch_request->mails, &mail, 1);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen
b43d7e2b753d69fa6eafcf647d75e6af1dcc0fc8Timo Sirainen if (mbox->to_pending_fetch_send == NULL &&
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
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 mbox->to_pending_fetch_send =
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen timeout_add_short(0, imapc_mail_fetch_flush, mbox);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen }
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen}
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo 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{
7dd326f772ed4193e1bfdafdb46fea616970e1acJosef 'Jeff' Sipek struct imapc_mail *mail = IMAPC_MAIL(_mail);
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(_mail->box);
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen struct mail_index_view *view;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen string_t *str;
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen uint32_t seq;
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen unsigned int i;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen i_assert(headers == NULL ||
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_HEADERS));
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen
1b0b44348d1f94f1f0e418d80323646e1e335c2bTimo Sirainen if (_mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER) {
1b0b44348d1f94f1f0e418d80323646e1e335c2bTimo Sirainen mail_set_aborted(_mail);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
1b0b44348d1f94f1f0e418d80323646e1e335c2bTimo Sirainen }
7204b8112e005ff81dcf628f7880ef1feed1effeTimo Sirainen _mail->mail_stream_opened = TRUE;
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)
2a1d9dda6e05f596b70703b74721847308127e3eTimo Sirainen return mail->fetch_sent ? 0 : 1;
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 ");
50ffc12831eff618d35a8ee7537b61eaa95a4adeTimo Sirainen if ((fields & (MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_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 }
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if ((fields & MAIL_FETCH_IMAP_BODY) != 0)
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen str_append(str, "BODY ");
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if ((fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0)
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen str_append(str, "BODYSTRUCTURE ");
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen if ((fields & MAIL_FETCH_STREAM_BODY) != 0) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_ZIMBRA_WORKAROUNDS))
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen str_append(str, "BODY.PEEK[] ");
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen else {
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 }
25fecf139625e35bbcd9262be8b28cbb4e8407faTimo Sirainen fields |= MAIL_FETCH_STREAM_HEADER;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo 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 mail->fetching_fields |= fields;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen mail->fetch_count++;
2a1d9dda6e05f596b70703b74721847308127e3eTimo Sirainen mail->fetch_sent = FALSE;
14fd61e73569f356c57ccc253cfbbb6d77cccdf9Timo Sirainen mail->fetch_failed = FALSE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen imapc_mail_delayed_send_or_merge(mail, str);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen return 1;
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;
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi mail->imail.data.stream = i_stream_create_fd(mail->fd, 0);
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 }
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen mail->header_fetched = TRUE;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->body_fetched = TRUE;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imapc_mail_init_stream(mail);
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen}
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainenstatic enum mail_fetch_field
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainenimapc_mail_get_wanted_fetch_fields(struct imapc_mail *mail)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = 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;
50ffc12831eff618d35a8ee7537b61eaa95a4adeTimo Sirainen if ((data->wanted_fields & (MAIL_FETCH_PHYSICAL_SIZE |
50ffc12831eff618d35a8ee7537b61eaa95a4adeTimo Sirainen MAIL_FETCH_VIRTUAL_SIZE)) != 0 &&
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen data->physical_size == (uoff_t)-1 &&
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 data->body == NULL &&
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE))
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen fields |= MAIL_FETCH_IMAP_BODY;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if ((data->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0 &&
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen data->bodystructure == NULL &&
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE))
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen fields |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
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;
25fecf139625e35bbcd9262be8b28cbb4e8407faTimo Sirainen fields |= MAIL_FETCH_STREAM_HEADER;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen return fields;
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen}
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainenvoid imapc_mail_try_init_stream_from_cache(struct imapc_mail *mail)
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen{
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen struct mail *_mail = &mail->imail.mail.mail;
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(_mail->box);
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen if (mbox->prev_mail_cache.uid == _mail->uid)
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen imapc_mail_cache_get(mail, &mbox->prev_mail_cache);
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen}
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainenbool imapc_mail_prefetch(struct mail *_mail)
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen{
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 enum mail_fetch_field fields;
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen const char *const *headers = NULL;
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen /* try to get as much from cache as possible */
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen imapc_mail_update_access_parts(&mail->imail);
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. */
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen if (mail->imail.data.access_part != 0)
e1777cb59a96d8710a6c5cefe6a17c7c15159c9fTimo Sirainen imapc_mail_try_init_stream_from_cache(mail);
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen
d02af9610cf5d6560c5ebf4491f59eca2ba810a8Timo Sirainen fields = imapc_mail_get_wanted_fetch_fields(mail);
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen if (data->wanted_headers != NULL && data->stream == NULL &&
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen (fields & MAIL_FETCH_STREAM_HEADER) == 0 &&
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 headers = data->wanted_headers->name;
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen else
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen fields |= MAIL_FETCH_STREAM_HEADER;
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen }
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen if (fields != 0 || headers != NULL) T_BEGIN {
fe080d248e2bd374e9d86c8a34ec6f14e88b8a14Timo Sirainen if (imapc_mail_send_fetch(_mail, fields, headers) > 0)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen mail->imail.data.prefetch_sent = TRUE;
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 }
50ffc12831eff618d35a8ee7537b61eaa95a4adeTimo Sirainen if ((fields & (MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE)) != 0) {
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen if (imail->imail.data.physical_size == (uoff_t)-1)
adcb46fe2c6d1139dfbd8ab08a8fbe96e53f8fd6Timo Sirainen return FALSE;
50ffc12831eff618d35a8ee7537b61eaa95a4adeTimo Sirainen fields &= ~(MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_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 }
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if ((fields & MAIL_FETCH_IMAP_BODY) != 0) {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if (imail->imail.data.body == NULL)
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen return FALSE;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen fields &= ~MAIL_FETCH_IMAP_BODY;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen }
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if ((fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0) {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if (imail->imail.data.bodystructure == NULL)
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen return FALSE;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen fields &= ~MAIL_FETCH_IMAP_BODYSTRUCTURE;
e1005f8bf9190e1778010032dbd20c64acb53610Timo 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{
7dd326f772ed4193e1bfdafdb46fea616970e1acJosef 'Jeff' Sipek struct imapc_mail *imail = IMAPC_MAIL(_mail);
6a384c0f8980bfdefe40c42bf39d43302e58ad14Josef 'Jeff' Sipek struct imapc_mailbox *mbox = 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;
969f57f722570982a5febbaab2462b692aa68733Timo Sirainen }
969f57f722570982a5febbaab2462b692aa68733Timo Sirainen if (_mail->saving) {
969f57f722570982a5febbaab2462b692aa68733Timo Sirainen mail_storage_set_error(_mail->box->storage,
969f57f722570982a5febbaab2462b692aa68733Timo Sirainen MAIL_ERROR_NOTPOSSIBLE,
969f57f722570982a5febbaab2462b692aa68733Timo Sirainen "Attempting to issue FETCH for a mail not yet committed");
969f57f722570982a5febbaab2462b692aa68733Timo 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) */
2a1d9dda6e05f596b70703b74721847308127e3eTimo Sirainen if (ret > 0)
2a1d9dda6e05f596b70703b74721847308127e3eTimo Sirainen imapc_mail_fetch_flush(mbox);
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen while (imail->fetch_count > 0 &&
b8eb60a9ba83e2f3f6d969e810553eb937be2128Timo Sirainen (!imapc_mail_have_fields(imail, fields) ||
14fd61e73569f356c57ccc253cfbbb6d77cccdf9Timo Sirainen !imail->header_list_fetched)) {
fda7b3649d2ccdb4a95f5bf09eb8cf5435d57261Timo Sirainen imapc_mailbox_run_nofetch(mbox);
14fd61e73569f356c57ccc253cfbbb6d77cccdf9Timo Sirainen }
1b0b44348d1f94f1f0e418d80323646e1e335c2bTimo Sirainen if (imail->fetch_failed) {
1b0b44348d1f94f1f0e418d80323646e1e335c2bTimo Sirainen mail_storage_set_internal_error(&mbox->storage->storage);
14fd61e73569f356c57ccc253cfbbb6d77cccdf9Timo Sirainen return -1;
1b0b44348d1f94f1f0e418d80323646e1e335c2bTimo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainenvoid imapc_mail_fetch_flush(struct imapc_mailbox *mbox)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen{
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen struct imapc_command *cmd;
2a1d9dda6e05f596b70703b74721847308127e3eTimo Sirainen struct imapc_mail *const *mailp;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen if (mbox->pending_fetch_request == NULL) {
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_assert(mbox->to_pending_fetch_send == NULL);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen return;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen }
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen
2a1d9dda6e05f596b70703b74721847308127e3eTimo Sirainen array_foreach(&mbox->pending_fetch_request->mails, mailp)
2a1d9dda6e05f596b70703b74721847308127e3eTimo Sirainen (*mailp)->fetch_sent = TRUE;
2a1d9dda6e05f596b70703b74721847308127e3eTimo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen cmd = imapc_client_mailbox_cmd(mbox->client_box,
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen imapc_mail_fetch_callback,
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen mbox->pending_fetch_request);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
b7a672661c5642d6e8db9e96f7028b1af1e3255aTimo Sirainen array_append(&mbox->fetch_requests, &mbox->pending_fetch_request, 1);
b7a672661c5642d6e8db9e96f7028b1af1e3255aTimo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen imapc_command_send(cmd, str_c(mbox->pending_fetch_cmd));
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen mbox->pending_fetch_request = NULL;
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&mbox->to_pending_fetch_send);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen str_truncate(mbox->pending_fetch_cmd, 0);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen}
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo 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),
677b75f90d81eafe742896d6570a2f63ce501d05Josef 'Jeff' Sipek *null_header_filter_callback, NULL);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen i_stream_unref(input);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen *input = filter_input;
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen}
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainenvoid imapc_mail_init_stream(struct imapc_mail *mail)
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen{
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen struct index_mail *imail = &mail->imail;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen struct mail *_mail = &imail->mail.mail;
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = IMAPC_MAILBOX(_mail->box);
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
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. */
b8947936e65a9b79ffe1a4f7a9835c946a9b635bTimo Sirainen imapc_stream_filter(&imail->data.stream);
b8947936e65a9b79ffe1a4f7a9835c946a9b635bTimo Sirainen }
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 }
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen } else if (mail->body_fetched) {
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
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imail->data.stream_has_only_header = !mail->body_fetched;
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,
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen const struct imap_arg *arg,
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen bool have_header, bool have_body)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct index_mail *imail = &mail->imail;
e01ebd51ac369430ec81945e3c5317d6d6244138Timo Sirainen struct imapc_mailbox *mbox = IMAPC_MAILBOX(imail->mail.mail.box);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen struct istream *hdr_stream = NULL;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const char *value;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen int fd;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (imail->data.stream != NULL) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen i_assert(mail->header_fetched);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen if (mail->body_fetched || !have_body)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen if (have_header) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen /* replace the existing stream */
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen } else if (mail->fd == -1) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen /* append this body stream to the existing
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen header stream */
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen hdr_stream = imail->data.stream;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen i_stream_ref(hdr_stream);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen } else {
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 if (lseek(mail->fd, 0, SEEK_SET) < 0)
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen i_error("lseek(imapc) failed: %m");
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen hdr_stream = i_stream_create_fd_autoclose(&mail->fd, 0);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen }
2ed248fba21fdd3abcc4bb4d07c2822b9ba3f66fTimo Sirainen index_mail_close_streams(imail);
a943ed0f901e312445fd393249b91932797bba79Josef 'Jeff' Sipek i_close_fd(&mail->fd);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen } else {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen if (!have_header) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen /* BODY.PEEK[TEXT] received - we can't currently handle
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen this before receiving BODY.PEEK[HEADER] reply */
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen return;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (arg->type == IMAP_ARG_LITERAL_SIZE) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen if (!imapc_find_lfile_arg(reply, arg, &fd)) {
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&hdr_stream);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if ((fd = dup(fd)) == -1) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen i_error("dup() failed: %m");
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&hdr_stream);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail->fd = fd;
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi imail->data.stream = i_stream_create_fd(fd, 0);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (!imap_arg_get_nstring(arg, &value))
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen value = NULL;
e01ebd51ac369430ec81945e3c5317d6d6244138Timo Sirainen if (value == NULL ||
e01ebd51ac369430ec81945e3c5317d6d6244138Timo Sirainen (value[0] == '\0' &&
e01ebd51ac369430ec81945e3c5317d6d6244138Timo Sirainen IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_EMPTY_IS_EXPUNGED))) {
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen mail_set_expunged(&imail->mail.mail);
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&hdr_stream);
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);
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 */
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen i_stream_unref(&hdr_stream);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen } else {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen buffer_set_used_size(mail->body, 0);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
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 }
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen if (have_header)
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen mail->header_fetched = TRUE;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen mail->body_fetched = have_body;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen if (hdr_stream != NULL) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen struct istream *inputs[3];
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen inputs[0] = hdr_stream;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen inputs[1] = imail->data.stream;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen inputs[2] = NULL;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imail->data.stream = i_stream_create_concat(inputs);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen i_stream_unref(&inputs[0]);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen i_stream_unref(&inputs[1]);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imapc_mail_init_stream(mail);
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;
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi input = i_stream_create_fd(fd, 0);
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
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainenstatic const char *
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainenimapc_args_to_bodystructure(struct imapc_mail *mail,
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen const struct imap_arg *list_arg, bool extended)
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen{
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen const struct imap_arg *args;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen struct message_part *parts = NULL;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen const char *ret, *error;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen pool_t pool;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if (!imap_arg_get_list(list_arg, &args)) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(&mail->imail.mail.mail,
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen "imapc: Server sent invalid BODYSTRUCTURE parameters");
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen return NULL;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen }
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen
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 ret = NULL;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen } else {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen string_t *str = t_str_new(128);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen imap_bodystructure_write(parts, str, extended);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen ret = p_strdup(mail->imail.mail.data_pool, str_c(str));
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen }
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen pool_unref(&pool);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen return ret;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen}
e1005f8bf9190e1778010032dbd20c64acb53610Timo 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{
7b0a52bf38f8a7ab0c262acf4c761d6a0f22a07cJosef 'Jeff' Sipek struct imapc_mailbox *mbox = 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) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imapc_fetch_stream(mail, reply, &args[i+1], TRUE, TRUE);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen match = TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else if (strcasecmp(key, "BODY[HEADER]") == 0) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imapc_fetch_stream(mail, reply, &args[i+1], TRUE, FALSE);
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen match = TRUE;
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen } else if (strcasecmp(key, "BODY[TEXT]") == 0) {
eb1365e61674c54c7c453143356a891fb2e2b3d6Timo Sirainen imapc_fetch_stream(mail, reply, &args[i+1], FALSE, TRUE);
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;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen } else if (strcasecmp(key, "BODY") == 0) {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen mail->imail.data.body =
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen imapc_args_to_bodystructure(mail, &args[i+1], FALSE);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen }
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen match = TRUE;
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen } else if (strcasecmp(key, "BODYSTRUCTURE") == 0) {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) {
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen mail->imail.data.bodystructure =
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen imapc_args_to_bodystructure(mail, &args[i+1], TRUE);
e1005f8bf9190e1778010032dbd20c64acb53610Timo Sirainen }
e1005f8bf9190e1778010032dbd20c64acb53610Timo 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}