message-parser.c revision 9042caa1ad49a3b44cf2b63cbcc66b00c27bab4d
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen/* RFC-2046 requires boundaries are max. 70 chars + "--" prefix + "--" suffix.
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen We'll add a bit more just in case. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_header_parser_ctx *hdr_parser_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int (*parse_next_block)(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmessage_part_header_callback_t *null_message_part_header_callback = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenboundary_find(struct message_boundary *boundaries,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* As MIME spec says: search from latest one to oldest one so that we
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen don't break if the same boundary is used in nested parts. Also the
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen full message line doesn't have to match the boundary, only the
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen beginning. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen memcmp(boundaries->boundary, data, boundaries->len) == 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void parse_body_add_block(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int missing_cr_count = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const unsigned char *cur, *next, *data = block->data;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* check if we have NULs */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* count number of lines and missing CRs */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen while ((next = memchr(cur, '\n', block->size - (cur - data))) != NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->part->body_size.physical_size += block->size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->part->body_size.virtual_size += block->size + missing_cr_count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int message_parser_read_more(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = i_stream_read_data(ctx->input, &block_r->data,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* EOF, but we still have some data.
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return it. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmessage_part_append(pool_t pool, struct message_part *parent)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* set child position */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void parse_next_body_multipart_init(struct message_parser_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen b = p_new(ctx->parser_pool, struct message_boundary, 1);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainenstatic int parse_next_body_message_rfc822_init(struct message_parser_ctx *ctx,
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainenboundary_line_find(struct message_parser_ctx *ctx,
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen const unsigned char *data, size_t size, bool full,
9c7e765845357342923e16351181091028e5930fTimo Sirainen /* not a boundary, just skip this line */
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen /* need to find the end of line */
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen if (memchr(data + 2, '\n', size - 2) == NULL &&
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen /* no LF found */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen *boundary_r = boundary_find(ctx->boundaries, data, size);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen memcmp(data + (*boundary_r)->len, "--", 2) == 0;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainenstatic int parse_next_mime_header_init(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_IS_MIME;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned char *ptr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
0b3662995e9fa0d0d857ec5350ce2b1ee6d3b94fTimo Sirainen ptr = memchr(block_r->data, '\n', block_r->size);
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen /* found the LF */
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen /* a new MIME part begins */
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->parse_next_block = parse_next_mime_header_init;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenstatic int parse_part_finish(struct message_parser_ctx *ctx,
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen struct message_block *block_r, bool first_line)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen /* get back to parent MIME part, summing the child MIME part sizes
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen into parent's body sizes */
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen for (part = ctx->part; part != boundary->part; part = part->parent) {
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen message_size_add(&part->parent->body_size, &part->body_size);
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen message_size_add(&part->parent->body_size, &part->header_size);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen /* this boundary isn't needed anymore */
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen /* forget about the boundaries we possibly skipped */
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen /* the boundary itself should already be in buffer. add that. */
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen block_r->data = i_stream_get_data(ctx->input, &block_r->size);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen i_assert(block_r->size >= ctx->skip + 2 + boundary->len +
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen /* [\n]--<boundary> */
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen block_r->size = (first_line ? 0 : 1) + 2 + boundary->len;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen ctx->parse_next_block = parse_next_body_skip_boundary_line;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
c93cd163f9c1d4b0ca29f49cbfdbf474caeef5bfTimo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* handle boundary in first line of message. alternatively
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen it's an empty line. */
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen return ret == 0 ? 0 :
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen parse_part_finish(ctx, boundary, block_r, TRUE);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen /* skip to beginning of the next line. the first line was
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen handled already. */
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen while ((next = memchr(cur, '\n', end - cur)) != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we can at least skip data until the first [CR]LF.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen input buffer can't be full anymore. */
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen ret = boundary_line_find(ctx, cur, end - cur, full, &boundary);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* found / need more data */
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen /* found / need more data */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen } else if (boundary_start == 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* no linefeeds in this block. we can just skip it. */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* the boundary wasn't found from this data block,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen we'll need more data. */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->want_count = (block_r->size - boundary_start) + 1;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* a) we found the boundary
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen b) we need more data and haven't reached EOF yet
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so leave CR+LF + last line to buffer */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen parse_part_finish(ctx, boundary, block_r, FALSE);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainenstatic void parse_content_type(struct message_parser_ctx *ctx,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen const char *const *results;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen if (rfc822_parse_content_type(&parser, content_type) < 0)
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen if (strcasecmp(str_c(content_type), "message/rfc822") == 0)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen else if (strncasecmp(str_c(content_type), "text", 4) == 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strncasecmp(str_c(content_type), "multipart/", 10) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcasecmp(str_c(content_type)+10, "digest") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART_DIGEST;
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if (strcasecmp(results[0], "boundary") == 0) {
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen (MESSAGE_PART_FLAG_MESSAGE_RFC822 | MESSAGE_PART_FLAG_MULTIPART)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int parse_next_header(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcasecmp(hdr->name, "Mime-Version") == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* it's MIME. Content-* headers are valid */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (strcasecmp(hdr->name, "Content-Type") == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MESSAGE_PARSER_FLAG_MIME_VERSION_STRICT) == 0)
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen /* end of headers */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* multipart type but no message boundary */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* It's not MIME. Reset everything we found from
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen Content-Type. */
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen (part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* when there's no content-type specified and we're
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen content-type */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen /* otherwise we default to text/plain */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (message_parse_header_has_nuls(ctx->hdr_parser_ctx))
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_assert((part->flags & MUTEX_FLAGS) != MUTEX_FLAGS);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen } else if (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->parse_next_block = parse_next_body_message_rfc822_init;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
ff4bb2dfb5714eeb0408d3bb862de1646351d097Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* return empty block as end of headers */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen message_parse_header_init(ctx->input, &ctx->part->header_size,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int preparsed_parse_eof(struct message_parser_ctx *ctx ATTR_UNUSED,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic void preparsed_skip_to_next(struct message_parser_ctx *ctx)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int preparsed_parse_body_finish(struct message_parser_ctx *ctx,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int preparsed_parse_body_more(struct message_parser_ctx *ctx,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (ctx->input->v_offset + block_r->size >= end_offset) {
60f9b96be55e63f0113e273dda8ba3b883c6f095Timo Sirainen block_r->size = end_offset - ctx->input->v_offset;
60f9b96be55e63f0113e273dda8ba3b883c6f095Timo Sirainen ctx->parse_next_block = preparsed_parse_body_finish;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int preparsed_parse_body_init(struct message_parser_ctx *ctx,
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen /* header was actually larger than the cached size suggested */
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen i_stream_skip(ctx->input, offset - ctx->input->v_offset);
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->parse_next_block = preparsed_parse_body_more;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen return preparsed_parse_body_more(ctx, block_r);
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainenstatic int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen ctx->parse_next_block = preparsed_parse_body_init;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainenstatic int preparsed_parse_next_header(struct message_parser_ctx *ctx,
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen ctx->parse_next_block = preparsed_parse_finish_header;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen /* return empty block as end of headers */
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen if (ctx->input->v_offset != ctx->part->physical_pos +
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen i_assert(ctx->part->physical_pos >= ctx->input->v_offset);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen i_stream_skip(ctx->input, ctx->part->physical_pos -
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen message_parse_header_init(ctx->input, NULL, ctx->hdr_flags);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return preparsed_parse_next_header(ctx, block_r);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenmessage_parser_init(pool_t part_pool, struct istream *input,
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen pool = pool_alloconly_create("Message Parser", 1024);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx = p_new(pool, struct message_parser_ctx, 1);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parts = ctx->part = part_pool == NULL ? NULL :
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parse_next_block = parse_next_header_init;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenmessage_parser_init_from_parts(struct message_part *parts,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx = message_parser_init(NULL, input, hdr_flags, flags);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
9c7e765845357342923e16351181091028e5930fTimo Sirainenint message_parser_deinit(struct message_parser_ctx **_ctx,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenint message_parser_parse_next_block(struct message_parser_ctx *ctx,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen while ((ret = ctx->parse_next_block(ctx, block_r)) == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ret = message_parser_read_more(ctx, block_r, &full);
0b3662995e9fa0d0d857ec5350ce2b1ee6d3b94fTimo Sirainen /* Successful EOF or unexpected failure */
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen i_assert(ctx->input->eof || ctx->input->closed ||
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen ctx->input->stream_errno != 0 || ctx->broken);
65d6ca3fb5450b81df0190d9e9aa62c00fed5116Timo Sirainen message_size_add(&ctx->part->parent->body_size,
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainen message_size_add(&ctx->part->parent->body_size,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid message_parser_parse_header(struct message_parser_ctx *ctx,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen /* well, can't return error so fake end of headers */
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainenvoid message_parser_parse_body(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {