message-parser.c revision 7f28ca8d7196de9e46eb2cc1264d46cb52d6b7c5
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
abf015c9682f0f723db87a7c97bc284ef814818fTimo Sirainen/* RFC-2046 requires boundaries are max. 70 chars + "--" prefix + "--" suffix.
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen We'll add a bit more just in case. */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen struct message_header_parser_ctx *hdr_parser_ctx;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen int (*parse_next_block)(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmessage_part_header_callback_t *null_message_part_header_callback = NULL;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainenboundary_find(struct message_boundary *boundaries,
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. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen memcmp(boundaries->boundary, data, boundaries->len) == 0)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic void parse_body_add_block(struct message_parser_ctx *ctx,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen unsigned int missing_cr_count = 0;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen ctx->part->body_size.physical_size += block->size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->part->body_size.virtual_size += block->size + missing_cr_count;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic int message_parser_read_more(struct message_parser_ctx *ctx,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ret = i_stream_read_data(ctx->input, &block_r->data,
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen /* EOF, but we still have some data. return it. */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenmessage_part_append(pool_t pool, struct message_part *parent)
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen /* set child position */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic void parse_next_body_multipart_init(struct message_parser_ctx *ctx)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen b = p_new(ctx->parser_pool, struct message_boundary, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int parse_next_body_message_rfc822_init(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenboundary_line_find(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const unsigned char *data, size_t size, bool full,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* not a boundary, just skip this line */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* need to find the end of line */
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen /* no LF found */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen *boundary_r = boundary_find(ctx->boundaries, data, size);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen memcmp(data + (*boundary_r)->len, "--", 2) == 0;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainenstatic int parse_next_mime_header_init(struct message_parser_ctx *ctx,
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_IS_MIME;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx,
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* found the LF */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* a new MIME part begins */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->parse_next_block = parse_next_mime_header_init;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int parse_part_finish(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct message_block *block_r, bool first_line)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* message ended unexpectedly */
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);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* this boundary isn't needed anymore */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* forget about the boundaries we possibly skipped */
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 +
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* [\n]--<boundary> */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen block_r->size = (first_line ? 0 : 1) + 2 + boundary->len;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->parse_next_block = parse_next_body_skip_boundary_line;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const unsigned char *data;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* handle boundary in first line of message. alternatively
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen it's an empty line. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return parse_part_finish(ctx, boundary, block_r, TRUE);
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. */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen /* we can skip the first lines. input buffer can't be
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen full anymore. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* no linefeeds in this block. we can just skip it. */
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen ret = boundary_line_find(ctx, block_r->data + next_line_idx,
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen /* found / need more data */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen /* the boundary wasn't found from this data block,
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen we'll need more data. */
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen ctx->want_count = (block_r->size - boundary_start) + 1;
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen /* leave CR+LF + last line to buffer */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen parse_part_finish(ctx, boundary, block_r, FALSE);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void parse_content_type(struct message_parser_ctx *ctx,
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (rfc822_parse_content_type(&parser, content_type) < 0)
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 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else if (strncasecmp(str_c(content_type), "multipart/", 10) == 0) {
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (strcasecmp(str_c(content_type)+10, "digest") == 0)
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART_DIGEST;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while (rfc822_parse_content_param(&parser, &key, &value) > 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->last_boundary = p_strdup(ctx->parser_pool, value);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen (MESSAGE_PART_FLAG_MESSAGE_RFC822 | MESSAGE_PART_FLAG_MULTIPART)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int parse_next_header(struct message_parser_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk else if (strcasecmp(hdr->name, "Mime-Version") == 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* it's MIME. Content-* headers are valid */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen } else if (strcasecmp(hdr->name, "Content-Type") == 0) {
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen MESSAGE_PARSER_FLAG_MIME_VERSION_STRICT) == 0)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* end of headers */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* multipart type but no message boundary */
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. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen /* when there's no content-type specified and we're
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen content-type */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen /* otherwise we default to text/plain */
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (message_parse_header_has_nuls(ctx->hdr_parser_ctx))
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen i_assert((part->flags & MUTEX_FLAGS) != MUTEX_FLAGS);
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;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen /* return empty block as end of headers */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen message_parse_header_init(ctx->input, &ctx->part->header_size,
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainenstatic int preparsed_parse_eof(struct message_parser_ctx *ctx ATTR_UNUSED,
97333cbaa7893be8bac7b5741e328ebfff0aeab0Timo Sirainenstatic void preparsed_skip_to_next(struct message_parser_ctx *ctx)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic int preparsed_parse_body_finish(struct message_parser_ctx *ctx,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic int preparsed_parse_body_more(struct message_parser_ctx *ctx,
0992011130e9d0a498ca860ddbe4028398a530c5Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
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 Sirainenstatic int preparsed_parse_body_init(struct message_parser_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* header was actually larger than the cached size suggested */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_skip(ctx->input, offset - ctx->input->v_offset);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen ctx->parse_next_block = preparsed_parse_body_more;
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen return preparsed_parse_body_more(ctx, block_r);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->parse_next_block = preparsed_parse_body_init;
878a83a906e1be6354b563ead096955a22ad5fbeTimo Sirainenstatic int preparsed_parse_next_header(struct message_parser_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->parse_next_block = preparsed_parse_finish_header;
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen /* return empty block as end of headers */
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen if (ctx->input->v_offset != ctx->part->physical_pos +
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen i_assert(ctx->part->physical_pos >= ctx->input->v_offset);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen i_stream_skip(ctx->input, ctx->part->physical_pos -
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen message_parse_header_init(ctx->input, NULL, ctx->hdr_flags);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return preparsed_parse_next_header(ctx, block_r);
9b78c0d5e13141f4df6c6e483f854e5acb861288Timo Sirainenmessage_parser_init(pool_t part_pool, struct istream *input,
8d5c97bf940e43e8ec6e9f1ec8655f3b20edafbeTimo Sirainen pool = pool_alloconly_create("Message Parser", 1024);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen ctx = p_new(pool, struct message_parser_ctx, 1);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ctx->parts = ctx->part = part_pool == NULL ? NULL :
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen ctx->parse_next_block = parse_next_header_init;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenmessage_parser_init_from_parts(struct message_part *parts,
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen ctx = message_parser_init(NULL, input, hdr_flags, flags);
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainenint message_parser_deinit(struct message_parser_ctx **_ctx,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenint message_parser_parse_next_block(struct message_parser_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen while ((ret = ctx->parse_next_block(ctx, block_r)) == 0) {
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);
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen message_size_add(&ctx->part->parent->body_size,
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen message_size_add(&ctx->part->parent->body_size,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid message_parser_parse_header(struct message_parser_ctx *ctx,
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {
8552b0cad8ffe9ccb8270577ba28b8010c89af11Timo Sirainen /* well, can't return error so fake end of headers */
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainenvoid message_parser_parse_body(struct message_parser_ctx *ctx,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {