message-parser.c revision 9042caa1ad49a3b44cf2b63cbcc66b00c27bab4d
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "str.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "rfc822-parser.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "rfc2231-parser.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "message-parser.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
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#define BOUNDARY_END_MAX_LEN (70 + 2 + 2 + 10)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct message_boundary {
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen struct message_boundary *next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_part *part;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *boundary;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t len;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int epilogue_found:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct message_parser_ctx {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen pool_t parser_pool, part_pool;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct istream *input;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_part *parts, *part;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen enum message_header_parser_flags hdr_flags;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen enum message_parser_flags flags;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *last_boundary;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_boundary *boundaries;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t skip;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen char last_chr;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int want_count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_header_parser_ctx *hdr_parser_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int (*parse_next_block)(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_block *block_r);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int part_seen_content_type:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int broken:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int eof:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmessage_part_header_callback_t *null_message_part_header_callback = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_block *block_r);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_block *block_r);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_block *block_r);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_block *block_r);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct message_boundary *
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenboundary_find(struct message_boundary *boundaries,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const unsigned char *data, size_t len)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
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 while (boundaries != NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (boundaries->len <= len &&
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen memcmp(boundaries->boundary, data, boundaries->len) == 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return boundaries;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen boundaries = boundaries->next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void parse_body_add_block(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_block *block)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int missing_cr_count = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const unsigned char *cur, *next, *data = block->data;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(block->size > 0);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen block->hdr = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* check if we have NULs */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (memchr(data, '\0', block->size) != NULL)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* count number of lines and missing CRs */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (*data == '\n') {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->part->body_size.lines++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx->last_chr != '\r')
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen missing_cr_count++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen cur = data + 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen while ((next = memchr(cur, '\n', block->size - (cur - data))) != NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->part->body_size.lines++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (next[-1] != '\r')
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen missing_cr_count++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen cur = next + 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->last_chr = data[block->size - 1];
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->skip += block->size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->part->body_size.physical_size += block->size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->part->body_size.virtual_size += block->size + missing_cr_count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int message_parser_read_more(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_block *block_r, bool *full_r)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx->skip > 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_skip(ctx->input, ctx->skip);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->skip = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *full_r = FALSE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = i_stream_read_data(ctx->input, &block_r->data,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen &block_r->size, ctx->want_count);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret <= 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen switch (ret) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen case 0:
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (!ctx->input->eof) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(!ctx->input->blocking);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen break;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen case -1:
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(ctx->input->eof ||
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->input->stream_errno != 0);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->eof = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (block_r->size != 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* EOF, but we still have some data.
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return it. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen case -2:
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *full_r = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen break;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen default:
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_unreached();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->want_count = 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct message_part *
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmessage_part_append(pool_t pool, struct message_part *parent)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_part *part, **list;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen part = p_new(pool, struct message_part, 1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen part->parent = parent;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* set child position */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen part->physical_pos =
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen parent->physical_pos +
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen parent->body_size.physical_size +
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen parent->header_size.physical_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list = &part->parent->children;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (*list != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list = &(*list)->next;
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *list = part;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return part;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void parse_next_body_multipart_init(struct message_parser_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen struct message_boundary *b;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen b = p_new(ctx->parser_pool, struct message_boundary, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen b->part = ctx->part;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen b->boundary = ctx->last_boundary;
2abfef71398a61e5ed97c23a1ceb71461933ccb8Timo Sirainen b->len = strlen(b->boundary);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen b->next = ctx->boundaries;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->boundaries = b;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->last_boundary = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainenstatic int parse_next_body_message_rfc822_init(struct message_parser_ctx *ctx,
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen struct message_block *block_r)
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen{
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen return parse_next_header_init(ctx, block_r);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen}
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainenstatic int
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainenboundary_line_find(struct message_parser_ctx *ctx,
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen const unsigned char *data, size_t size, bool full,
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen struct message_boundary **boundary_r)
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen{
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen *boundary_r = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (size < 2) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(!full);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->input->eof)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return -1;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->want_count = 2;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return 0;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[0] != '-' || data[1] != '-') {
9c7e765845357342923e16351181091028e5930fTimo Sirainen /* not a boundary, just skip this line */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return -1;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen /* need to find the end of line */
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen if (memchr(data + 2, '\n', size - 2) == NULL &&
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen size < BOUNDARY_END_MAX_LEN &&
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen !ctx->input->eof && !full) {
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen /* no LF found */
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen ctx->want_count = BOUNDARY_END_MAX_LEN;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return 0;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen data += 2;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen size -= 2;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen *boundary_r = boundary_find(ctx->boundaries, data, size);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (*boundary_r == NULL)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return -1;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen (*boundary_r)->epilogue_found =
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen size >= (*boundary_r)->len + 2 &&
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen memcmp(data + (*boundary_r)->len, "--", 2) == 0;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return 1;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen}
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainenstatic int parse_next_mime_header_init(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_block *block_r)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_IS_MIME;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return parse_next_header_init(ctx, block_r);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen}
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx,
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen struct message_block *block_r)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned char *ptr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool full;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen
0b3662995e9fa0d0d857ec5350ce2b1ee6d3b94fTimo Sirainen ptr = memchr(block_r->data, '\n', block_r->size);
0b3662995e9fa0d0d857ec5350ce2b1ee6d3b94fTimo Sirainen if (ptr == NULL) {
0b3662995e9fa0d0d857ec5350ce2b1ee6d3b94fTimo Sirainen parse_body_add_block(ctx, block_r);
0b3662995e9fa0d0d857ec5350ce2b1ee6d3b94fTimo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen /* found the LF */
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen block_r->size = (ptr - block_r->data) + 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parse_body_add_block(ctx, block_r);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen /* a new MIME part begins */
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->parse_next_block = parse_next_mime_header_init;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenstatic int parse_part_finish(struct message_parser_ctx *ctx,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct message_boundary *boundary,
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen struct message_block *block_r, bool first_line)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_part *part;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
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);
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen }
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen ctx->part = part;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (boundary->epilogue_found) {
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen /* this boundary isn't needed anymore */
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen ctx->boundaries = boundary->next;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (ctx->boundaries != NULL)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen else
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen return ctx->parse_next_block(ctx, block_r);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen }
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen /* forget about the boundaries we possibly skipped */
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen ctx->boundaries = boundary;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
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 (first_line ? 0 : 1));
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen block_r->data += ctx->skip;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen /* [\n]--<boundary> */
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen block_r->size = (first_line ? 0 : 1) + 2 + boundary->len;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen parse_body_add_block(ctx, block_r);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen ctx->parse_next_block = parse_next_body_skip_boundary_line;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen return 1;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen}
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen struct message_block *block_r)
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen{
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct message_boundary *boundary = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned char *data, *cur, *next, *end;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen size_t boundary_start;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen int ret;
a87e5f15283e057c7dc26dd9db7b616268c95ca7Timo Sirainen bool full;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
c93cd163f9c1d4b0ca29f49cbfdbf474caeef5bfTimo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = block_r->data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->last_chr == '\n') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* handle boundary in first line of message. alternatively
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen it's an empty line. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = boundary_line_find(ctx, block_r->data,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen block_r->size, full, &boundary);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen if (ret >= 0) {
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen return ret == 0 ? 0 :
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen parse_part_finish(ctx, boundary, block_r, TRUE);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen }
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen }
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen i_assert(block_r->size > 0);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen boundary_start = 0;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen /* skip to beginning of the next line. the first line was
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen handled already. */
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen cur = data; end = data + block_r->size;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen while ((next = memchr(cur, '\n', end - cur)) != NULL) {
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen cur = next + 1;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen boundary_start = next - data;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (next > data && next[-1] == '\r')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen boundary_start--;
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (boundary_start != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we can at least skip data until the first [CR]LF.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen input buffer can't be full anymore. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen full = FALSE;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen ret = boundary_line_find(ctx, cur, end - cur, full, &boundary);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (ret >= 0) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* found / need more data */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (ret == 0 && boundary_start == 0)
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen ctx->want_count += cur - block_r->data;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen break;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen if (next != NULL) {
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen /* found / need more data */
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen i_assert(ret >= 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(!(ret == 0 && full));
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen } else if (boundary_start == 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* no linefeeds in this block. we can just skip it. */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ret = 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen boundary_start = block_r->size;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen } else {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* the boundary wasn't found from this data block,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen we'll need more data. */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ret = 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->want_count = (block_r->size - boundary_start) + 1;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (ret > 0 || (ret == 0 && !ctx->eof)) {
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 */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen block_r->size = boundary_start;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (block_r->size != 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen parse_body_add_block(ctx, block_r);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return 1;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return ret <= 0 ? ret :
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen parse_part_finish(ctx, boundary, block_r, FALSE);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen struct message_block *block_r)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen bool full;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen int ret;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return ret;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen parse_body_add_block(ctx, block_r);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainenstatic void parse_content_type(struct message_parser_ctx *ctx,
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen struct message_header_line *hdr)
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct rfc822_parser_context parser;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen const char *const *results;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen string_t *content_type;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen if (ctx->part_seen_content_type)
7bd6001d84ecc1792ddfd54fe8efa63c509d90b1Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part_seen_content_type = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen (void)rfc822_skip_lwsp(&parser);
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen content_type = t_str_new(64);
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen if (rfc822_parse_content_type(&parser, content_type) < 0)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
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 &&
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen (str_len(content_type) == 4 ||
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen str_data(content_type)[4] == '/'))
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_TEXT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strncasecmp(str_c(content_type), "multipart/", 10) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcasecmp(str_c(content_type)+10, "digest") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART_DIGEST;
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen }
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen ctx->last_boundary != NULL)
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen return;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen (void)rfc2231_parse(&parser, &results);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen for (; *results != NULL; results += 2) {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if (strcasecmp(results[0], "boundary") == 0) {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen ctx->last_boundary =
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen p_strdup(ctx->parser_pool, results[1]);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen break;
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen}
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen#define MUTEX_FLAGS \
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen (MESSAGE_PART_FLAG_MESSAGE_RFC822 | MESSAGE_PART_FLAG_MULTIPART)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int parse_next_header(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_block *block_r)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_part *part = ctx->part;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_header_line *hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen if (ctx->skip > 0) {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen i_stream_skip(ctx->input, ctx->skip);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen ctx->skip = 0;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen (void)i_stream_get_data(ctx->input, &size);
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen ctx->want_count = size + 1;
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (hdr != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (hdr->eoh)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcasecmp(hdr->name, "Mime-Version") == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* it's MIME. Content-* headers are valid */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen part->flags |= MESSAGE_PART_FLAG_IS_MIME;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (strcasecmp(hdr->name, "Content-Type") == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((ctx->flags &
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MESSAGE_PARSER_FLAG_MIME_VERSION_STRICT) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen part->flags |= MESSAGE_PART_FLAG_IS_MIME;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (hdr->continues)
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen hdr->use_full_value = TRUE;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen else T_BEGIN {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen parse_content_type(ctx, hdr);
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen } T_END;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen }
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen block_r->hdr = hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen block_r->size = 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return 1;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen /* end of headers */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->last_boundary == NULL) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* multipart type but no message boundary */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen part->flags = 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
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. */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen part->flags = 0;
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen ctx->last_boundary = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (!ctx->part_seen_content_type ||
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen (part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (part->parent != NULL &&
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen (part->parent->flags &
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen MESSAGE_PART_FLAG_MULTIPART_DIGEST) != 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* when there's no content-type specified and we're
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen below multipart/digest, assume message/rfc822
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen content-type */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen } else {
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen /* otherwise we default to text/plain */
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen part->flags |= MESSAGE_PART_FLAG_TEXT;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (message_parse_header_has_nuls(ctx->hdr_parser_ctx))
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_assert((part->flags & MUTEX_FLAGS) != MUTEX_FLAGS);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->last_chr = '\n';
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if (ctx->last_boundary != NULL) {
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen parse_next_body_multipart_init(ctx);
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;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (ctx->boundaries != NULL)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen else
ff4bb2dfb5714eeb0408d3bb862de1646351d097Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->want_count = 1;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* return empty block as end of headers */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen block_r->hdr = NULL;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen block_r->size = 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return 1;
ff4bb2dfb5714eeb0408d3bb862de1646351d097Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
ff4bb2dfb5714eeb0408d3bb862de1646351d097Timo Sirainen struct message_block *block_r)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_assert(ctx->hdr_parser_ctx == NULL);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->hdr_parser_ctx =
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen message_parse_header_init(ctx->input, &ctx->part->header_size,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->hdr_flags);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->part_seen_content_type = FALSE;
60f9b96be55e63f0113e273dda8ba3b883c6f095Timo Sirainen
60f9b96be55e63f0113e273dda8ba3b883c6f095Timo Sirainen ctx->parse_next_block = parse_next_header;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return parse_next_header(ctx, block_r);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int preparsed_parse_eof(struct message_parser_ctx *ctx ATTR_UNUSED,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen struct message_block *block_r ATTR_UNUSED)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic void preparsed_skip_to_next(struct message_parser_ctx *ctx)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen while (ctx->part != NULL) {
60f9b96be55e63f0113e273dda8ba3b883c6f095Timo Sirainen if (ctx->part->next != NULL) {
60f9b96be55e63f0113e273dda8ba3b883c6f095Timo Sirainen ctx->part = ctx->part->next;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen break;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->part = ctx->part->parent;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (ctx->part == NULL)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->parse_next_block = preparsed_parse_eof;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int preparsed_parse_body_finish(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_block *block_r)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
bde6382cf65fba6165dc3603f5419e194d87f404Timo Sirainen ctx->skip = 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen preparsed_skip_to_next(ctx);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return ctx->parse_next_block(ctx, block_r);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int preparsed_parse_body_more(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_block *block_r)
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen uoff_t end_offset = ctx->part->physical_pos +
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->part->header_size.physical_size +
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->part->body_size.physical_size;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen bool full;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen int ret;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return ret;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
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;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->skip = block_r->size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int preparsed_parse_body_init(struct message_parser_ctx *ctx,
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen struct message_block *block_r)
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen{
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen uoff_t offset = ctx->part->physical_pos +
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->part->header_size.physical_size;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen if (offset < ctx->input->v_offset) {
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen /* header was actually larger than the cached size suggested */
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->broken = TRUE;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen return -1;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen }
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen i_stream_skip(ctx->input, offset - ctx->input->v_offset);
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->parse_next_block = preparsed_parse_body_more;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen return preparsed_parse_body_more(ctx, block_r);
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen}
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainenstatic int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen struct message_block *block_r)
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen{
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen if (ctx->part->children != NULL) {
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->part = ctx->part->children;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen ctx->parse_next_block = preparsed_parse_body_init;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen } else {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen preparsed_skip_to_next(ctx);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen return ctx->parse_next_block(ctx, block_r);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen}
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainenstatic int preparsed_parse_next_header(struct message_parser_ctx *ctx,
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen struct message_block *block_r)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen{
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen struct message_header_line *hdr;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen size_t size;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen int ret;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen (void)i_stream_get_data(ctx->input, &size);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen ctx->want_count = size + 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (hdr != NULL) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen block_r->hdr = hdr;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen block_r->size = 0;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return 1;
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen }
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen ctx->parse_next_block = preparsed_parse_finish_header;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen /* return empty block as end of headers */
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen block_r->hdr = NULL;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen block_r->size = 0;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen i_assert(ctx->skip == 0);
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen if (ctx->input->v_offset != ctx->part->physical_pos +
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen ctx->part->header_size.physical_size) {
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen ctx->broken = TRUE;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen return -1;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen }
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return 1;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen}
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen struct message_block *block_r)
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen{
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen i_assert(ctx->hdr_parser_ctx == NULL);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
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 ctx->input->v_offset);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->hdr_parser_ctx =
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen message_parse_header_init(ctx->input, NULL, ctx->hdr_flags);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return preparsed_parse_next_header(ctx, block_r);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen}
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenstruct message_parser_ctx *
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenmessage_parser_init(pool_t part_pool, struct istream *input,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen enum message_header_parser_flags hdr_flags,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen enum message_parser_flags flags)
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen{
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen struct message_parser_ctx *ctx;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen pool_t pool;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen pool = pool_alloconly_create("Message Parser", 1024);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx = p_new(pool, struct message_parser_ctx, 1);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parser_pool = pool;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->part_pool = part_pool;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->hdr_flags = hdr_flags;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->flags = flags;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->input = input;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parts = ctx->part = part_pool == NULL ? NULL :
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen p_new(part_pool, struct message_part, 1);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parse_next_block = parse_next_header_init;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen i_stream_ref(input);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return ctx;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen}
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenstruct message_parser_ctx *
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenmessage_parser_init_from_parts(struct message_part *parts,
65d6ca3fb5450b81df0190d9e9aa62c00fed5116Timo Sirainen struct istream *input,
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen enum message_header_parser_flags hdr_flags,
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen enum message_parser_flags flags)
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen{
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen struct message_parser_ctx *ctx;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx = message_parser_init(NULL, input, hdr_flags, flags);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parts = ctx->part = parts;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen return ctx;
73c76fa7340a107229c530196d026aadeae979c7Timo Sirainen}
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen
9c7e765845357342923e16351181091028e5930fTimo Sirainenint message_parser_deinit(struct message_parser_ctx **_ctx,
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen struct message_part **parts_r)
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen{
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen struct message_parser_ctx *ctx = *_ctx;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen int ret = ctx->broken ? -1 : 0;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *_ctx = NULL;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *parts_r = ctx->parts;
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen if (ctx->hdr_parser_ctx != NULL)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_stream_unref(&ctx->input);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen pool_unref(&ctx->parser_pool);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return ret;
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen}
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenint message_parser_parse_next_block(struct message_parser_ctx *ctx,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct message_block *block_r)
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen int ret;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen bool eof = FALSE, full;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen while ((ret = ctx->parse_next_block(ctx, block_r)) == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ret = message_parser_read_more(ctx, block_r, &full);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (ret == 0) {
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen i_assert(!ctx->input->blocking);
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen return 0;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (ret == -1) {
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen i_assert(!eof);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen eof = TRUE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen }
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen block_r->part = ctx->part;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen if (ret < 0 && ctx->part != NULL) {
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);
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen while (ctx->part->parent != NULL) {
65d6ca3fb5450b81df0190d9e9aa62c00fed5116Timo Sirainen message_size_add(&ctx->part->parent->body_size,
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainen &ctx->part->body_size);
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainen message_size_add(&ctx->part->parent->body_size,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen &ctx->part->header_size);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->part = ctx->part->parent;
65d6ca3fb5450b81df0190d9e9aa62c00fed5116Timo Sirainen }
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen }
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen#undef message_parser_parse_header
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid message_parser_parse_header(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_size *hdr_size,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen message_part_header_callback_t *callback,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen void *context)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct message_block block;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen int ret;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen callback(block.part, block.hdr, context);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (block.hdr == NULL)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen break;
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert(ret != 0);
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen if (ret < 0) {
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen /* well, can't return error so fake end of headers */
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen callback(ctx->part, NULL, context);
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen *hdr_size = ctx->part->header_size;
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen}
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen#undef message_parser_parse_body
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainenvoid message_parser_parse_body(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen message_part_header_callback_t *hdr_callback,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen void *context)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen{
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen struct message_block block;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen if (block.size == 0 && hdr_callback != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr_callback(block.part, block.hdr, context);
013e3b3942e9550fde619a0b3ce6bdd04edc4268Timo Sirainen }
013e3b3942e9550fde619a0b3ce6bdd04edc4268Timo Sirainen i_assert(ret != 0);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen