message-parser.c revision 7f28ca8d7196de9e46eb2cc1264d46cb52d6b7c5
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#include "str.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "istream.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "rfc822-parser.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "message-parser.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
abf015c9682f0f723db87a7c97bc284ef814818fTimo Sirainen/* RFC-2046 requires boundaries are max. 70 chars + "--" prefix + "--" suffix.
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen We'll add a bit more just in case. */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#define BOUNDARY_END_MAX_LEN (70 + 2 + 2 + 10)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenstruct message_boundary {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_boundary *next;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_part *part;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *boundary;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen size_t len;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int epilogue_found:1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen};
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct message_parser_ctx {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen pool_t parser_pool, part_pool;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream *input;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_part *parts, *part;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen enum message_header_parser_flags hdr_flags;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen enum message_parser_flags flags;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen const char *last_boundary;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen struct message_boundary *boundaries;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen size_t skip;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen char last_chr;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen unsigned int want_count;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen struct message_header_parser_ctx *hdr_parser_ctx;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen int (*parse_next_block)(struct message_parser_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct message_block *block_r);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int part_seen_content_type:1;
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen unsigned int broken:1;
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen};
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmessage_part_header_callback_t *null_message_part_header_callback = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct message_block *block_r);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct message_block *block_r);
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_block *block_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct message_block *block_r);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenstatic struct message_boundary *
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainenboundary_find(struct message_boundary *boundaries,
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen const unsigned char *data, size_t len)
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen{
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen /* As MIME spec says: search from latest one to oldest one so that we
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen don't break if the same boundary is used in nested parts. Also the
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen full message line doesn't have to match the boundary, only the
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen beginning. */
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen while (boundaries != NULL) {
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen if (boundaries->len <= len &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen memcmp(boundaries->boundary, data, boundaries->len) == 0)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return boundaries;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen boundaries = boundaries->next;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return NULL;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic void parse_body_add_block(struct message_parser_ctx *ctx,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct message_block *block)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen unsigned int missing_cr_count = 0;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen const unsigned char *data = block->data;
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainen size_t i;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen block->hdr = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < block->size; i++) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (data[i] <= '\n') {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (data[i] == '\n') {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ctx->part->body_size.lines++;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if ((i > 0 && data[i-1] != '\r') ||
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen (i == 0 && ctx->last_chr != '\r'))
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen missing_cr_count++;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen } else if (data[i] == '\0')
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen ctx->part->body_size.physical_size += block->size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->part->body_size.virtual_size += block->size + missing_cr_count;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->last_chr = data[i-1];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->skip += block->size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic int message_parser_read_more(struct message_parser_ctx *ctx,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct message_block *block_r)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen int ret;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen if (ctx->skip > 0) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ctx->skip = 0;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ret = i_stream_read_data(ctx->input, &block_r->data,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen &block_r->size, ctx->want_count);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen if (ret <= 0) {
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen if (ret == -1 && block_r->size != 0) {
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen /* EOF, but we still have some data. return it. */
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen return 1;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen }
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen if (ret < 0)
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen return ret;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (!ctx->input->eof) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_assert(!ctx->input->blocking);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return 0;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ctx->want_count = 1;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return 1;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic struct message_part *
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenmessage_part_append(pool_t pool, struct message_part *parent)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct message_part *part, **list;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen part = p_new(pool, struct message_part, 1);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen part->parent = parent;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen /* set child position */
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen part->physical_pos =
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen parent->physical_pos +
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen parent->body_size.physical_size +
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen parent->header_size.physical_size;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen list = &part->parent->children;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen while (*list != NULL)
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen list = &(*list)->next;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen *list = part;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen return part;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic void parse_next_body_multipart_init(struct message_parser_ctx *ctx)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct message_boundary *b;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen b = p_new(ctx->parser_pool, struct message_boundary, 1);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen b->part = ctx->part;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen b->boundary = ctx->last_boundary;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen b->len = strlen(b->boundary);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen b->next = ctx->boundaries;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->boundaries = b;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->last_boundary = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int parse_next_body_message_rfc822_init(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_block *block_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return parse_next_header_init(ctx, block_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenboundary_line_find(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const unsigned char *data, size_t size, bool full,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_boundary **boundary_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t i;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *boundary_r = NULL;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (size < 2) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(!full);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ctx->input->eof)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return -1;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen ctx->want_count = 2;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (data[0] != '-' || data[1] != '-') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* not a boundary, just skip this line */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* need to find the end of line */
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen for (i = 2; i < size; i++) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (data[i] == '\n')
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen }
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen if (i == size && i < BOUNDARY_END_MAX_LEN &&
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen !ctx->input->eof && !full) {
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen /* no LF found */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->want_count = BOUNDARY_END_MAX_LEN;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return 0;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen }
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen data += 2;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen size -= 2;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen *boundary_r = boundary_find(ctx->boundaries, data, size);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (*boundary_r == NULL)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return -1;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen (*boundary_r)->epilogue_found =
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size >= (*boundary_r)->len + 2 &&
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen memcmp(data + (*boundary_r)->len, "--", 2) == 0;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainenstatic int parse_next_mime_header_init(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_block *block_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_IS_MIME;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return parse_next_header_init(ctx, block_r);
d7ec773d995888b09c4d8c88a4b0b134a2002361Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct message_block *block_r)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen size_t i;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen int ret;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen return ret;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen for (i = 0; i < block_r->size; i++) {
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if (block_r->data[i] == '\n')
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen break;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen if (i == block_r->size) {
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen parse_body_add_block(ctx, block_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* found the LF */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen block_r->size = i + 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen parse_body_add_block(ctx, block_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* a new MIME part begins */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->parse_next_block = parse_next_mime_header_init;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return 1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int parse_part_finish(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_boundary *boundary,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_block *block_r, bool first_line)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct message_part *part;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (boundary == NULL) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* message ended unexpectedly */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return -1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* get back to parent MIME part, summing the child MIME part sizes
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen into parent's body sizes */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen for (part = ctx->part; part != boundary->part; part = part->parent) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen message_size_add(&part->parent->body_size, &part->body_size);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen message_size_add(&part->parent->body_size, &part->header_size);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ctx->part = part;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (boundary->epilogue_found) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* this boundary isn't needed anymore */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ctx->boundaries = boundary->next;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (ctx->boundaries != NULL)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen else
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen return ctx->parse_next_block(ctx, block_r);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* forget about the boundaries we possibly skipped */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->boundaries = boundary;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* the boundary itself should already be in buffer. add that. */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen block_r->data = i_stream_get_data(ctx->input, &block_r->size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(block_r->size >= ctx->skip + 2 + boundary->len +
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen (first_line ? 0 : 1));
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen block_r->data += ctx->skip;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* [\n]--<boundary> */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen block_r->size = (first_line ? 0 : 1) + 2 + boundary->len;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen parse_body_add_block(ctx, block_r);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->parse_next_block = parse_next_body_skip_boundary_line;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return 1;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen struct message_block *block_r)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen struct message_boundary *boundary = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const unsigned char *data;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t i, boundary_start;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen int ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bool eof, full;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen return ret;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen eof = ret == -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen full = ret == -2;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen data = block_r->data;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (ctx->last_chr == '\n') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* handle boundary in first line of message. alternatively
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen it's an empty line. */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen ret = boundary_line_find(ctx, block_r->data,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen block_r->size, full, &boundary);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (ret >= 0) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (ret == 0)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return 0;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return parse_part_finish(ctx, boundary, block_r, TRUE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen }
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen for (i = boundary_start = 0; i < block_r->size; i++) {
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen /* skip to beginning of the next line. the first line was
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen handled already. */
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen size_t next_line_idx = block_r->size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (; i < block_r->size; i++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (data[i] == '\n') {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen boundary_start = i;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (i > 0 && data[i-1] == '\r')
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen boundary_start--;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen next_line_idx = i + 1;
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (boundary_start != 0) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen /* we can skip the first lines. input buffer can't be
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen full anymore. */
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen full = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else if (next_line_idx == block_r->size) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* no linefeeds in this block. we can just skip it. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen boundary_start = block_r->size;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen full = FALSE;
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen }
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen ret = boundary_line_find(ctx, block_r->data + next_line_idx,
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen block_r->size - next_line_idx, full,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen &boundary);
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen if (ret >= 0) {
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen /* found / need more data */
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen if (ret == 0 && boundary_start == 0)
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen ctx->want_count += next_line_idx;
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (i >= block_r->size) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen /* the boundary wasn't found from this data block,
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen we'll need more data. */
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen if (eof)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = 0;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen ctx->want_count = (block_r->size - boundary_start) + 1;
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen }
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen }
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen i_assert(!(ret == 0 && full));
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ret >= 0) {
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen /* leave CR+LF + last line to buffer */
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen block_r->size = boundary_start;
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen }
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen if (block_r->size != 0) {
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen parse_body_add_block(ctx, block_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return ret <= 0 ? ret :
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen parse_part_finish(ctx, boundary, block_r, FALSE);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen struct message_block *block_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen int ret;
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen return ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen parse_body_add_block(ctx, block_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
b00c511e4675c4a1270d92924fc445cfb8631cf3Timo Sirainen}
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void parse_content_type(struct message_parser_ctx *ctx,
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen struct message_header_line *hdr)
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen{
b00c511e4675c4a1270d92924fc445cfb8631cf3Timo Sirainen struct rfc822_parser_context parser;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen const char *key, *value;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen string_t *content_type;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (ctx->part_seen_content_type)
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen return;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen ctx->part_seen_content_type = TRUE;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen (void)rfc822_skip_lwsp(&parser);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen content_type = t_str_new(64);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (rfc822_parse_content_type(&parser, content_type) < 0)
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen return;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (strcasecmp(str_c(content_type), "message/rfc822") == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen else if (strncasecmp(str_c(content_type), "text", 4) == 0 &&
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen (str_len(content_type) == 4 ||
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen str_data(content_type)[4] == '/'))
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_TEXT;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else if (strncasecmp(str_c(content_type), "multipart/", 10) == 0) {
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (strcasecmp(str_c(content_type)+10, "digest") == 0)
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART_DIGEST;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen }
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen ctx->last_boundary != NULL)
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while (rfc822_parse_content_param(&parser, &key, &value) > 0) {
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (strcasecmp(key, "boundary") == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->last_boundary = p_strdup(ctx->parser_pool, value);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen break;
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen }
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen }
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen}
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen#define MUTEX_FLAGS \
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen (MESSAGE_PART_FLAG_MESSAGE_RFC822 | MESSAGE_PART_FLAG_MULTIPART)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int parse_next_header(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_block *block_r)
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_part *part = ctx->part;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_header_line *hdr;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t size;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen int ret;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (ctx->skip > 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->skip = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen (void)i_stream_get_data(ctx->input, &size);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ctx->want_count = size + 1;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return ret;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (hdr != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (hdr->eoh)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen ;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk else if (strcasecmp(hdr->name, "Mime-Version") == 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* it's MIME. Content-* headers are valid */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen part->flags |= MESSAGE_PART_FLAG_IS_MIME;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen } else if (strcasecmp(hdr->name, "Content-Type") == 0) {
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen if ((ctx->flags &
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen MESSAGE_PARSER_FLAG_MIME_VERSION_STRICT) == 0)
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen part->flags |= MESSAGE_PART_FLAG_IS_MIME;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (hdr->continues)
02a6291366caff79793db35d479e2a062bec2af4Timo Sirainen hdr->use_full_value = TRUE;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen else T_BEGIN {
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen parse_content_type(ctx, hdr);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen } T_END;
573085b4b25b0bbae8d27969df2c91702eefa23eTimo Sirainen }
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen block_r->hdr = hdr;
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen block_r->size = 0;
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* end of headers */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->last_boundary == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* multipart type but no message boundary */
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen part->flags = 0;
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen }
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen if ((part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen /* It's not MIME. Reset everything we found from
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen Content-Type. */
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen part->flags = 0;
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen ctx->last_boundary = NULL;
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen }
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!ctx->part_seen_content_type ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (part->parent != NULL &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (part->parent->flags &
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MESSAGE_PART_FLAG_MULTIPART_DIGEST) != 0) {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen /* when there's no content-type specified and we're
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen below multipart/digest, assume message/rfc822
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen content-type */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen } else {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen /* otherwise we default to text/plain */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen part->flags |= MESSAGE_PART_FLAG_TEXT;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen }
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen }
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (message_parse_header_has_nuls(ctx->hdr_parser_ctx))
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen i_assert((part->flags & MUTEX_FLAGS) != MUTEX_FLAGS);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen ctx->last_chr = '\n';
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (ctx->last_boundary != NULL) {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen parse_next_body_multipart_init(ctx);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen } else if (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen ctx->parse_next_block = parse_next_body_message_rfc822_init;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen else if (ctx->boundaries != NULL)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen else
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen ctx->want_count = 1;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen /* return empty block as end of headers */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen block_r->hdr = NULL;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen block_r->size = 0;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen return 1;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen}
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen struct message_block *block_r)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen i_assert(ctx->hdr_parser_ctx == NULL);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen ctx->hdr_parser_ctx =
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen message_parse_header_init(ctx->input, &ctx->part->header_size,
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen ctx->hdr_flags);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen ctx->part_seen_content_type = FALSE;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen ctx->parse_next_block = parse_next_header;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen return parse_next_header(ctx, block_r);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen}
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainenstatic int preparsed_parse_eof(struct message_parser_ctx *ctx ATTR_UNUSED,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct message_block *block_r ATTR_UNUSED)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen{
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen return -1;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen}
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
97333cbaa7893be8bac7b5741e328ebfff0aeab0Timo Sirainenstatic void preparsed_skip_to_next(struct message_parser_ctx *ctx)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen{
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen while (ctx->part != NULL) {
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen if (ctx->part->next != NULL) {
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen ctx->part = ctx->part->next;
97333cbaa7893be8bac7b5741e328ebfff0aeab0Timo Sirainen break;
97333cbaa7893be8bac7b5741e328ebfff0aeab0Timo Sirainen }
97333cbaa7893be8bac7b5741e328ebfff0aeab0Timo Sirainen ctx->part = ctx->part->parent;
97333cbaa7893be8bac7b5741e328ebfff0aeab0Timo Sirainen }
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (ctx->part == NULL)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen ctx->parse_next_block = preparsed_parse_eof;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic int preparsed_parse_body_finish(struct message_parser_ctx *ctx,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen struct message_block *block_r)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen i_stream_skip(ctx->input, ctx->skip);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen ctx->skip = 0;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen preparsed_skip_to_next(ctx);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return ctx->parse_next_block(ctx, block_r);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic int preparsed_parse_body_more(struct message_parser_ctx *ctx,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen struct message_block *block_r)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen uoff_t end_offset = ctx->part->physical_pos +
0992011130e9d0a498ca860ddbe4028398a530c5Timo Sirainen ctx->part->header_size.physical_size +
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen ctx->part->body_size.physical_size;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen int ret;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
0992011130e9d0a498ca860ddbe4028398a530c5Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return ret;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (ctx->input->v_offset + block_r->size >= end_offset) {
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen block_r->size = end_offset - ctx->input->v_offset;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen ctx->parse_next_block = preparsed_parse_body_finish;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen }
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen ctx->skip = block_r->size;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return 1;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic int preparsed_parse_body_init(struct message_parser_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct message_block *block_r)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen uoff_t offset = ctx->part->physical_pos +
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->part->header_size.physical_size;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (offset < ctx->input->v_offset) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* header was actually larger than the cached size suggested */
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen ctx->broken = TRUE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_skip(ctx->input, offset - ctx->input->v_offset);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen ctx->parse_next_block = preparsed_parse_body_more;
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen return preparsed_parse_body_more(ctx, block_r);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen struct message_block *block_r)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen{
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if (ctx->part->children != NULL) {
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->part = ctx->part->children;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->parse_next_block = preparsed_parse_body_init;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen } else {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen preparsed_skip_to_next(ctx);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return ctx->parse_next_block(ctx, block_r);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
878a83a906e1be6354b563ead096955a22ad5fbeTimo Sirainen
878a83a906e1be6354b563ead096955a22ad5fbeTimo Sirainenstatic int preparsed_parse_next_header(struct message_parser_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct message_block *block_r)
b879ed8dd4b5850987e6b89a92f794d87c6be7d7Timo Sirainen{
b879ed8dd4b5850987e6b89a92f794d87c6be7d7Timo Sirainen struct message_header_line *hdr;
b879ed8dd4b5850987e6b89a92f794d87c6be7d7Timo Sirainen size_t size;
b879ed8dd4b5850987e6b89a92f794d87c6be7d7Timo Sirainen int ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
705f6fbad395e6f014838e797b7dbcaceafd2f1dTimo Sirainen (void)i_stream_get_data(ctx->input, &size);
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen ctx->want_count = size + 1;
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen return ret;
97333cbaa7893be8bac7b5741e328ebfff0aeab0Timo Sirainen }
97333cbaa7893be8bac7b5741e328ebfff0aeab0Timo Sirainen
97333cbaa7893be8bac7b5741e328ebfff0aeab0Timo Sirainen if (hdr != NULL) {
97333cbaa7893be8bac7b5741e328ebfff0aeab0Timo Sirainen block_r->hdr = hdr;
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen block_r->size = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->parse_next_block = preparsed_parse_finish_header;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen /* return empty block as end of headers */
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen block_r->hdr = NULL;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen block_r->size = 0;
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen i_assert(ctx->skip == 0);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen if (ctx->input->v_offset != ctx->part->physical_pos +
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen ctx->part->header_size.physical_size)
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen ctx->broken = TRUE;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen return 1;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen}
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen struct message_block *block_r)
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen{
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen i_assert(ctx->hdr_parser_ctx == NULL);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen i_assert(ctx->part->physical_pos >= ctx->input->v_offset);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen i_stream_skip(ctx->input, ctx->part->physical_pos -
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen ctx->input->v_offset);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ctx->hdr_parser_ctx =
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen message_parse_header_init(ctx->input, NULL, ctx->hdr_flags);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return preparsed_parse_next_header(ctx, block_r);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstruct message_parser_ctx *
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainenmessage_parser_init(pool_t part_pool, struct istream *input,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen enum message_header_parser_flags hdr_flags,
dbe06905918a415a34c5621b9fdf45be0b9c8e64Timo Sirainen enum message_parser_flags flags)
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen struct message_parser_ctx *ctx;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen pool_t pool;
8d5c97bf940e43e8ec6e9f1ec8655f3b20edafbeTimo Sirainen
8d5c97bf940e43e8ec6e9f1ec8655f3b20edafbeTimo Sirainen pool = pool_alloconly_create("Message Parser", 1024);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen ctx = p_new(pool, struct message_parser_ctx, 1);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->parser_pool = pool;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->part_pool = part_pool;
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen ctx->hdr_flags = hdr_flags;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ctx->flags = flags;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ctx->input = input;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ctx->parts = ctx->part = part_pool == NULL ? NULL :
762e17079d29d9f1838114ff5fec9ceaba8eb6a8Timo Sirainen p_new(part_pool, struct message_part, 1);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen ctx->parse_next_block = parse_next_header_init;
50349cd047ca9e7c100cbeb70acfe26672649959Timo Sirainen i_stream_ref(input);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen return ctx;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstruct message_parser_ctx *
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenmessage_parser_init_from_parts(struct message_part *parts,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct istream *input,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen enum message_header_parser_flags hdr_flags,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen enum message_parser_flags flags)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct message_parser_ctx *ctx;
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen ctx = message_parser_init(NULL, input, hdr_flags, flags);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen ctx->parts = ctx->part = parts;
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainen return ctx;
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainen}
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainen
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainenint message_parser_deinit(struct message_parser_ctx **_ctx,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct message_part **parts_r)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen{
dbe06905918a415a34c5621b9fdf45be0b9c8e64Timo Sirainen struct message_parser_ctx *ctx = *_ctx;
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen int ret = ctx->broken ? -1 : 0;
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen *_ctx = NULL;
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen *parts_r = ctx->parts;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (ctx->hdr_parser_ctx != NULL)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen i_stream_unref(&ctx->input);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen pool_unref(&ctx->parser_pool);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return ret;
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen}
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenint message_parser_parse_next_block(struct message_parser_ctx *ctx,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct message_block *block_r)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen{
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen int ret;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen bool eof = FALSE;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen while ((ret = ctx->parse_next_block(ctx, block_r)) == 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ret = message_parser_read_more(ctx, block_r);
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen if (ret == 0) {
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen i_assert(!ctx->input->blocking);
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen return 0;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen }
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainen if (ret == -1) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_assert(!eof);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen eof = TRUE;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen block_r->part = ctx->part;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (ret < 0 && ctx->part != NULL) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* Successful EOF or unexpected failure */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_assert(ctx->input->eof || ctx->input->closed ||
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->input->stream_errno != 0 || ctx->broken);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while (ctx->part->parent != NULL) {
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen message_size_add(&ctx->part->parent->body_size,
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen &ctx->part->body_size);
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen message_size_add(&ctx->part->parent->body_size,
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen &ctx->part->header_size);
72f2a851238e5661695c63bff0e9a9e800ba577aTimo Sirainen ctx->part = ctx->part->parent;
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen }
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen }
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen return ret;
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen#undef message_parser_parse_header
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid message_parser_parse_header(struct message_parser_ctx *ctx,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen struct message_size *hdr_size,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen message_part_header_callback_t *callback,
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen void *context)
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen{
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen struct message_block block;
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen int ret;
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen callback(block.part, block.hdr, context);
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen if (block.hdr == NULL)
705f6fbad395e6f014838e797b7dbcaceafd2f1dTimo Sirainen break;
b7835adbfddd8c92b51d6653fb759f963302fa78Timo Sirainen }
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen i_assert(ret != 0);
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen if (ret < 0) {
8552b0cad8ffe9ccb8270577ba28b8010c89af11Timo Sirainen /* well, can't return error so fake end of headers */
98c3aa2587ad3e81e1548a3a4f79b2a24566cec3Timo Sirainen callback(ctx->part, NULL, context);
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen }
72f2a851238e5661695c63bff0e9a9e800ba577aTimo Sirainen
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen *hdr_size = ctx->part->header_size;
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen}
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen#undef message_parser_parse_body
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainenvoid message_parser_parse_body(struct message_parser_ctx *ctx,
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen message_part_header_callback_t *hdr_callback,
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen void *context)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct message_block block;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen int ret;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen if (block.size == 0 && hdr_callback != NULL)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen hdr_callback(block.part, block.hdr, context);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_assert(ret != 0);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen