imap-fetch-body.c revision 0d82d7744160c598ecfe73ec25598ad43596d10c
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "imap-common.h"
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen#include "buffer.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "str.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "strescape.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "istream.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "ostream.h"
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen#include "istream-header-filter.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "message-parser.h"
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen#include "message-send.h"
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen#include "mail-storage-private.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "imap-parser.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "imap-fetch.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include <stdlib.h>
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include <ctype.h>
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen#include <unistd.h>
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstruct imap_fetch_body_data {
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen struct imap_fetch_body_data *next;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen struct mailbox_header_lookup_ctx *header_ctx;
12d38e76ba7f70d6219c89ec7416fea0d5de7e02Timo Sirainen const char *section; /* NOTE: always uppercased */
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen uoff_t skip, max_size; /* if you don't want max_size,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen set it to (uoff_t)-1 */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *const *fields;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen size_t fields_count;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int skip_set:1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int peek:1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen};
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainenstatic void fetch_read_error(struct imap_fetch_context *ctx)
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen{
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen errno = ctx->cur_input->stream_errno;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mail_storage_set_critical(ctx->box->storage,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen "read(%s) failed: %m (FETCH for mailbox %s UID %u)",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_stream_get_name(ctx->cur_input),
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mailbox_get_vname(ctx->cur_mail->box), ctx->cur_mail->uid);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenstatic int seek_partial(unsigned int select_counter, unsigned int uid,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct partial_fetch_cache *partial,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct istream *stream,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen uoff_t virtual_skip, bool *cr_skipped_r)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen if (select_counter == partial->select_counter && uid == partial->uid &&
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen stream->v_offset == partial->physical_start &&
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen virtual_skip >= partial->pos.virtual_size) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* we can use the cache */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen virtual_skip -= partial->pos.virtual_size;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen } else {
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen partial->select_counter = select_counter;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen partial->uid = uid;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen partial->physical_start = stream->v_offset;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen partial->cr_skipped = FALSE;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen memset(&partial->pos, 0, sizeof(partial->pos));
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen }
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen i_stream_seek(stream, partial->physical_start +
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen partial->pos.physical_size);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (message_skip_virtual(stream, virtual_skip, &partial->pos,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen partial->cr_skipped, cr_skipped_r) < 0)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen return -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen partial->cr_skipped = FALSE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic uoff_t get_send_size(const struct imap_fetch_body_data *body,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen uoff_t max_size)
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen uoff_t size;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (body->skip >= max_size)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen size = max_size - body->skip;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return size <= body->max_size ? size : body->max_size;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic const char *get_body_name(const struct imap_fetch_body_data *body)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen string_t *str;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str = t_str_new(128);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_printfa(str, "BODY[%s]", body->section);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (body->skip_set)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen str_printfa(str, "<%"PRIuUOFF_T">", body->skip);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen return str_c(str);
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainen}
026d971be5201aed5ccf60138900770e42cf0de5Timo Sirainen
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainenstatic string_t *get_prefix(struct imap_fetch_context *ctx,
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen const struct imap_fetch_body_data *body,
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen uoff_t size)
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen string_t *str;
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen str = t_str_new(128);
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen if (ctx->first)
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen ctx->first = FALSE;
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen else
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, ' ');
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, get_body_name(body));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (size != (uoff_t)-1)
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen str_printfa(str, " {%"PRIuUOFF_T"}\r\n", size);
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen else
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen str_append(str, " NIL");
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen return str;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen}
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainenstatic off_t imap_fetch_send(struct imap_fetch_context *ctx,
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen struct ostream *output, struct istream *input,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen bool cr_skipped, uoff_t virtual_size,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen bool add_missing_eoh, bool *last_cr)
d1ba8ecbb936ace90179d2292952546708d68f71Timo Sirainen{
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen const unsigned char *msg;
4b1781e4c64be52e25b5994e5242dbe696cc7d29Timo Sirainen size_t i, size;
4b1781e4c64be52e25b5994e5242dbe696cc7d29Timo Sirainen uoff_t vsize_left, sent;
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen off_t ret;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen unsigned char add;
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen bool blocks = FALSE;
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen /* go through the message data and insert CRs where needed. */
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen sent = 0; vsize_left = virtual_size;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen while (vsize_left > 0 && !blocks &&
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen i_stream_read_data(input, &msg, &size, 0) > 0) {
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen add = '\0';
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen for (i = 0; i < size && vsize_left > 0; i++) {
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen vsize_left--;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen if (msg[i] == '\n') {
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen if ((i > 0 && msg[i-1] != '\r') ||
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen (i == 0 && !cr_skipped)) {
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen /* missing CR */
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen add = '\r';
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen break;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen }
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen } else if (msg[i] == '\0') {
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen add = 128;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen break;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen }
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen }
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen if ((ret = o_stream_send(output, msg, i)) < 0)
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen return -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if ((uoff_t)ret < i) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen add = '\0';
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen blocks = TRUE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ret > 0)
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen cr_skipped = msg[ret-1] == '\r';
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen i_stream_skip(input, ret);
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen sent += ret;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (add != '\0') {
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if ((ret = o_stream_send(output, &add, 1)) < 0)
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi return -1;
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi if (ret == 0)
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi blocks = TRUE;
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi else {
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen sent++;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen cr_skipped = add == '\r';
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (add == 128)
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen i_stream_skip(input, 1);
865a82c1e9bba11609835a36674964649025bf77Timo Sirainen }
865a82c1e9bba11609835a36674964649025bf77Timo Sirainen }
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen }
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen if (input->stream_errno != 0) {
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen fetch_read_error(ctx);
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen return -1;
5d4855d7b4dcffb6975ed8e3c9c376dac74e5c8aTimo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen if (add_missing_eoh && sent + 2 == virtual_size) {
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen /* Netscape missing EOH workaround. */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen o_stream_set_max_buffer_size(output, (size_t)-1);
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen if (o_stream_send(output, "\r\n", 2) < 0)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen sent += 2;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if ((uoff_t)sent != virtual_size && !blocks) {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* Input stream gave less data than we expected. Two choices
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen here: either we fill the missing data with spaces or we
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen disconnect the client.
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen We shouldn't really ever get here. One reason is if mail
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen was deleted from NFS server while we were reading it.
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen Another is some temporary disk error.
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen If we filled the missing data the client could cache it,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen and if it was just a temporary error the message would be
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen permanently left corrupted in client's local cache. So, we
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen disconnect the client and hope that next try works. */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("FETCH %s for mailbox %s UID %u got too little data: "
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen "%"PRIuUOFF_T" vs %"PRIuUOFF_T, ctx->cur_name,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mailbox_get_vname(ctx->cur_mail->box),
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen ctx->cur_mail->uid, (uoff_t)sent, virtual_size);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_set_cache_corrupted(ctx->cur_mail, ctx->cur_size_field);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_disconnect(ctx->client, "FETCH failed");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return -1;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *last_cr = cr_skipped;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen return sent;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen}
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainenstatic int fetch_stream_send(struct imap_fetch_context *ctx)
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen{
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen off_t ret;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen o_stream_set_max_buffer_size(ctx->client->output, 4096);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen ret = imap_fetch_send(ctx, ctx->client->output, ctx->cur_input,
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen ctx->skip_cr, ctx->cur_size - ctx->cur_offset,
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen ctx->cur_append_eoh, &ctx->skip_cr);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen if (ret < 0)
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen return -1;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen ctx->cur_offset += ret;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (ctx->update_partial) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen struct partial_fetch_cache *p = &ctx->client->last_partial;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen p->cr_skipped = ctx->skip_cr != 0;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen p->pos.physical_size =
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen ctx->cur_input->v_offset - p->physical_start;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen p->pos.virtual_size += ret;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen return ctx->cur_offset == ctx->cur_size;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen}
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int fetch_stream_send_direct(struct imap_fetch_context *ctx)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen off_t ret;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_set_max_buffer_size(ctx->client->output, 0);
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen ret = o_stream_send_istream(ctx->client->output, ctx->cur_input);
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen if (ret < 0)
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen return -1;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi ctx->cur_offset += ret;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen if (ctx->cur_append_eoh && ctx->cur_offset + 2 == ctx->cur_size) {
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi /* Netscape missing EOH workaround. */
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi if (o_stream_send(ctx->client->output, "\r\n", 2) < 0)
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi return -1;
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi ctx->cur_offset += 2;
865a82c1e9bba11609835a36674964649025bf77Timo Sirainen ctx->cur_append_eoh = FALSE;
865a82c1e9bba11609835a36674964649025bf77Timo Sirainen }
3db05c8c00faca6ab9ac8391e1d6977365f4d1b3Timo Sirainen
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen if (ctx->cur_offset != ctx->cur_size) {
3db05c8c00faca6ab9ac8391e1d6977365f4d1b3Timo Sirainen /* unfinished */
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen if (!i_stream_have_bytes_left(ctx->cur_input)) {
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen /* Input stream gave less data than expected */
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen i_error("FETCH %s for mailbox %s UID %u "
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen "got too little data (copying): "
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen "%"PRIuUOFF_T" vs %"PRIuUOFF_T,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cur_name, mailbox_get_vname(ctx->cur_mail->box),
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cur_mail->uid, ctx->cur_offset, ctx->cur_size);
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen mail_set_cache_corrupted(ctx->cur_mail,
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen ctx->cur_size_field);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen client_disconnect(ctx->client, "FETCH failed");
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen return -1;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_set_flush_pending(ctx->client->output, TRUE);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen return 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen return 1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int fetch_stream(struct imap_fetch_context *ctx,
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen const struct message_size *size)
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen{
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen struct istream *input;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (size->physical_size == size->virtual_size &&
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ctx->cur_mail->has_no_nuls) {
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen /* no need to kludge with CRs, we can use sendfile() */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen input = i_stream_create_limit(ctx->cur_input, ctx->cur_size);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen i_stream_unref(&ctx->cur_input);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cur_input = input;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen ctx->cont_handler = fetch_stream_send_direct;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen } else {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen ctx->cont_handler = fetch_stream_send;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen return ctx->cont_handler(ctx);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen}
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainenstatic int fetch_data(struct imap_fetch_context *ctx,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const struct imap_fetch_body_data *body,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const struct message_size *size)
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen string_t *str;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ctx->cur_name = p_strconcat(ctx->cmd->pool,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen "[", body->section, "]", NULL);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ctx->cur_size = get_send_size(body, size->virtual_size);
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen str = get_prefix(ctx, body, ctx->cur_size);
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen if (o_stream_send(ctx->client->output,
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen str_data(str), str_len(str)) < 0)
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen return -1;
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen if (!ctx->update_partial) {
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen if (message_skip_virtual(ctx->cur_input, body->skip, NULL,
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen FALSE, &ctx->skip_cr) < 0) {
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen fetch_read_error(ctx);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen } else {
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen if (seek_partial(ctx->select_counter, ctx->cur_mail->uid,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen &ctx->client->last_partial, ctx->cur_input,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen body->skip, &ctx->skip_cr) < 0) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen fetch_read_error(ctx);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return -1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen return fetch_stream(ctx, size);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const struct imap_fetch_body_data *body)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen{
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const struct message_size *fetch_size;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen struct istream *input;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen struct message_size hdr_size, body_size;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (body->section[0] == '\0') {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (mail_get_stream(mail, NULL, NULL, &input) < 0 ||
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen mail_get_virtual_size(mail, &body_size.virtual_size) < 0 ||
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen mail_get_physical_size(mail, &body_size.physical_size) < 0)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return -1;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen } else {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (mail_get_stream(mail, &hdr_size,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen body->section[0] == 'H' ? NULL : &body_size,
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen &input) < 0)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return -1;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen ctx->cur_input = input;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen i_stream_ref(ctx->cur_input);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ctx->update_partial = TRUE;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen switch (body->section[0]) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen case '\0':
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* BODY[] - fetch everything */
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen fetch_size = &body_size;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ctx->cur_size_field = MAIL_FETCH_VIRTUAL_SIZE;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen break;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen case 'H':
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* BODY[HEADER] - fetch only header */
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen fetch_size = &hdr_size;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ctx->cur_size_field = MAIL_FETCH_MESSAGE_PARTS;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen break;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen case 'T':
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* BODY[TEXT] - skip header */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen i_stream_skip(ctx->cur_input, hdr_size.physical_size);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen fetch_size = &body_size;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ctx->cur_size_field = MAIL_FETCH_VIRTUAL_SIZE;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen break;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen default:
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen i_unreached();
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return fetch_data(ctx, body, fetch_size);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainenstatic void header_filter_eoh(struct message_header_line *hdr,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen bool *matched ATTR_UNUSED,
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen struct imap_fetch_context *ctx)
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen{
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen if (hdr != NULL && hdr->eoh)
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen ctx->cur_have_eoh = TRUE;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen}
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainenstatic int fetch_header_partial_from(struct imap_fetch_context *ctx,
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen const struct imap_fetch_body_data *body,
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen const char *header_section)
865a82c1e9bba11609835a36674964649025bf77Timo Sirainen{
865a82c1e9bba11609835a36674964649025bf77Timo Sirainen struct message_size msg_size;
75b4cc30566e22675b9e7b19b15a7fd929d8f54cTimo Sirainen struct istream *input;
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen uoff_t old_offset;
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen /* MIME, HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen ctx->cur_have_eoh = FALSE;
88e9835c4d8973c62cd4db1ec7324ff46dd3ff15Timo Sirainen if (strncmp(header_section, "HEADER.FIELDS ", 14) == 0) {
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen input = i_stream_create_header_filter(ctx->cur_input,
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen HEADER_FILTER_INCLUDE,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen body->fields,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen body->fields_count,
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen header_filter_eoh, ctx);
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen } else if (strncmp(header_section, "HEADER.FIELDS.NOT ", 18) == 0) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen input = i_stream_create_header_filter(ctx->cur_input,
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen HEADER_FILTER_EXCLUDE,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen body->fields,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen body->fields_count,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen header_filter_eoh, ctx);
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen } else {
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen i_error("BUG: Accepted invalid section from user: '%s'",
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen header_section);
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen return -1;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen }
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen i_stream_unref(&ctx->cur_input);
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen ctx->cur_input = input;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen ctx->update_partial = FALSE;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen old_offset = ctx->cur_input->v_offset;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen if (message_get_header_size(ctx->cur_input, &msg_size, NULL) < 0) {
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen fetch_read_error(ctx);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return -1;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_stream_seek(ctx->cur_input, old_offset);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cur_size_field = 0;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen return fetch_data(ctx, body, &msg_size);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen}
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainenstatic int
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainenfetch_body_header_partial(struct imap_fetch_context *ctx, struct mail *mail,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen const struct imap_fetch_body_data *body)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen{
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (mail_get_stream(mail, NULL, NULL, &ctx->cur_input) < 0)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen return -1;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen i_stream_ref(ctx->cur_input);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen ctx->update_partial = FALSE;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return fetch_header_partial_from(ctx, body, body->section);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen}
6dd436dbf05c6c96fc4b6873bb9b44ede860edd7Timo Sirainen
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainenstatic int
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainenfetch_body_header_fields(struct imap_fetch_context *ctx, struct mail *mail,
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen struct imap_fetch_body_data *body)
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen{
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen struct message_size size;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen uoff_t old_offset;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (mail == NULL) {
3bfdab77880db25dbdc8bf48c2cfc2d50b98e426Aki Tuomi /* deinit */
3bfdab77880db25dbdc8bf48c2cfc2d50b98e426Aki Tuomi mailbox_header_lookup_unref(&body->header_ctx);
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainen return 0;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (mail_get_header_stream(mail, body->header_ctx, &ctx->cur_input) < 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return -1;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen i_stream_ref(ctx->cur_input);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen ctx->update_partial = FALSE;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen old_offset = ctx->cur_input->v_offset;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen if (message_get_body_size(ctx->cur_input, &size, NULL) < 0) {
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen fetch_read_error(ctx);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen return -1;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen }
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen i_stream_seek(ctx->cur_input, old_offset);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen /* FIXME: We'll just always add the end of headers line now.
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen ideally mail-storage would have a way to tell us if it exists. */
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen size.virtual_size += 2;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen ctx->cur_append_eoh = TRUE;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen ctx->cur_size_field = 0;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen return fetch_data(ctx, body, &size);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen}
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen/* Find message_part for section (eg. 1.3.4) */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic int part_find(struct mail *mail, const struct imap_fetch_body_data *body,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const struct message_part **part_r, const char **section_r)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct message_part *part;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const char *path;
7cba14a4c3beb026a2862ee50d24c554fa713329Timo Sirainen unsigned int num;
7cba14a4c3beb026a2862ee50d24c554fa713329Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (mail_get_parts(mail, &part) < 0)
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen return -1;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen path = body->section;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen while (*path >= '0' && *path <= '9' && part != NULL) {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen /* get part number, we have already verified its validity */
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen num = 0;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen while (*path != '\0' && *path != '.') {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_assert(*path >= '0' && *path <= '9');
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen num = num*10 + (*path - '0');
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen path++;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (*path == '.')
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen path++;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (part->flags & MESSAGE_PART_FLAG_MULTIPART) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* find the part */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen part = part->children;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen for (; num > 1 && part != NULL; num--)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen part = part->next;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen } else {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* only 1 allowed with non-multipart messages */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (num != 1)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen part = NULL;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (part != NULL &&
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) &&
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen (*path >= '0' && *path <= '9')) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* if we continue inside the message/rfc822, skip this
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen body part */
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen part = part->children;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen *part_r = part;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *section_r = path;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return 0;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic int fetch_body_mime(struct imap_fetch_context *ctx, struct mail *mail,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const struct imap_fetch_body_data *body)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const struct message_part *part;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const char *section;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (part_find(mail, body, &part, &section) < 0)
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen return -1;
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen if (part == NULL) {
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen /* part doesn't exist */
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen string_t *str = get_prefix(ctx, body, (uoff_t)-1);
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen if (o_stream_send(ctx->client->output,
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen str_data(str), str_len(str)) < 0)
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen return -1;
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen return 1;
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen if (mail_get_stream(mail, NULL, NULL, &ctx->cur_input) < 0)
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen return -1;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_stream_ref(ctx->cur_input);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ctx->update_partial = TRUE;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen ctx->cur_size_field = MAIL_FETCH_MESSAGE_PARTS;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (*section == '\0') {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* fetch the whole section */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos +
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen part->header_size.physical_size);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return fetch_data(ctx, body, &part->body_size);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (strcmp(section, "MIME") == 0) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* fetch section's MIME header */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen return fetch_data(ctx, body, &part->header_size);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen }
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen /* TEXT and HEADER are only for message/rfc822 parts */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) == 0) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen string_t *str = get_prefix(ctx, body, 0);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (o_stream_send(ctx->client->output,
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen str_data(str), str_len(str)) < 0)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return -1;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen return 1;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_assert(part->children != NULL && part->children->next == NULL);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen part = part->children;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (strcmp(section, "TEXT") == 0) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos +
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen part->header_size.physical_size);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen return fetch_data(ctx, body, &part->body_size);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen if (strcmp(section, "HEADER") == 0) {
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen /* all headers */
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return fetch_data(ctx, body, &part->header_size);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (strncmp(section, "HEADER", 6) == 0) {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen return fetch_header_partial_from(ctx, body, section);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen }
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen i_error("BUG: Accepted invalid section from user: '%s'", body->section);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen return 1;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen}
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenstatic bool fetch_body_header_fields_check(const char *section)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (*section++ != '(')
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek return FALSE;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (*section == ')')
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return FALSE; /* has to be at least one field */
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen while (*section != '\0' && *section != ')') {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen if (*section == '(')
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen return FALSE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen section++;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (*section++ != ')')
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return FALSE;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (*section != '\0')
459b483806babd159daa8b461377281d89bb3bdcTimo Sirainen return FALSE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return TRUE;
3bfdab77880db25dbdc8bf48c2cfc2d50b98e426Aki Tuomi}
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainenstatic bool fetch_body_header_fields_init(struct imap_fetch_context *ctx,
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen struct imap_fetch_body_data *body,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *section)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *const *arr, *name;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen if (!fetch_body_header_fields_check(section))
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen return FALSE;
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen name = get_body_name(body);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen MAIL_FETCH_STREAM_BODY)) != 0) {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* we'll need to open the file anyway, don't try to get the
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen headers from cache. */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen fetch_body_header_partial, body);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen return TRUE;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen }
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen for (arr = body->fields; *arr != NULL; arr++) {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen const char *hdr = p_strdup(ctx->cmd->pool, *arr);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen array_append(&ctx->all_headers, &hdr, 1);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen }
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen body->header_ctx = mailbox_header_lookup_init(ctx->box, body->fields);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen imap_fetch_add_handler(ctx, FALSE, TRUE, name, "NIL",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen fetch_body_header_fields, body);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return TRUE;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen}
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainenstatic bool fetch_body_section_name_init(struct imap_fetch_context *ctx,
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen struct imap_fetch_body_data *body)
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen{
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen const char *name, *section = body->section;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen name = get_body_name(body);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen if (*section == '\0') {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER |
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen MAIL_FETCH_STREAM_BODY;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen fetch_body, body);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen return TRUE;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen }
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen if (strcmp(section, "TEXT") == 0) {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_BODY;
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen fetch_body, body);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return TRUE;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strncmp(section, "HEADER", 6) == 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* exact header matches could be cached */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (section[6] == '\0') {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen fetch_body, body);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return TRUE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strncmp(section, "HEADER.FIELDS ", 14) == 0 &&
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen fetch_body_header_fields_init(ctx, body, section+14))
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return TRUE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 &&
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen fetch_body_header_fields_check(section+18)) {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen fetch_body_header_partial, body);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen return TRUE;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen }
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen } else if (*section >= '0' && *section <= '9') {
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen ctx->fetch_data |= MAIL_FETCH_STREAM_BODY |
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen MAIL_FETCH_MESSAGE_PARTS;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen while ((*section >= '0' && *section <= '9') ||
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen *section == '.') section++;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen if (*section == '\0' ||
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen strcmp(section, "MIME") == 0 ||
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen strcmp(section, "TEXT") == 0 ||
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen strcmp(section, "HEADER") == 0 ||
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen (strncmp(section, "HEADER.FIELDS ", 14) == 0 &&
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen fetch_body_header_fields_check(section+14)) ||
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 &&
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen fetch_body_header_fields_check(section+18))) {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen fetch_body_mime, body);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen return TRUE;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen }
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen }
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen client_send_command_error(ctx->cmd,
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen "Invalid BODY[..] parameter: Unknown or broken section");
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen return FALSE;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen}
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen/* Parse next digits in string into integer. Returns FALSE if the integer
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen becomes too big and wraps. */
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenstatic bool read_uoff_t(const char **p, uoff_t *value)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen uoff_t prev;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *value = 0;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen while (**p >= '0' && **p <= '9') {
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen prev = *value;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *value = *value * 10 + (**p - '0');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (*value < prev)
02967c39a2f4922fe433718e0f9ef0e6031c432bTimo Sirainen return FALSE;
02967c39a2f4922fe433718e0f9ef0e6031c432bTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen (*p)++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen return TRUE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstatic bool body_section_build(struct imap_fetch_context *ctx,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct imap_fetch_body_data *body,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *prefix,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct imap_arg *args,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int args_count)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen string_t *str;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char **arr, *value;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen size_t i;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str = str_new(ctx->cmd->pool, 128);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, prefix);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, " (");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* @UNSAFE: NULL-terminated list of headers */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen arr = p_new(ctx->cmd->pool, const char *, args_count + 1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (i = 0; i < args_count; i++) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!imap_arg_get_astring(&args[i], &value)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_send_command_error(ctx->cmd,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "Invalid BODY[..] parameter: "
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "Header list contains non-strings");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return FALSE;
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi }
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (i != 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, ' ');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen arr[i] = p_strdup(ctx->cmd->pool, t_str_ucase(value));
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen if (args[i].type == IMAP_ARG_ATOM)
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen str_append(str, arr[i]);
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen else {
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen str_append_c(str, '"');
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen str_append(str, str_escape(arr[i]));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, '"');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen str_append_c(str, ')');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen qsort(arr, args_count, sizeof(*arr), i_strcasecmp_p);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen body->fields = arr;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen body->fields_count = args_count;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen body->section = str_c(str);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return TRUE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenbool fetch_body_section_init(struct imap_fetch_context *ctx, const char *name,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct imap_arg **args)
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek{
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek struct imap_fetch_body_data *body;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct imap_arg *list_args;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int list_count;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *partial, *str;
7cba14a4c3beb026a2862ee50d24c554fa713329Timo Sirainen const char *p = name + 4;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen body = p_new(ctx->cmd->pool, struct imap_fetch_body_data, 1);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen body->max_size = (uoff_t)-1;
7cba14a4c3beb026a2862ee50d24c554fa713329Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strncmp(p, ".PEEK", 5) == 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen body->peek = TRUE;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen p += 5;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen } else {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen ctx->flags_update_seen = TRUE;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
4e65040b019c061d242c8bc19bf76009679b8a15Timo Sirainen
4e65040b019c061d242c8bc19bf76009679b8a15Timo Sirainen if (*p != '[') {
4e65040b019c061d242c8bc19bf76009679b8a15Timo Sirainen client_send_command_error(ctx->cmd,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "Invalid BODY[..] parameter: Missing '['");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return FALSE;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (imap_arg_get_list_full(&(*args)[0], &list_args, &list_count)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* BODY[HEADER.FIELDS.. (headers list)] */
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (!imap_arg_get_atom(&(*args)[1], &str) ||
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen str[0] != ']') {
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen client_send_command_error(ctx->cmd,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen "Invalid BODY[..] parameter: Missing ']'");
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen return FALSE;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (!body_section_build(ctx, body, p+1, list_args, list_count))
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen return FALSE;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen p = str;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen *args += 2;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen } else {
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen /* no headers list */
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen body->section = p+1;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen p = strchr(body->section, ']');
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (p == NULL) {
a355fad576bc0c95b11161cf48b48d343229a2b3Timo Sirainen client_send_command_error(ctx->cmd,
a355fad576bc0c95b11161cf48b48d343229a2b3Timo Sirainen "Invalid BODY[..] parameter: Missing ']'");
a355fad576bc0c95b11161cf48b48d343229a2b3Timo Sirainen return FALSE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen body->section = p_strdup_until(ctx->cmd->pool,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen body->section, p);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen }
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (*++p == '<') {
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen /* <start.end> */
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen partial = p;
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen p++;
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen body->skip_set = TRUE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
12d38e76ba7f70d6219c89ec7416fea0d5de7e02Timo Sirainen if (!read_uoff_t(&p, &body->skip) || body->skip > OFF_T_MAX) {
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen /* wrapped */
client_send_command_error(ctx->cmd,
"Invalid BODY[..] parameter: "
"Too big partial start");
return FALSE;
}
if (*p == '.') {
p++;
if (!read_uoff_t(&p, &body->max_size) ||
body->max_size > OFF_T_MAX) {
/* wrapped */
client_send_command_error(ctx->cmd,
"Invalid BODY[..] parameter: "
"Too big partial end");
return FALSE;
}
}
if (*p != '>') {
client_send_command_error(ctx->cmd,
t_strdup_printf("Invalid BODY[..] parameter: "
"Missing '>' in '%s'",
partial));
return FALSE;
}
}
return fetch_body_section_name_init(ctx, body);
}
static int fetch_rfc822_size(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
uoff_t size;
if (mail_get_virtual_size(mail, &size) < 0)
return -1;
str_printfa(ctx->cur_str, "RFC822.SIZE %"PRIuUOFF_T" ", size);
return 1;
}
static int fetch_rfc822(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
struct message_size size;
const char *str;
struct istream *input;
if (mail_get_stream(mail, NULL, NULL, &input) < 0 ||
mail_get_virtual_size(mail, &size.virtual_size) < 0 ||
mail_get_physical_size(mail, &size.physical_size) < 0)
return -1;
ctx->cur_input = input;
i_stream_ref(ctx->cur_input);
ctx->update_partial = FALSE;
if (ctx->cur_offset == 0) {
str = t_strdup_printf(" RFC822 {%"PRIuUOFF_T"}\r\n",
size.virtual_size);
if (ctx->first) {
str++; ctx->first = FALSE;
}
if (o_stream_send_str(ctx->client->output, str) < 0)
return -1;
}
ctx->cur_name = "RFC822";
ctx->cur_size = size.virtual_size;
ctx->cur_size_field = MAIL_FETCH_VIRTUAL_SIZE;
return fetch_stream(ctx, &size);
}
static int fetch_rfc822_header(struct imap_fetch_context *ctx,
struct mail *mail, void *context ATTR_UNUSED)
{
struct message_size hdr_size;
const char *str;
if (mail_get_stream(mail, &hdr_size, NULL, &ctx->cur_input) < 0)
return -1;
i_stream_ref(ctx->cur_input);
ctx->update_partial = FALSE;
str = t_strdup_printf(" RFC822.HEADER {%"PRIuUOFF_T"}\r\n",
hdr_size.virtual_size);
if (ctx->first) {
str++; ctx->first = FALSE;
}
if (o_stream_send_str(ctx->client->output, str) < 0)
return -1;
ctx->cur_name = "RFC822.HEADER";
ctx->cur_size = hdr_size.virtual_size;
ctx->cur_size_field = MAIL_FETCH_MESSAGE_PARTS;
return fetch_stream(ctx, &hdr_size);
}
static int fetch_rfc822_text(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
{
struct message_size hdr_size, body_size;
const char *str;
if (mail_get_stream(mail, &hdr_size, &body_size, &ctx->cur_input) < 0)
return -1;
i_stream_ref(ctx->cur_input);
ctx->update_partial = FALSE;
str = t_strdup_printf(" RFC822.TEXT {%"PRIuUOFF_T"}\r\n",
body_size.virtual_size);
if (ctx->first) {
str++; ctx->first = FALSE;
}
if (o_stream_send_str(ctx->client->output, str) < 0)
return -1;
i_stream_seek(ctx->cur_input, hdr_size.physical_size);
ctx->cur_name = "RFC822.TEXT";
ctx->cur_size = body_size.virtual_size;
ctx->cur_size_field = MAIL_FETCH_VIRTUAL_SIZE;
return fetch_stream(ctx, &body_size);
}
bool fetch_rfc822_init(struct imap_fetch_context *ctx, const char *name,
const struct imap_arg **args ATTR_UNUSED)
{
if (name[6] == '\0') {
ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER |
MAIL_FETCH_STREAM_BODY;
ctx->flags_update_seen = TRUE;
imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
fetch_rfc822, NULL);
return TRUE;
}
if (strcmp(name+6, ".SIZE") == 0) {
ctx->fetch_data |= MAIL_FETCH_VIRTUAL_SIZE;
imap_fetch_add_handler(ctx, TRUE, FALSE, name, "0",
fetch_rfc822_size, NULL);
return TRUE;
}
if (strcmp(name+6, ".HEADER") == 0) {
ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER;
imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
fetch_rfc822_header, NULL);
return TRUE;
}
if (strcmp(name+6, ".TEXT") == 0) {
ctx->fetch_data |= MAIL_FETCH_STREAM_BODY;
ctx->flags_update_seen = TRUE;
imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
fetch_rfc822_text, NULL);
return TRUE;
}
client_send_command_error(ctx->cmd, t_strconcat(
"Unknown parameter ", name, NULL));
return FALSE;
}