imap-fetch-body.c revision 768a07208b89e58308a965494090b658a577bc56
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "common.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "buffer.h"
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include "str.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "strescape.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "istream.h"
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#include "ostream.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "istream-header-filter.h"
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#include "message-parser.h"
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen#include "message-send.h"
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#include "mail-storage.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-parser.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-fetch.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include <stdlib.h>
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include <ctype.h>
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include <unistd.h>
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstruct imap_fetch_body_data {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct imap_fetch_body_data *next;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_header_lookup_ctx *header_ctx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *section; /* NOTE: always uppercased */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uoff_t skip, max_size; /* if you don't want max_size,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen set it to (uoff_t)-1 */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *const *fields;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size_t fields_count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int skip_set:1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int peek:1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen};
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstruct partial_cache {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unsigned int select_counter;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unsigned int uid;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uoff_t physical_start;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int cr_skipped;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct message_size pos;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen};
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic struct partial_cache partial = { 0, 0, 0, 0, { 0, 0, 0 } };
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int seek_partial(unsigned int select_counter, unsigned int uid,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct partial_cache *partial, struct istream *stream,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uoff_t virtual_skip)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int cr_skipped;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (select_counter == partial->select_counter && uid == partial->uid &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen stream->v_offset == partial->physical_start &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen virtual_skip >= partial->pos.virtual_size) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* we can use the cache */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen virtual_skip -= partial->pos.virtual_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen partial->select_counter = select_counter;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen partial->uid = uid;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen partial->physical_start = stream->v_offset;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen partial->cr_skipped = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen memset(&partial->pos, 0, sizeof(partial->pos));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_seek(stream, partial->physical_start +
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen partial->pos.physical_size);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen message_skip_virtual(stream, virtual_skip, &partial->pos,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen partial->cr_skipped, &cr_skipped);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen partial->cr_skipped = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return cr_skipped;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic uoff_t get_send_size(const struct imap_fetch_body_data *body,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uoff_t max_size)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen uoff_t size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (body->skip >= max_size)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size = max_size - body->skip;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return size <= body->max_size ? size : body->max_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic string_t *get_prefix(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_body_data *body,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uoff_t size)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen string_t *str;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str = t_str_new(128);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ctx->first)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->first = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_append_c(str, ' ');
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_printfa(str, "BODY[%s]", body->section);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (body->skip_set)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str_printfa(str, "<%"PRIuUOFF_T">", body->skip);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (size != (uoff_t)-1)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_printfa(str, " {%"PRIuUOFF_T"}\r\n", size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen else
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str_append(str, " NIL");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return str;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic off_t imap_fetch_send(struct ostream *output, struct istream *input,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen int cr_skipped, uoff_t virtual_size,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen int add_missing_eoh, int *last_cr)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const unsigned char *msg;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size_t i, size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen uoff_t vsize_left, sent;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen off_t ret;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unsigned char add;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen int blocks = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* go through the message data and insert CRs where needed. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen sent = 0; vsize_left = virtual_size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen while (vsize_left > 0 && !blocks &&
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_stream_read_data(input, &msg, &size, 0) > 0) {
7a24bdc1a5e2d5368c2569b4852192f2bdb5a31fTimo Sirainen add = '\0';
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen for (i = 0; i < size && vsize_left > 0; i++) {
7a24bdc1a5e2d5368c2569b4852192f2bdb5a31fTimo Sirainen vsize_left--;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
7a24bdc1a5e2d5368c2569b4852192f2bdb5a31fTimo Sirainen if (msg[i] == '\n') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if ((i > 0 && msg[i-1] != '\r') ||
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen (i == 0 && !cr_skipped)) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* missing CR */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen add = '\r';
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen break;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else if (msg[i] == '\0') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen add = 128;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen break;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if ((ret = o_stream_send(output, msg, i)) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen if ((uoff_t)ret < i) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen add = '\0';
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen blocks = TRUE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ret > 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen cr_skipped = msg[ret-1] == '\r';
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_stream_skip(input, ret);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen sent += ret;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (add != '\0') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if ((ret = o_stream_send(output, &add, 1)) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ret == 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen blocks = TRUE;
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen else {
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen sent++;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen cr_skipped = add == '\r';
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (add == 128)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_stream_skip(input, 1);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (add_missing_eoh && sent + 2 == virtual_size) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* Netscape missing EOH workaround. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_set_max_buffer_size(output, (size_t)-1);
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen if (o_stream_send(output, "\r\n", 2) < 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return -1;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen sent += 2;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if ((uoff_t)sent != virtual_size && !blocks) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* Input stream gave less data than we expected. Two choices
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen here: either we fill the missing data with spaces or we
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen disconnect the client.
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen We shouldn't really ever get here. One reason is if mail
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen was deleted from NFS server while we were reading it.
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen Another is some temporary disk error.
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen If we filled the missing data the client could cache it,
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen and if it was just a temporary error the message would be
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen permanently left corrupted in client's local cache. So, we
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen disconnect the client and hope that next try works. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_close(output);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen *last_cr = cr_skipped;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return sent;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainenstatic int fetch_stream_send(struct imap_fetch_context *ctx)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen off_t ret;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_set_max_buffer_size(ctx->client->output, 4096);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ret = imap_fetch_send(ctx->client->output, ctx->cur_input,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->skip_cr, ctx->cur_size - ctx->cur_offset,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_append_eoh, &ctx->skip_cr);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ret < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_offset += ret;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ctx->update_partial) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen partial.cr_skipped = ctx->skip_cr != 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen partial.pos.physical_size =
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_input->v_offset - partial.physical_start;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen partial.pos.virtual_size += ret;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return ctx->cur_offset == ctx->cur_size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int fetch_stream_send_direct(struct imap_fetch_context *ctx)
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen{
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen off_t ret;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_set_max_buffer_size(ctx->client->output, 0);
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen ret = o_stream_send_istream(ctx->client->output, ctx->cur_input);
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ret < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_offset += ret;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ctx->cur_append_eoh && ctx->cur_offset + 2 == ctx->cur_size) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* Netscape missing EOH workaround. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (o_stream_send(ctx->client->output, "\r\n", 2) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_offset += 2;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_append_eoh = FALSE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ctx->cur_offset != ctx->cur_size &&
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen !i_stream_have_bytes_left(ctx->cur_input)) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* Input stream gave less data than expected */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_close(ctx->client->output);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return ctx->cur_offset == ctx->cur_size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int fetch_stream(struct imap_fetch_context *ctx,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct message_size *size)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct istream *input;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (size->physical_size == size->virtual_size &&
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_mail->has_no_nuls) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* no need to kludge with CRs, we can use sendfile() */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen input = i_stream_create_limit(default_pool, ctx->cur_input,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_input->v_offset,
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen ctx->cur_size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_stream_unref(ctx->cur_input);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_input = input;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cont_handler = fetch_stream_send_direct;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cont_handler = fetch_stream_send;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return ctx->cont_handler(ctx);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int fetch_data(struct imap_fetch_context *ctx,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct imap_fetch_body_data *body,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct message_size *size)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen string_t *str;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_size = get_send_size(body, size->virtual_size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str = get_prefix(ctx, body, ctx->cur_size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (o_stream_send(ctx->client->output,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_data(str), str_len(str)) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (!ctx->update_partial) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen message_skip_virtual(ctx->cur_input, body->skip, NULL, FALSE,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen &ctx->skip_cr);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->skip_cr =
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen seek_partial(ctx->select_counter, ctx->cur_mail->uid,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen &partial, ctx->cur_input, body->skip);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return fetch_stream(ctx, size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen void *context)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct imap_fetch_body_data *body = context;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct message_size *fetch_size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct message_size hdr_size, body_size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_input =
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen mail_get_stream(mail, &hdr_size,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen body->section[0] == 'H' ? NULL : &body_size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ctx->cur_input == NULL)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_ref(ctx->cur_input);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->update_partial = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen switch (body->section[0]) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen case '\0':
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* BODY[] - fetch everything */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen message_size_add(&body_size, &hdr_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen fetch_size = &body_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen break;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen case 'H':
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* BODY[HEADER] - fetch only header */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen fetch_size = &hdr_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen break;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen case 'T':
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* BODY[TEXT] - skip header */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_skip(ctx->cur_input, hdr_size.physical_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen fetch_size = &body_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen break;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen default:
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_unreached();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return fetch_data(ctx, body, fetch_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void header_filter_eoh(struct message_header_line *hdr,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int *matched __attr_unused__, void *context)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct imap_fetch_context *ctx = context;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (hdr != NULL && hdr->eoh)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->cur_have_eoh = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int fetch_header_partial_from(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_body_data *body,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *header_section)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct message_size msg_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct istream *input;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen uoff_t old_offset;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* MIME, HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->cur_have_eoh = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (strncmp(header_section, "HEADER.FIELDS ", 14) == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen input = i_stream_create_header_filter(ctx->cur_input,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen HEADER_FILTER_INCLUDE,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen body->fields,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen body->fields_count,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen header_filter_eoh, ctx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else if (strncmp(header_section, "HEADER.FIELDS.NOT ", 18) == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen input = i_stream_create_header_filter(ctx->cur_input,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen HEADER_FILTER_EXCLUDE,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen body->fields,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen body->fields_count,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen header_filter_eoh, ctx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_error("BUG: Accepted invalid section from user: '%s'",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen header_section);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_unref(ctx->cur_input);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->cur_input = input;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->update_partial = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen old_offset = ctx->cur_input->v_offset;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen message_get_header_size(ctx->cur_input, &msg_size, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_seek(ctx->cur_input, old_offset);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!ctx->cur_have_eoh &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (client_workarounds & WORKAROUND_NETSCAPE_EOH) != 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* Netscape 4.x doesn't like if end of headers line is
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen missing. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen msg_size.virtual_size += 2;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->cur_append_eoh = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return fetch_data(ctx, body, &msg_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int fetch_body_header_partial(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail *mail, void *context)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_body_data *body = context;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->cur_input = mail_get_stream(mail, NULL, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ctx->cur_input == NULL)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_ref(ctx->cur_input);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->update_partial = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return fetch_header_partial_from(ctx, body, body->section);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_body_header_fields(struct imap_fetch_context *ctx,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct mail *mail, void *context)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct imap_fetch_body_data *body = context;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct message_size size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uoff_t old_offset;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->cur_input = mail_get_header_stream(mail, body->header_ctx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ctx->cur_input == NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_ref(ctx->cur_input);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->update_partial = FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen old_offset = ctx->cur_input->v_offset;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen message_get_body_size(ctx->cur_input, &size, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_seek(ctx->cur_input, old_offset);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* FIXME: We'll just always add the end of headers line now.
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ideally mail-storage would have a way to tell us if it exists. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size.virtual_size += 2;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_append_eoh = TRUE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return fetch_data(ctx, body, &size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen/* Find message_part for section (eg. 1.3.4) */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int part_find(struct mail *mail, const struct imap_fetch_body_data *body,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct message_part **part_r, const char **section_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct message_part *part;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *path;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int num;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen part = mail_get_parts(mail);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (part == NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen path = body->section;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen while (*path >= '0' && *path <= '9' && part != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* get part number, we have already verified its validity */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen num = 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen while (*path != '\0' && *path != '.') {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(*path >= '0' && *path <= '9');
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
db0735f9b388c5bcfb781b1b25015e898d63d953Timo Sirainen num = num*10 + (*path - '0');
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen path++;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (*path == '.')
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen path++;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (part->flags & MESSAGE_PART_FLAG_MULTIPART) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* find the part */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen part = part->children;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (; num > 1 && part != NULL; num--)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen part = part->next;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen } else {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* only 1 allowed with non-multipart messages */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (num != 1)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen part = NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (part != NULL &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (*path >= '0' && *path <= '9')) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* if we continue inside the message/rfc822, skip this
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen body part */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen part = part->children;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *part_r = part;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *section_r = path;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_body_mime(struct imap_fetch_context *ctx, struct mail *mail,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen void *context)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const struct imap_fetch_body_data *body = context;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const struct message_part *part;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *section;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen if (part_find(mail, body, &part, &section) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (part == NULL) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* part doesn't exist */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen string_t *str = get_prefix(ctx, body, (uoff_t)-1);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (o_stream_send(ctx->client->output,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str_data(str), str_len(str)) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->cur_input = mail_get_stream(mail, NULL, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ctx->cur_input == NULL)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_ref(ctx->cur_input);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->update_partial = TRUE;
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen if (*section == '\0') {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* fetch the whole section */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos +
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen part->header_size.physical_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return fetch_data(ctx, body, &part->body_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (strcmp(section, "MIME") == 0) {
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen /* fetch section's MIME header */
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return fetch_data(ctx, body, &part->header_size);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* TEXT and HEADER are only for message/rfc822 parts */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) == 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen string_t *str = get_prefix(ctx, body, 0);
fb7dd075cf883e5e7defbc0c8fb8326e30bdccdeTimo Sirainen if (o_stream_send(ctx->client->output,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str_data(str), str_len(str)) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen i_assert(part->children != NULL && part->children->next == NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen part = part->children;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (strcmp(section, "TEXT") == 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos +
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen part->header_size.physical_size);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return fetch_data(ctx, body, &part->body_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (strcmp(section, "HEADER") == 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* all headers */
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return fetch_data(ctx, body, &part->header_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (strncmp(section, "HEADER", 6) == 0) {
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return fetch_header_partial_from(ctx, body, section);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen i_error("BUG: Accepted invalid section from user: '%s'", body->section);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_body_header_fields_check(const char *section)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (*section++ != '(')
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return FALSE;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen if (*section == ')')
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return FALSE; /* has to be at least one field */
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen while (*section != '\0' && *section != ')') {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (*section == '(')
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen section++;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (*section++ != ')')
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
41955c400476941fa274f18b106a5922866fd780Timo Sirainen if (*section != '\0')
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return TRUE;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen}
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainenstatic int fetch_body_header_fields_init(struct imap_fetch_context *ctx,
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen struct imap_fetch_body_data *body,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *section)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
d516e6848ecfbc7381abe9414fd8011fdf9d8c95Timo Sirainen const char *const *arr;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen
d516e6848ecfbc7381abe9414fd8011fdf9d8c95Timo Sirainen if (!fetch_body_header_fields_check(section))
d516e6848ecfbc7381abe9414fd8011fdf9d8c95Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen MAIL_FETCH_STREAM_BODY)) != 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* we'll need to open the file anyway, don't try to get the
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen headers from cache. */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen imap_fetch_add_handler(ctx, FALSE,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen fetch_body_header_partial, body);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return TRUE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen }
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen t_push();
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen for (arr = body->fields; *arr != NULL; arr++) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen char *hdr = p_strdup(ctx->cmd->pool, *arr);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen buffer_append(ctx->all_headers_buf, &hdr, sizeof(hdr));
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body->header_ctx = mailbox_header_lookup_init(ctx->box, body->fields);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_body_header_fields, body);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen t_pop();
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return TRUE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenstatic int fetch_body_section_name_init(struct imap_fetch_context *ctx,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct imap_fetch_body_data *body)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen const char *section = body->section;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (*section == '\0') {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER |
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen MAIL_FETCH_STREAM_BODY;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_body, body);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return TRUE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (strcmp(section, "TEXT") == 0) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_BODY;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_body, body);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return TRUE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen }
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (strncmp(section, "HEADER", 6) == 0) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* exact header matches could be cached */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (section[6] == '\0') {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_body, body);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return TRUE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen }
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (strncmp(section, "HEADER.FIELDS ", 14) == 0 &&
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen fetch_body_header_fields_init(ctx, body, section+14))
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return TRUE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 &&
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen fetch_body_header_fields_check(section+18)) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen imap_fetch_add_handler(ctx, FALSE,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen fetch_body_header_partial, body);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return TRUE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen }
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen } else if (*section >= '0' && *section <= '9') {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_BODY |
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen MAIL_FETCH_MESSAGE_PARTS;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen while ((*section >= '0' && *section <= '9') ||
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen *section == '.') section++;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (*section == '\0' ||
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen strcmp(section, "MIME") == 0 ||
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen strcmp(section, "TEXT") == 0 ||
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen strcmp(section, "HEADER") == 0 ||
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen (strncmp(section, "HEADER.FIELDS ", 14) == 0 &&
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen fetch_body_header_fields_check(section+14)) ||
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 &&
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen fetch_body_header_fields_check(section+18))) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen imap_fetch_add_handler(ctx, FALSE,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen fetch_body_mime, body);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return TRUE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen client_send_command_error(ctx->cmd,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen "Invalid BODY[..] parameter: Unknown or broken section");
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return FALSE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen}
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen/* Parse next digits in string into integer. Returns FALSE if the integer
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen becomes too big and wraps. */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenstatic int read_uoff_t(const char **p, uoff_t *value)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen{
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen uoff_t prev;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen *value = 0;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen while (**p >= '0' && **p <= '9') {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen prev = *value;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen *value = *value * 10 + (**p - '0');
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (*value < prev)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return FALSE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen (*p)++;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen }
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return TRUE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen}
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenstatic int body_section_build(struct imap_fetch_context *ctx,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen struct imap_fetch_body_data *body,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen const char *prefix,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen const struct imap_arg_list *list)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen{
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen string_t *str;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen const char **arr;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen size_t i;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen str = str_new(ctx->cmd->pool, 128);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen str_append(str, prefix);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen str_append(str, " (");
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* @UNSAFE: NULL-terminated list of headers */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen arr = p_new(ctx->cmd->pool, const char *, list->size + 1);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen for (i = 0; i < list->size; i++) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (list->args[i].type != IMAP_ARG_ATOM &&
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen list->args[i].type != IMAP_ARG_STRING) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen client_send_command_error(ctx->cmd,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen "Invalid BODY[..] parameter: "
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen "Header list contains non-strings");
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return FALSE;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen }
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (i != 0)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen str_append_c(str, ' ');
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen arr[i] = str_ucase(IMAP_ARG_STR(&list->args[i]));
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (list->args[i].type == IMAP_ARG_ATOM)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen str_append(str, arr[i]);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen else {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen str_append_c(str, '"');
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen str_append(str, str_escape(arr[i]));
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen str_append_c(str, '"');
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen str_append_c(str, ')');
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen qsort(arr, list->size, sizeof(*arr), strcasecmp_p);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body->fields = arr;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body->fields_count = list->size;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body->section = str_c(str);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return TRUE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenint fetch_body_section_init(struct imap_fetch_context *ctx, const char *name,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct imap_arg **args)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen{
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen struct imap_fetch_body_data *body;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen const char *partial;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen const char *p = name + 4;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body = p_new(ctx->cmd->pool, struct imap_fetch_body_data, 1);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body->max_size = (uoff_t)-1;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (strncmp(p, ".PEEK", 5) == 0) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body->peek = TRUE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen p += 5;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen } else {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen ctx->flags_update_seen = TRUE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (*p != '[') {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen client_send_command_error(ctx->cmd,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Invalid BODY[..] parameter: Missing '['");
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return FALSE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if ((*args)[0].type == IMAP_ARG_LIST) {
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen /* BODY[HEADER.FIELDS.. (headers list)] */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if ((*args)[1].type != IMAP_ARG_ATOM ||
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen IMAP_ARG_STR(&(*args)[1])[0] != ']') {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen client_send_command_error(ctx->cmd,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Invalid BODY[..] parameter: Missing ']'");
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return FALSE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (!body_section_build(ctx, body, p+1,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen IMAP_ARG_LIST(&(*args)[0])))
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return FALSE;
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen p = IMAP_ARG_STR(&(*args)[1]);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen *args += 2;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen } else {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* no headers list */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body->section = p+1;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen p = strchr(body->section, ']');
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen if (p == NULL) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen client_send_command_error(ctx->cmd,
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen "Invalid BODY[..] parameter: Missing ']'");
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return FALSE;
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen }
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen body->section = p_strdup_until(ctx->cmd->pool,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body->section, p);
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen }
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen if (*++p == '<') {
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen /* <start.end> */
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen partial = p;
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen p++;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body->skip_set = TRUE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (!read_uoff_t(&p, &body->skip) || body->skip > OFF_T_MAX) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* wrapped */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen client_send_command_error(ctx->cmd,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Invalid BODY[..] parameter: "
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Too big partial start");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (*p == '.') {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen p++;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (!read_uoff_t(&p, &body->max_size) ||
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen body->max_size > OFF_T_MAX) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* wrapped */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen client_send_command_error(ctx->cmd,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Invalid BODY[..] parameter: "
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Too big partial end");
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return FALSE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (*p != '>') {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen client_send_command_error(ctx->cmd,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen t_strdup_printf("Invalid BODY[..] parameter: "
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Missing '>' in '%s'",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen partial));
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return fetch_body_section_name_init(ctx, body);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_rfc822_size(struct imap_fetch_context *ctx, struct mail *mail,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen void *context __attr_unused__)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen uoff_t size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen size = mail_get_virtual_size(mail);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (size == (uoff_t)-1)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str_printfa(ctx->cur_str, "RFC822.SIZE %"PRIuUOFF_T" ", size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return 1;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen}
41955c400476941fa274f18b106a5922866fd780Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_rfc822(struct imap_fetch_context *ctx, struct mail *mail,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen void *context __attr_unused__)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct message_size hdr_size, body_size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *str;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->cur_input = mail_get_stream(mail, &hdr_size, &body_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ctx->cur_input == NULL)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_ref(ctx->cur_input);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->update_partial = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen message_size_add(&body_size, &hdr_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ctx->cur_offset == 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str = t_strdup_printf(" RFC822 {%"PRIuUOFF_T"}\r\n",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen body_size.virtual_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ctx->first) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str++; ctx->first = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (o_stream_send_str(ctx->client->output, str) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->cur_size = body_size.virtual_size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return fetch_stream(ctx, &body_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_rfc822_header(struct imap_fetch_context *ctx,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct mail *mail, void *context __attr_unused__)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct message_size hdr_size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *str;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->cur_input = mail_get_stream(mail, &hdr_size, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ctx->cur_input == NULL)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_ref(ctx->cur_input);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->update_partial = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str = t_strdup_printf(" RFC822.HEADER {%"PRIuUOFF_T"}\r\n",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen hdr_size.virtual_size);
41955c400476941fa274f18b106a5922866fd780Timo Sirainen if (ctx->first) {
41955c400476941fa274f18b106a5922866fd780Timo Sirainen str++; ctx->first = FALSE;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen }
41955c400476941fa274f18b106a5922866fd780Timo Sirainen if (o_stream_send_str(ctx->client->output, str) < 0)
41955c400476941fa274f18b106a5922866fd780Timo Sirainen return -1;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen
41955c400476941fa274f18b106a5922866fd780Timo Sirainen ctx->cur_size = hdr_size.virtual_size;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen return fetch_stream(ctx, &hdr_size);
41955c400476941fa274f18b106a5922866fd780Timo Sirainen}
41955c400476941fa274f18b106a5922866fd780Timo Sirainen
41955c400476941fa274f18b106a5922866fd780Timo Sirainenstatic int fetch_rfc822_text(struct imap_fetch_context *ctx, struct mail *mail,
41955c400476941fa274f18b106a5922866fd780Timo Sirainen void *context __attr_unused__)
41955c400476941fa274f18b106a5922866fd780Timo Sirainen{
41955c400476941fa274f18b106a5922866fd780Timo Sirainen struct message_size hdr_size, body_size;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen const char *str;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen
41955c400476941fa274f18b106a5922866fd780Timo Sirainen ctx->cur_input = mail_get_stream(mail, &hdr_size, &body_size);
41955c400476941fa274f18b106a5922866fd780Timo Sirainen if (ctx->cur_input == NULL)
41955c400476941fa274f18b106a5922866fd780Timo Sirainen return -1;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen
41955c400476941fa274f18b106a5922866fd780Timo Sirainen i_stream_ref(ctx->cur_input);
41955c400476941fa274f18b106a5922866fd780Timo Sirainen ctx->update_partial = FALSE;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen
41955c400476941fa274f18b106a5922866fd780Timo Sirainen str = t_strdup_printf(" RFC822.TEXT {%"PRIuUOFF_T"}\r\n",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen body_size.virtual_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ctx->first) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str++; ctx->first = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (o_stream_send_str(ctx->client->output, str) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_seek(ctx->cur_input, hdr_size.physical_size);
41955c400476941fa274f18b106a5922866fd780Timo Sirainen ctx->cur_size = body_size.virtual_size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return fetch_stream(ctx, &body_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenint fetch_rfc822_init(struct imap_fetch_context *ctx, const char *name,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct imap_arg **args __attr_unused__)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (name[6] == '\0') {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER |
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen MAIL_FETCH_STREAM_BODY;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->flags_update_seen = TRUE;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_rfc822, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (strcmp(name+6, ".SIZE") == 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->fetch_data |= MAIL_FETCH_VIRTUAL_SIZE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen imap_fetch_add_handler(ctx, TRUE, fetch_rfc822_size, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (strcmp(name+6, ".HEADER") == 0) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_rfc822_header, NULL);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return TRUE;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen }
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (strcmp(name+6, ".TEXT") == 0) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_BODY;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->flags_update_seen = TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_rfc822_text, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen client_send_command_error(ctx->cmd, t_strconcat(
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Unknown parameter ", name, NULL));
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen