imap-msgpart.c revision d65184737a0465602db98e103f9097b1a1ea9564
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "lib.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "str.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "array.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "istream.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "istream-crlf.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "istream-nonuls.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "istream-base64.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "istream-header-filter.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "istream-qp.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "ostream.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "message-parser.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "message-decoder.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "mail-storage-private.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "mail-namespace.h"
70375a50991814959d061db0e2d4da35e542e437Timo Sirainen#include "imap-bodystructure.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "imap-parser.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "imap-msgpart.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschenum fetch_type {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch FETCH_FULL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch FETCH_MIME,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch FETCH_MIME_BODY,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch FETCH_HEADER,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch FETCH_HEADER_FIELDS,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch FETCH_HEADER_FIELDS_NOT,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch FETCH_BODY
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct imap_msgpart {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pool_t pool;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* "" for root, otherwise e.g. "1.2.3". the .MIME, .HEADER, etc.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch suffix not included */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *section_number;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch enum fetch_type fetch_type;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch enum mail_fetch_field wanted_fields;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* HEADER.FIELDS[.NOT] (list of headers) */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct mailbox_header_lookup_ctx *header_ctx;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *const *headers;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* which part of the message part to fetch (default: 0..(uoff_t)-1) */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uoff_t partial_offset, partial_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int decode_cte_to_binary:1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct imap_msgpart_open_ctx {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* from matching message_part, set after opening: */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uoff_t physical_pos;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_size mime_hdr_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_size mime_body_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
2d8ff6cda406da5c53e635fe31dfadc3bdb05235Timo Sirainen
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic struct imap_msgpart *imap_msgpart_type(enum fetch_type fetch_type)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_msgpart *msgpart;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pool_t pool;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pool = pool_alloconly_create("imap msgpart", sizeof(*msgpart)+32);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart = p_new(pool, struct imap_msgpart, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->pool = pool;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->partial_size = (uoff_t)-1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type = fetch_type;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->section_number = "";
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (fetch_type == FETCH_HEADER || fetch_type == FETCH_FULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->wanted_fields |= MAIL_FETCH_STREAM_HEADER;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (fetch_type == FETCH_BODY || fetch_type == FETCH_FULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->wanted_fields |= MAIL_FETCH_STREAM_BODY;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return msgpart;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct imap_msgpart *imap_msgpart_full(void)
6541da94741ea43514cdac3dd2ebbcf839ffb783Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return imap_msgpart_type(FETCH_FULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct imap_msgpart *imap_msgpart_header(void)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return imap_msgpart_type(FETCH_HEADER);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct imap_msgpart *imap_msgpart_body(void)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return imap_msgpart_type(FETCH_BODY);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
4fa772eefd5a22a597601488be44997e788cb60dStephan Boschstatic struct message_part *
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_msgpart_find(struct message_part *parts, const char *section)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_part *part = parts;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *path;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int num;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch path = section;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch while (*path >= '0' && *path <= '9' && part != NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* get part number, we have already verified its validity */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch num = 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch while (*path != '\0' && *path != '.') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(*path >= '0' && *path <= '9');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch num = num*10 + (*path - '0');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch path++;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (*path == '.')
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch path++;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* find the part */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part = part->children;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch for (; num > 1 && part != NULL; num--)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part = part->next;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* only 1 allowed with non-multipart messages.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if the child isn't message/rfc822, the path must be
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch finished after this. */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (num != 1)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch else if (*path != '\0' &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) == 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (part != NULL &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) != 0 &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (*path >= '0' && *path <= '9')) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* if we continue inside the message/rfc822, skip this
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch body part */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part = part->children;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(part == NULL || *path == '\0');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return part;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_msgpart_get_header_fields(pool_t pool, const char *header_list,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ARRAY_TYPE(const_string) *fields)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct istream *input;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_parser *parser;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct imap_arg *args, *hdr_list;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int list_count;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int i;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int result = 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch input = i_stream_create_from_data(header_list, strlen(header_list));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch parser = imap_parser_create(input, NULL, (size_t)-1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (imap_parser_finish_line(parser, 0, 0, &args) > 0 &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_arg_get_list_full(args, &hdr_list, &list_count) &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch args[1].type == IMAP_ARG_EOL &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch list_count > 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *value;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch p_array_init(fields, pool, list_count);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch for (i = 0; i < list_count; i++) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!imap_arg_get_astring(&hdr_list[i], &value)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result = -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch value = p_strdup(pool, t_str_ucase(value));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_append(fields, &value, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result = -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* istream-header-filter requires headers to be sorted */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_sort(fields, i_strcasecmp_p);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_parser_unref(&parser);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_unref(&input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return result;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_msgpart_parse_header_fields(struct imap_msgpart *msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *header_list)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ARRAY_TYPE(const_string) fields;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (imap_msgpart_get_header_fields(msgpart->pool, header_list,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch &fields) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_append_zero(&fields);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->headers = array_idx(&fields, 0);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschint imap_msgpart_parse(const char *section, struct imap_msgpart **msgpart_r)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_msgpart *msgpart;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pool_t pool;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int i;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bool next_digit;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pool = pool_alloconly_create("imap msgpart", 1024);
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen msgpart = *msgpart_r = p_new(pool, struct imap_msgpart, 1);
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen msgpart->pool = pool;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->partial_size = (uoff_t)-1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* get the section number */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch next_digit = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch for (i = 0; section[i] != '\0'; i++) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (section[i] >= '0' && section[i] <= '9') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch next_digit = FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (!next_digit && section[i] == '.') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch next_digit = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen if (i == 0) {
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen /* [], [HEADER], etc. */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->section_number = "";
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (section[i] == '\0') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* [1.2.3] */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (i > 0 && section[i-1] == '.') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pool_unref(&pool);
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->section_number = p_strdup(pool, section);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch section = "";
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* [1.2.3.MIME], [1.2.3.HEADER], etc */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (section[i-1] != '.') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pool_unref(&pool);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->section_number = p_strndup(pool, section, i-1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch section += i;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (*section == '\0') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->wanted_fields |= MAIL_FETCH_STREAM_BODY;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (*msgpart->section_number == '\0') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* BODY[] - header+body */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type = FETCH_FULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->wanted_fields |= MAIL_FETCH_STREAM_HEADER;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* BODY[1] - body only */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type = FETCH_MIME_BODY;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch section = t_str_ucase(section);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (strcmp(section, "MIME") == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type = FETCH_MIME;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->wanted_fields |= MAIL_FETCH_STREAM_BODY;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (strcmp(section, "TEXT") == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* body (for root or for message/rfc822) */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type = FETCH_BODY;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->wanted_fields |= MAIL_FETCH_STREAM_BODY;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (strncmp(section, "HEADER", 6) == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* header (for root or for message/rfc822) */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (section[6] == '\0') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type = FETCH_HEADER;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (strncmp(section, "HEADER.FIELDS ", 14) == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type = FETCH_HEADER_FIELDS;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = imap_msgpart_parse_header_fields(msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch section+14);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type = FETCH_HEADER_FIELDS_NOT;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = imap_msgpart_parse_header_fields(msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch section+18);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch ret = -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_msgpart_free(&msgpart);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody if (msgpart->fetch_type == FETCH_HEADER_FIELDS) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* we may be able to get this from cache, don't give a
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch wanted_fields hint */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (*msgpart->section_number == '\0')
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->wanted_fields |= MAIL_FETCH_STREAM_HEADER;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch else
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->wanted_fields |= MAIL_FETCH_STREAM_BODY;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_unreached();
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschvoid imap_msgpart_free(struct imap_msgpart **_msgpart)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch struct imap_msgpart *msgpart = *_msgpart;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *_msgpart = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_msgpart_close_mailbox(msgpart);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pool_unref(&msgpart->pool);
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
4fa772eefd5a22a597601488be44997e788cb60dStephan Boschvoid imap_msgpart_set_decode_to_binary(struct imap_msgpart *msgpart)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->decode_cte_to_binary = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschvoid imap_msgpart_set_partial(struct imap_msgpart *msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uoff_t offset, uoff_t size)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->partial_offset = offset;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->partial_size = size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschuoff_t imap_msgpart_get_partial_offset(struct imap_msgpart *msgpart)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return msgpart->partial_offset;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschenum mail_fetch_field imap_msgpart_get_fetch_data(struct imap_msgpart *msgpart)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return msgpart->wanted_fields;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_msgpart_get_partial_header(struct mail *mail, struct istream *mail_input,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct imap_msgpart *msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_size *hdr_size_r,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_msgpart_open_result *result_r)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *const *hdr_fields = msgpart->headers;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int hdr_count = str_array_length(hdr_fields);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct istream *input;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bool has_nuls;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (msgpart->fetch_type == FETCH_HEADER_FIELDS) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch input = i_stream_create_header_filter(mail_input,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch HEADER_FILTER_INCLUDE |
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch HEADER_FILTER_HIDE_BODY,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch hdr_fields, hdr_count,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *null_header_filter_callback,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (void *)NULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(msgpart->fetch_type == FETCH_HEADER_FIELDS_NOT);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch input = i_stream_create_header_filter(mail_input,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch HEADER_FILTER_EXCLUDE |
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch HEADER_FILTER_HIDE_BODY,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch hdr_fields, hdr_count,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *null_header_filter_callback,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (void *)NULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (message_get_header_size(input, hdr_size_r, &has_nuls) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch errno = input->stream_errno;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mail_storage_set_critical(mail->box->storage,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "read(%s) failed: %m", i_stream_get_name(mail_input));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_unref(&input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_seek(input, 0);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result_r->input = input;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result_r->size = hdr_size_r->virtual_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschskip_using_parts(struct mail *mail, struct istream *input,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uoff_t physical_start, uoff_t *virtual_skip)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch enum mail_lookup_abort old_lookup_abort;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_part *parts, *part;
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen uoff_t vpos;
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen int ret;
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch old_lookup_abort = mail->lookup_abort;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mail->lookup_abort = MAIL_LOOKUP_ABORT_NOT_IN_CACHE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = mail_get_parts(mail, &parts);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mail->lookup_abort = old_lookup_abort;
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen if (ret < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch for (part = parts, vpos = 0; part != NULL; ) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (vpos + part->header_size.virtual_size > *virtual_skip)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* skip header */
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen vpos += part->header_size.virtual_size;
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen *virtual_skip -= part->header_size.virtual_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_seek(input, physical_start + part->physical_pos +
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part->header_size.physical_size);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (vpos + part->body_size.virtual_size <= *virtual_skip) {
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen /* skip body */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch vpos += part->body_size.virtual_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *virtual_skip -= part->body_size.virtual_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_seek(input, physical_start +
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part->physical_pos +
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part->header_size.physical_size +
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part->body_size.physical_size);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part = part->next;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* maybe we have a child and can skip using it? */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part = part->children;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic struct istream *
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_msgpart_crlf_seek(struct mail *mail, struct istream *input,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct imap_msgpart *msgpart)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct mail_msgpart_partial_cache *cache = &mail->box->partial_cache;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct istream *crlf_input;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const unsigned char *data;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch size_t size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uoff_t physical_start = input->v_offset;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uoff_t virtual_skip = msgpart->partial_offset;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(msgpart->headers == NULL); /* HEADER.FIELDS returns CRLFs */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (virtual_skip == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* no need to seek */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (cache->uid == mail->uid &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cache->physical_start == physical_start &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cache->virtual_pos < virtual_skip) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* use cache */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_seek(input, physical_start + cache->physical_pos);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch virtual_skip -= cache->virtual_pos;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* can't use cache, but maybe we can skip faster using the
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch message parts. */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch skip_using_parts(mail, input, physical_start, &virtual_skip);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch crlf_input = i_stream_create_crlf(input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_unref(&input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch input = crlf_input;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_skip(input, virtual_skip);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((msgpart->partial_offset != 0 ||
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->partial_size != (uoff_t)-1) &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_read_data(input, &data, &size, 0) > 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* update cache */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cache->uid = mail->uid;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cache->physical_start = physical_start;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cache->physical_pos = input->v_offset;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cache->virtual_pos = msgpart->partial_offset;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (data[0] == '\n') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* the physical_pos points to virtual CRLF, but
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch virtual_pos already skipped CR. that can't work,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch so seek back the virtual CR */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cache->virtual_pos--;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return input;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_msgpart_get_partial(struct mail *mail, const struct imap_msgpart *msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bool convert_nuls, bool use_partial_cache,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct message_size *part_size,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_msgpart_open_result *result)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct istream *input2;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uoff_t bytes_left;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* input is already seeked to the beginning of the wanted data */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (msgpart->partial_offset >= part_size->virtual_size) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* can't seek past the MIME part */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_unref(&result->input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result->input = i_stream_create_from_data("", 0);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result->size = 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch if (part_size->virtual_size == part_size->physical_size) {
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch /* input has CRLF linefeeds, we can quickly seek to
9008daea438f0e389b37aabbbde62a1f02725e32Timo Sirainen wanted position */
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch i_stream_skip(result->input, msgpart->partial_offset);
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* input has LF linefeeds. it can be slow to seek to wanted
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch position, so try to do caching whenever possible */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(use_partial_cache);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result->input = imap_msgpart_crlf_seek(mail, result->input,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bytes_left = part_size->virtual_size - msgpart->partial_offset;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (msgpart->partial_size <= bytes_left) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* limit output to specified number of bytes */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result->size = msgpart->partial_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* send all bytes */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result->size = bytes_left;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!mail->has_no_nuls && convert_nuls) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* IMAP literals must not contain NULs. change them to
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch 0x80 characters. */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch input2 = i_stream_create_nonuls(result->input, 0x80);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_unref(&result->input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result->input = input2;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch input2 = i_stream_create_limit(result->input, result->size);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_unref(&result->input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result->input = input2;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_msgpart_find_part(struct mail *mail, const struct imap_msgpart *msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_part **part_r)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_part *parts, *part = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (*msgpart->section_number == '\0') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *part_r = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_parts(mail, &parts) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part = imap_msgpart_find(parts, msgpart->section_number);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (part == NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* MIME part not found. */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *part_r = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch switch (msgpart->fetch_type) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_MIME:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* What to do if this is a message/rfc822? Does it have
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch MIME headers or not? Possibilities are: a) no, return
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch empty string (UW-IMAP does this), b) return the same as
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch HEADER. Dovecot has done b) for a long time and it's not
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch very clear which one is correct, so we'll just continue
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch with b) */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_FULL:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_MIME_BODY:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_HEADER:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_HEADER_FIELDS:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_HEADER_FIELDS_NOT:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_BODY:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* fetching message/rfc822 part's header/body */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *part_r = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(part->children != NULL &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part->children->next == NULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part = part->children;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *part_r = part;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_msgpart_open_normal(struct mail *mail, struct imap_msgpart *msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct message_part *part,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_size *part_size_r,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_msgpart_open_result *result_r)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_size hdr_size, body_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct istream *input = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch memset(&hdr_size, 0, sizeof(hdr_size));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch memset(&body_size, 0, sizeof(body_size));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch memset(part_size_r, 0, sizeof(*part_size_r));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (*msgpart->section_number != '\0') {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* find the MIME part */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_stream(mail, NULL, NULL, &input) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_seek(input, part->physical_pos);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch hdr_size = part->header_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch body_size = part->body_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else switch (msgpart->fetch_type) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_FULL:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* fetch the whole message */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_stream(mail, NULL, NULL, &input) < 0 ||
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mail_get_virtual_size(mail, &body_size.virtual_size) < 0 ||
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mail_get_physical_size(mail, &body_size.physical_size) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result_r->size_field = MAIL_FETCH_VIRTUAL_SIZE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_MIME:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_MIME_BODY:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_unreached();
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_HEADER:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_HEADER_FIELDS_NOT:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* fetch the message's header */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_hdr_stream(mail, &hdr_size, &input) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result_r->size_field = MAIL_FETCH_MESSAGE_PARTS;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_HEADER_FIELDS:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* try to lookup the headers from cache */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (msgpart->header_ctx == NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->header_ctx =
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mailbox_header_lookup_init(mail->box,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->headers);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_header_stream(mail, msgpart->header_ctx,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch &input) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result_r->size_field = 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_BODY:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* fetch the message's body */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_stream(mail, &hdr_size, &body_size, &input) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result_r->size_field = MAIL_FETCH_MESSAGE_PARTS;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (msgpart->headers != NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* return specific headers */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return imap_msgpart_get_partial_header(mail, input, msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part_size_r, result_r);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch switch (msgpart->fetch_type) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_FULL:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part_size_r->physical_size += body_size.physical_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part_size_r->virtual_size += body_size.virtual_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* fall through */
4abdade2cb09266ea3d063d5cb6893cb0583f20eTimo Sirainen case FETCH_MIME:
4abdade2cb09266ea3d063d5cb6893cb0583f20eTimo Sirainen case FETCH_HEADER:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part_size_r->physical_size += hdr_size.physical_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part_size_r->virtual_size += hdr_size.virtual_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_HEADER_FIELDS:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_HEADER_FIELDS_NOT:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_unreached();
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_BODY:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case FETCH_MIME_BODY:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_skip(input, hdr_size.physical_size);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part_size_r->physical_size += body_size.physical_size;
6541da94741ea43514cdac3dd2ebbcf839ffb783Stephan Bosch part_size_r->virtual_size += body_size.virtual_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
4abdade2cb09266ea3d063d5cb6893cb0583f20eTimo Sirainen result_r->input = input;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_ref(input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschint imap_msgpart_open(struct mail *mail, struct imap_msgpart *msgpart,
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen struct imap_msgpart_open_result *result_r)
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_part *part;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_size part_size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uoff_t size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bool include_hdr, binary, use_partial_cache;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch memset(result_r, 0, sizeof(*result_r));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((ret = imap_msgpart_find_part(mail, msgpart, &part)) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
2d8ff6cda406da5c53e635fe31dfadc3bdb05235Timo Sirainen if (ret == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* MIME part not found. return an empty part. */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result_r->input = i_stream_create_from_data("", 0);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (msgpart->decode_cte_to_binary &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (msgpart->fetch_type == FETCH_FULL ||
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type == FETCH_BODY ||
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type == FETCH_MIME_BODY)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* binary fetch */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch include_hdr = msgpart->fetch_type == FETCH_FULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (part == NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_parts(mail, &part) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_binary_stream(mail, part, include_hdr, &size,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch &binary, &result_r->input) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part_size.virtual_size = size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part_size.physical_size = size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch use_partial_cache = FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (imap_msgpart_open_normal(mail, msgpart, part, &part_size,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result_r) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch binary = FALSE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch use_partial_cache = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (binary && msgpart->decode_cte_to_binary)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch result_r->binary_decoded_input_has_nuls = TRUE;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_msgpart_get_partial(mail, msgpart, !binary, use_partial_cache,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch &part_size, result_r);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschint imap_msgpart_size(struct mail *mail, struct imap_msgpart *msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch size_t *size_r)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_msgpart_open_result result;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_part *part;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bool include_hdr;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!msgpart->decode_cte_to_binary ||
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (msgpart->fetch_type != FETCH_FULL &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type != FETCH_BODY &&
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch msgpart->fetch_type != FETCH_MIME_BODY)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* generic implementation */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (imap_msgpart_open(mail, msgpart, &result) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_stream_unref(&result.input);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *size_r = result.size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* binary-optimized implementation: */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((ret = imap_msgpart_find_part(mail, msgpart, &part)) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* MIME part not found. return an empty part. */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *size_r = 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (part == NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_parts(mail, &part) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch }
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch include_hdr = msgpart->fetch_type == FETCH_FULL;
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch return mail_get_binary_size(mail, part, include_hdr, size_r);
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_msgpart_parse_bodystructure(struct mail *mail,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_part *all_parts)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct mail_private *pmail = (struct mail_private *)mail;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *bodystructure, *error;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch &bodystructure) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (all_parts->context != NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* we just parsed the bodystructure */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (imap_bodystructure_parse(bodystructure, pmail->data_pool,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch all_parts, &error) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mail_storage_set_critical(mail->box->storage,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch "Invalid message_part/BODYSTRUCTURE %s: %s",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bodystructure, error);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mail_set_cache_corrupted(mail, MAIL_FETCH_MESSAGE_PARTS);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mail_set_cache_corrupted(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
0bb5699d56b7c9f897ee8e627ae4a8ba4fe0c21bTimo Sirainen }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschimap_msgpart_vsizes_to_binary(struct mail *mail, const struct message_part *part,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_part **binpart_r)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_part **pos;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch uoff_t size;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_binary_size(mail, part, FALSE, &size) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *binpart_r = t_new(struct message_part, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch **binpart_r = *part;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (*binpart_r)->body_size.virtual_size = size;
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pos = &(*binpart_r)->children;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch for (part = part->children; part != NULL; part = part->next) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (imap_msgpart_vsizes_to_binary(mail, part, pos) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch pos = &(*pos)->next;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschint imap_msgpart_bodypartstructure(struct mail *mail,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct imap_msgpart *msgpart,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char **bpstruct_r)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct message_part *all_parts, *part;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch string_t *bpstruct;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* if we start parsing the body in here, make sure we also parse the
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch BODYSTRUCTURE */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mail_add_temp_wanted_fields(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE, NULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((ret = imap_msgpart_find_part(mail, msgpart, &part)) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* MIME part not found. */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *bpstruct_r = NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (mail_get_parts(mail, &all_parts) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (all_parts->context == NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (imap_msgpart_parse_bodystructure(mail, all_parts) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (part == NULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch part = all_parts;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch T_BEGIN {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (msgpart->decode_cte_to_binary)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch ret = imap_msgpart_vsizes_to_binary(mail, part, &part);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (ret >= 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch bpstruct = t_str_new(256);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch imap_bodystructure_write(part, bpstruct, TRUE);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *bpstruct_r = str_c(bpstruct);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } T_END;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return ret < 0 ? -1 : 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschvoid imap_msgpart_close_mailbox(struct imap_msgpart *msgpart)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (msgpart->header_ctx != NULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mailbox_header_lookup_unref(&msgpart->header_ctx);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch