message-parser.c revision 1bc6f1c54b4d77830288b8cf19060bd8a6db7b27
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "buffer.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "rfc822-parser.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "rfc2231-parser.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo 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
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainenstruct message_boundary {
0c17af9d3f9323136a94e66605776ed4462a172dTimo 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 bool 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 const char *broken_reason;
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 unsigned int prev_hdr_newline_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int (*parse_next_block)(struct message_parser_ctx *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_block *block_r);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool part_seen_content_type:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool multipart:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool preparsed:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool 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_epilogue_init(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 struct message_boundary *best = NULL;
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. However, if there are multiple prefixes whose beginning
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen matches, use the longest matching one. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen while (boundaries != NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (boundaries->len <= len &&
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen memcmp(boundaries->boundary, data, boundaries->len) == 0 &&
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen (best == NULL || best->len < boundaries->len))
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen best = boundaries;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen boundaries = boundaries->next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return best;
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_bytes(ctx->input, &block_r->data,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen &block_r->size, ctx->want_count + 1);
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 if (!*full_r) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* reset number of wanted characters if we actually got them */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->want_count = 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct message_part *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmessage_part_append(pool_t pool, struct message_part *parent)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_part *p, *part, **list;
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(parent != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert((parent->flags & (MESSAGE_PART_FLAG_MULTIPART |
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MESSAGE_PART_FLAG_MESSAGE_RFC822)) != 0);
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen part = p_new(pool, struct message_part, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen part->parent = parent;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (p = parent; p != NULL; p = p->parent)
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen p->children_count++;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* set child position */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen part->physical_pos =
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen parent->physical_pos +
2abfef71398a61e5ed97c23a1ceb71461933ccb8Timo Sirainen parent->body_size.physical_size +
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parent->header_size.physical_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list = &part->parent->children;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (*list != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list = &(*list)->next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen *list = part;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen return part;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen}
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainenstatic void parse_next_body_multipart_init(struct message_parser_ctx *ctx)
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen{
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen struct message_boundary *b;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen b = p_new(ctx->parser_pool, struct message_boundary, 1);
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen b->part = ctx->part;
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen b->boundary = ctx->last_boundary;
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen b->len = strlen(b->boundary);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen b->next = ctx->boundaries;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->boundaries = b;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->last_boundary = NULL;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen}
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainenstatic int parse_next_body_message_rfc822_init(struct message_parser_ctx *ctx,
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen struct message_block *block_r)
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen{
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen return parse_next_header_init(ctx, block_r);
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenboundary_line_find(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned char *data, size_t size, bool full,
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen struct message_boundary **boundary_r)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen{
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen *boundary_r = NULL;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen if (size < 2) {
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen i_assert(!full);
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen if (ctx->input->eof)
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->want_count = 2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen }
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen if (data[0] != '-' || data[1] != '-') {
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen /* not a boundary, just skip this line */
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen return -1;
9c7e765845357342923e16351181091028e5930fTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen /* need to find the end of line */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo 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;
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen return 0;
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
b00787191c3c31bebb939c3d00f1fcdb67356c69Timo 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)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return -1;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen (*boundary_r)->epilogue_found =
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo 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,
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen struct message_block *block_r)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_IS_MIME;
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return parse_next_header_init(ctx, block_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct message_block *block_r)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen{
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const unsigned char *ptr;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen int ret;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen bool full;
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ptr = memchr(block_r->data, '\n', block_r->size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ptr == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parse_body_add_block(ctx, block_r);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (block_r->size > 0 &&
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen /* found the LF */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen block_r->size = (ptr - block_r->data) + 1;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen parse_body_add_block(ctx, block_r);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (ctx->boundaries == NULL || ctx->boundaries->part != ctx->part) {
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen /* epilogue */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->boundaries != NULL)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen else
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen } else {
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen /* a new MIME part begins */
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->parse_next_block = parse_next_mime_header_init;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen }
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (block_r->size > 0 &&
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen return 1;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen return ctx->parse_next_block(ctx, block_r);
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen}
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenstatic int parse_part_finish(struct message_parser_ctx *ctx,
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen struct message_boundary *boundary,
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen struct message_block *block_r, bool first_line)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen{
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct message_part *part;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen size_t line_size;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen i_assert(ctx->last_boundary == NULL);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen /* get back to parent MIME part, summing the child MIME part sizes
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen into parent's body sizes */
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen for (part = ctx->part; part != boundary->part; part = part->parent) {
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen message_size_add(&part->parent->body_size, &part->body_size);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen message_size_add(&part->parent->body_size, &part->header_size);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen }
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen i_assert(part != NULL);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->part = part;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (boundary->epilogue_found) {
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen /* this boundary isn't needed anymore */
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->boundaries = boundary->next;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen } else {
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen /* forget about the boundaries we possibly skipped */
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen ctx->boundaries = boundary;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen }
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen /* the boundary itself should already be in buffer. add that. */
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen block_r->data = i_stream_get_data(ctx->input, &block_r->size);
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen i_assert(block_r->size >= ctx->skip);
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen block_r->data += ctx->skip;
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen /* [[\r]\n]--<boundary>[--] */
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen if (first_line)
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen line_size = 0;
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen else if (block_r->data[0] == '\r') {
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen i_assert(block_r->data[1] == '\n');
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen line_size = 2;
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen } else {
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen i_assert(block_r->data[0] == '\n');
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen line_size = 1;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen line_size += 2 + boundary->len + (boundary->epilogue_found ? 2 : 0);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen i_assert(block_r->size >= ctx->skip + line_size);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen block_r->size = line_size;
a87e5f15283e057c7dc26dd9db7b616268c95ca7Timo Sirainen parse_body_add_block(ctx, block_r);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
c93cd163f9c1d4b0ca29f49cbfdbf474caeef5bfTimo Sirainen ctx->parse_next_block = parse_next_body_skip_boundary_line;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if ((ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return ctx->parse_next_block(ctx, block_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen struct message_block *block_r)
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen{
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen struct message_boundary *boundary = NULL;
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen const unsigned char *data, *cur, *next, *end;
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen size_t boundary_start;
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen int ret;
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen bool full;
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen return ret;
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen data = block_r->data;
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen if (ctx->last_chr == '\n') {
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen /* handle boundary in first line of message. alternatively
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen it's an empty line. */
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen ret = boundary_line_find(ctx, block_r->data,
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen block_r->size, full, &boundary);
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen if (ret >= 0) {
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen return ret == 0 ? 0 :
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen parse_part_finish(ctx, boundary, block_r, TRUE);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen }
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen }
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen i_assert(block_r->size > 0);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen boundary_start = 0;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* skip to beginning of the next line. the first line was
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen handled already. */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen cur = data; end = data + block_r->size;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen while ((next = memchr(cur, '\n', end - cur)) != NULL) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen cur = next + 1;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen boundary_start = next - data;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (next > data && next[-1] == '\r')
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen boundary_start--;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen if (boundary_start != 0) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* we can at least skip data until the first [CR]LF.
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen input buffer can't be full anymore. */
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen full = FALSE;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen }
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ret = boundary_line_find(ctx, cur, end - cur, full, &boundary);
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen if (ret >= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* found / need more data */
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen if (ret == 0 && boundary_start == 0)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->want_count += cur - block_r->data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen if (next != NULL) {
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen /* found / need more data */
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen i_assert(ret >= 0);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen i_assert(!(ret == 0 && full));
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen } else if (boundary_start == 0) {
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen /* no linefeeds in this block. we can just skip it. */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ret = 0;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (block_r->data[block_r->size-1] == '\r' && !ctx->eof) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* this may be the beginning of the \r\n--boundary */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen block_r->size--;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen boundary_start = block_r->size;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen } else {
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen /* the boundary wasn't found from this data block,
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen we'll need more data. */
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen ret = 0;
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen ctx->want_count = (block_r->size - boundary_start) + 1;
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen }
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen if (ret > 0 || (ret == 0 && !ctx->eof)) {
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen /* a) we found the boundary
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen b) we need more data and haven't reached EOF yet
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen so leave CR+LF + last line to buffer */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen block_r->size = boundary_start;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (block_r->size != 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen parse_body_add_block(ctx, block_r);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) == 0)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
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
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_block *block_r)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen bool full;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen int ret;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return ret;
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen parse_body_add_block(ctx, block_r);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainen (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) == 0)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen return 1;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen}
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstatic void parse_content_type(struct message_parser_ctx *ctx,
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen struct message_header_line *hdr)
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen{
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen struct rfc822_parser_context parser;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen const char *const *results;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen string_t *content_type;
7bd6001d84ecc1792ddfd54fe8efa63c509d90b1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->part_seen_content_type)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen ctx->part_seen_content_type = TRUE;
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen rfc822_skip_lwsp(&parser);
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen content_type = t_str_new(64);
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen if (rfc822_parse_content_type(&parser, content_type) < 0)
b63284468d717737ecd63d78b6928c5d7f0d3634Timo Sirainen return;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcasecmp(str_c(content_type), "message/rfc822") == 0)
9a56220167d02bbcb66a81b7553f4eb4da939945Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
9a56220167d02bbcb66a81b7553f4eb4da939945Timo Sirainen else if (strncasecmp(str_c(content_type), "text", 4) == 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (str_len(content_type) == 4 ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_data(content_type)[4] == '/'))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_TEXT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strncasecmp(str_c(content_type), "multipart/", 10) == 0) {
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART;
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen if (strcasecmp(str_c(content_type)+10, "digest") == 0)
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART_DIGEST;
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen ctx->last_boundary != NULL)
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen return;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen rfc2231_parse(&parser, &results);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen for (; *results != NULL; results += 2) {
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen if (strcasecmp(results[0], "boundary") == 0) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen ctx->last_boundary =
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen p_strdup(ctx->parser_pool, results[1]);
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen break;
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen }
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool block_is_at_eoh(const struct message_block *block)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (block->size < 1)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (block->data[0] == '\n')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen if (block->data[0] == '\r') {
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen if (block->size < 2)
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen return FALSE;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if (block->data[1] == '\n')
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen}
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen#define MUTEX_FLAGS \
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen (MESSAGE_PART_FLAG_MESSAGE_RFC822 | MESSAGE_PART_FLAG_MULTIPART)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainenstatic int parse_next_header(struct message_parser_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_block *block_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_part *part = ctx->part;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_header_line *hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_boundary *boundary;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen bool full;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen int ret;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) == 0)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret > 0 && block_is_at_eoh(block_r) &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->last_boundary != NULL &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (part->flags & MESSAGE_PART_FLAG_IS_MIME) != 0) {
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen /* we are at the end of headers and we've determined that we're
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen going to start a multipart. add the boundary already here
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen at this point so we can reliably determine whether the
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen "\n--boundary" belongs to us or to a previous boundary.
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen this is a problem if the boundary prefixes are identical,
eae1d6e75713d3d658908ac39b719992e2f8a456Timo Sirainen because MIME requires only the prefix to match. */
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen parse_next_body_multipart_init(ctx);
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen ctx->multipart = TRUE;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen }
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* before parsing the header see if we can find a --boundary from here.
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen we're guaranteed to be at the beginning of the line here. */
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen if (ret > 0) {
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen ret = ctx->boundaries == NULL ? -1 :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen boundary_line_find(ctx, block_r->data,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen block_r->size, full, &boundary);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (ret > 0 && boundary->part == ctx->part) {
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen /* our own body begins with our own --boundary.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen we don't want to handle that yet. */
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen ret = -1;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen if (ret < 0) {
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen /* no boundary */
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen ctx->want_count = i_stream_get_data_size(ctx->input) + 1;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return ret;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen } else if (ret == 0) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen /* need more data */
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return 0;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen } else {
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen /* boundary found. stop parsing headers here. The previous
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen [CR]LF belongs to the MIME boundary though. */
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (ctx->prev_hdr_newline_size > 0) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen i_assert(ctx->part->header_size.lines > 0);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen /* remove the newline size from the MIME header */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->part->header_size.lines--;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen ctx->part->header_size.physical_size -=
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen ctx->prev_hdr_newline_size;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen ctx->part->header_size.virtual_size -= 2;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen /* add the newline size to the parent's body */
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->part->parent->body_size.lines++;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen ctx->part->parent->body_size.physical_size +=
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->prev_hdr_newline_size;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->part->parent->body_size.virtual_size += 2;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if (hdr != NULL) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (hdr->eoh)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen else if (strcasecmp(hdr->name, "Mime-Version") == 0) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* it's MIME. Content-* headers are valid */
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen part->flags |= MESSAGE_PART_FLAG_IS_MIME;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen } else if (strcasecmp(hdr->name, "Content-Type") == 0) {
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen if ((ctx->flags &
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen MESSAGE_PARSER_FLAG_MIME_VERSION_STRICT) == 0)
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen part->flags |= MESSAGE_PART_FLAG_IS_MIME;
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (hdr->continues)
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen hdr->use_full_value = TRUE;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen else T_BEGIN {
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen parse_content_type(ctx, hdr);
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen } T_END;
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen }
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen block_r->hdr = hdr;
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen block_r->size = 0;
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen ctx->prev_hdr_newline_size = hdr->no_newline ? 0 :
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen (hdr->crlf_newline ? 2 : 1);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen return 1;
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen }
7c449f545b10daa47027552f98d916a9805da662Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* end of headers */
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen if ((part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen /* It's not MIME. Reset everything we found from
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Content-Type. */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_assert(!ctx->multipart);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen part->flags = 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
7c449f545b10daa47027552f98d916a9805da662Timo Sirainen ctx->last_boundary = NULL;
7c449f545b10daa47027552f98d916a9805da662Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (!ctx->part_seen_content_type ||
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen (part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
ff4bb2dfb5714eeb0408d3bb862de1646351d097Timo Sirainen if (part->parent != NULL &&
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainen (part->parent->flags &
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo 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;
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen } else {
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen /* otherwise we default to text/plain */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen part->flags |= MESSAGE_PART_FLAG_TEXT;
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen if (message_parse_header_has_nuls(ctx->hdr_parser_ctx))
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo 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);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->last_chr = '\n';
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->multipart) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_assert(ctx->last_boundary == NULL);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->multipart = FALSE;
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen } else if ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) != 0)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->parse_next_block = parse_next_body_message_rfc822_init;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen else if (ctx->boundaries != NULL)
60f9b96be55e63f0113e273dda8ba3b883c6f095Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen else
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->want_count = 1;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen /* return empty block as end of headers */
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen block_r->hdr = NULL;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen block_r->size = 0;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen return 1;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen}
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen struct message_block *block_r)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(ctx->hdr_parser_ctx == NULL);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->hdr_parser_ctx =
bde6382cf65fba6165dc3603f5419e194d87f404Timo Sirainen message_parse_header_init(ctx->input, &ctx->part->header_size,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->hdr_flags);
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen ctx->part_seen_content_type = FALSE;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->prev_hdr_newline_size = 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->parse_next_block = parse_next_header;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return parse_next_header(ctx, block_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainenstatic int preparsed_parse_eof(struct message_parser_ctx *ctx ATTR_UNUSED,
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen struct message_block *block_r ATTR_UNUSED)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen return -1;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen}
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainenstatic void preparsed_skip_to_next(struct message_parser_ctx *ctx)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen{
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen while (ctx->part != NULL) {
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen if (ctx->part->next != NULL) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ctx->part = ctx->part->next;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen break;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* parse epilogue of multipart parent if requested */
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if (ctx->part->parent != NULL &&
60f9b96be55e63f0113e273dda8ba3b883c6f095Timo Sirainen (ctx->part->parent->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* check for presence of epilogue */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t part_end = ctx->part->physical_pos +
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part->header_size.physical_size +
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->part->body_size.physical_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t parent_end = ctx->part->parent->physical_pos +
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->part->parent->header_size.physical_size +
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->part->parent->body_size.physical_size;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen if (parent_end > part_end) {
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->parse_next_block = preparsed_parse_epilogue_init;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen break;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen }
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen }
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->part = ctx->part->parent;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen }
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen if (ctx->part == NULL)
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->parse_next_block = preparsed_parse_eof;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen}
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainenstatic int preparsed_parse_body_finish(struct message_parser_ctx *ctx,
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen struct message_block *block_r)
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen{
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen ctx->skip = 0;
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen preparsed_skip_to_next(ctx);
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen return ctx->parse_next_block(ctx, block_r);
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen}
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainenstatic int preparsed_parse_prologue_finish(struct message_parser_ctx *ctx,
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen struct message_block *block_r)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen{
d22301419109ed4a38351715e6760011421dadecTimo Sirainen i_stream_skip(ctx->input, ctx->skip);
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen ctx->skip = 0;
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen ctx->part = ctx->part->children;
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen return ctx->parse_next_block(ctx, block_r);
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen}
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainenstatic int preparsed_parse_body_more(struct message_parser_ctx *ctx,
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen struct message_block *block_r)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen{
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen uoff_t end_offset = ctx->part->physical_pos +
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->part->header_size.physical_size +
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->part->body_size.physical_size;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen bool full;
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen int ret;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
7c449f545b10daa47027552f98d916a9805da662Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen return ret;
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen if (ctx->input->v_offset + block_r->size >= end_offset) {
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen block_r->size = end_offset - ctx->input->v_offset;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->parse_next_block = preparsed_parse_body_finish;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen }
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen ctx->skip = block_r->size;
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen return 1;
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen}
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainenstatic int preparsed_parse_prologue_more(struct message_parser_ctx *ctx,
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen struct message_block *block_r)
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen{
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen uoff_t boundary_min_start, end_offset;
8d889b6d842e96ecbe7b6493920bbb6df8e0ed30Timo Sirainen const unsigned char *cur;
0ed9ccd0047f75df54a49bc117ca301eb398e447Timo Sirainen bool full;
8d889b6d842e96ecbe7b6493920bbb6df8e0ed30Timo Sirainen int ret;
8d889b6d842e96ecbe7b6493920bbb6df8e0ed30Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen i_assert(ctx->part->children != NULL);
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen end_offset = ctx->part->children->physical_pos;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen return ret;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
7d7f4648f72b8c70928e04514b0d93dad0ba6fd5Timo Sirainen if (ctx->input->v_offset + block_r->size >= end_offset) {
7d7f4648f72b8c70928e04514b0d93dad0ba6fd5Timo Sirainen /* we've got the full prologue: clip off the initial boundary */
7d7f4648f72b8c70928e04514b0d93dad0ba6fd5Timo Sirainen block_r->size = end_offset - ctx->input->v_offset;
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen cur = block_r->data + block_r->size - 1;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen /* [\r]\n--boundary[\r]\n */
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen if (block_r->size < 5 || *cur != '\n') {
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen ctx->broken_reason = "Prologue boundary end not at expected position";
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen return -1;
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen }
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen cur--;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen if (*cur == '\r') cur--;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen /* find newline just before boundary */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen for (; cur >= block_r->data; cur--) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (*cur == '\n') break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
649823f9c7e42a424a8fadc427e12f3576c4f714Timo Sirainen
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen if (cur[0] != '\n' || cur[1] != '-' || cur[2] != '-') {
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen ctx->broken_reason = "Prologue boundary beginning not at expected position";
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen return -1;
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cur != block_r->data && cur[-1] == '\r') cur--;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* clip boundary */
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen block_r->size = cur - block_r->data;
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->parse_next_block = preparsed_parse_prologue_finish;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->skip = block_r->size;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen return 1;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen }
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen /* retain enough data in the stream buffer to contain initial boundary */
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainen if (end_offset > BOUNDARY_END_MAX_LEN)
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen boundary_min_start = end_offset - BOUNDARY_END_MAX_LEN;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen else
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen boundary_min_start = 0;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen if (ctx->input->v_offset + block_r->size >= boundary_min_start) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen if (boundary_min_start <= ctx->input->v_offset)
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return 0;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen block_r->size = boundary_min_start - ctx->input->v_offset;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen }
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->skip = block_r->size;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return 1;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen}
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenstatic int preparsed_parse_epilogue_more(struct message_parser_ctx *ctx,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen struct message_block *block_r)
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen{
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen uoff_t end_offset = ctx->part->physical_pos +
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->part->header_size.physical_size +
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->part->body_size.physical_size;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen bool full;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen int ret;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return ret;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen if (ctx->input->v_offset + block_r->size >= end_offset) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen block_r->size = end_offset - ctx->input->v_offset;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->parse_next_block = preparsed_parse_body_finish;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen }
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen ctx->skip = block_r->size;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen return 1;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen}
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenstatic int preparsed_parse_epilogue_boundary(struct message_parser_ctx *ctx,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen struct message_block *block_r)
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen{
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen uoff_t end_offset = ctx->part->physical_pos +
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->part->header_size.physical_size +
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->part->body_size.physical_size;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen const unsigned char *data, *cur;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen size_t size;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen bool full;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen int ret;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen if (end_offset - ctx->input->v_offset < 7) {
65d6ca3fb5450b81df0190d9e9aa62c00fed5116Timo Sirainen ctx->broken_reason = "Epilogue position is wrong";
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen return -1;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen }
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen return ret;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen /* [\r]\n--boundary--[\r]\n */
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen if (block_r->size < 7) {
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen ctx->want_count = 7;
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen return 0;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen }
649823f9c7e42a424a8fadc427e12f3576c4f714Timo Sirainen
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen data = block_r->data;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen size = block_r->size;
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen cur = data;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen if (*cur == '\r') cur++;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen if (cur[0] != '\n' || cur[1] != '-' || data[2] != '-') {
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen ctx->broken_reason = "Epilogue boundary start not at expected position";
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return -1;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen }
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen /* find the end of the line */
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen cur += 3;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen if ((cur = memchr(cur, '\n', size - (cur-data))) == NULL) {
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen if (end_offset < ctx->input->v_offset + size) {
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen ctx->broken_reason = "Epilogue boundary end not at expected position";
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return -1;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen } else if (ctx->input->v_offset + size < end_offset &&
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen size < BOUNDARY_END_MAX_LEN &&
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen !ctx->input->eof && !full) {
305465bb1a4c5d90c4b4e2c2790eb05fa4ebc41eTimo Sirainen ctx->want_count = BOUNDARY_END_MAX_LEN;
305465bb1a4c5d90c4b4e2c2790eb05fa4ebc41eTimo Sirainen return 0;
305465bb1a4c5d90c4b4e2c2790eb05fa4ebc41eTimo Sirainen }
305465bb1a4c5d90c4b4e2c2790eb05fa4ebc41eTimo Sirainen }
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen block_r->size = 0;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen ctx->parse_next_block = preparsed_parse_epilogue_more;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen ctx->skip = cur - data + 1;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return 0;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen}
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen
a38ef15060e45e5060bb24c403a580b9a57a818cTimo Sirainenstatic int preparsed_parse_body_init(struct message_parser_ctx *ctx,
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen struct message_block *block_r)
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen{
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen uoff_t offset = ctx->part->physical_pos +
73c76fa7340a107229c530196d026aadeae979c7Timo Sirainen ctx->part->header_size.physical_size;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen
9c7e765845357342923e16351181091028e5930fTimo Sirainen if (offset < ctx->input->v_offset) {
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen /* header was actually larger than the cached size suggested */
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen ctx->broken_reason = "Header larger than its cached size";
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen return -1;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_stream_skip(ctx->input, offset - ctx->input->v_offset);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* multipart messages may begin with --boundary--, which makes them
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen not have any children. */
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen ctx->part->children == NULL)
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->parse_next_block = preparsed_parse_body_more;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen else
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->parse_next_block = preparsed_parse_prologue_more;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return ctx->parse_next_block(ctx, block_r);
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen}
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic int preparsed_parse_epilogue_init(struct message_parser_ctx *ctx,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct message_block *block_r)
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen uoff_t offset = ctx->part->physical_pos +
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->part->header_size.physical_size +
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen ctx->part->body_size.physical_size;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->part = ctx->part->parent;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen if (offset < ctx->input->v_offset) {
7895c4845da515b0aa9bb156674a1fca40803f44Timo Sirainen /* last child was actually larger than the cached size
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen suggested */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->broken_reason = "Part larger than its cached size";
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen i_stream_skip(ctx->input, offset - ctx->input->v_offset);
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen ctx->parse_next_block = preparsed_parse_epilogue_boundary;
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen return ctx->parse_next_block(ctx, block_r);
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen}
7abd00c65bbf53fda3f638101c4cd43647d1eb07Timo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainenstatic int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen struct message_block *block_r)
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (ctx->part->children != NULL) {
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) != 0)
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen ctx->parse_next_block = preparsed_parse_body_init;
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen else {
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen ctx->part = ctx->part->children;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen }
65d6ca3fb5450b81df0190d9e9aa62c00fed5116Timo Sirainen } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainen ctx->parse_next_block = preparsed_parse_body_init;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen preparsed_skip_to_next(ctx);
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen }
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return ctx->parse_next_block(ctx, block_r);
65d6ca3fb5450b81df0190d9e9aa62c00fed5116Timo Sirainen}
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainenstatic int preparsed_parse_next_header(struct message_parser_ctx *ctx,
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen struct message_block *block_r)
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen{
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen struct message_header_line *hdr;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen int ret;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen ctx->want_count = i_stream_get_data_size(ctx->input) + 1;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen return ret;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen }
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen if (hdr != NULL) {
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen block_r->hdr = hdr;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen block_r->size = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen ctx->parse_next_block = preparsed_parse_finish_header;
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen /* return empty block as end of headers */
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen block_r->hdr = NULL;
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen block_r->size = 0;
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen i_assert(ctx->skip == 0);
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen if (ctx->input->v_offset != ctx->part->physical_pos +
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen ctx->part->header_size.physical_size) {
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen ctx->broken_reason = "Cached header size mismatch";
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen return -1;
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen }
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen return 1;
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen}
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen struct message_block *block_r)
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen{
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen struct istream *hdr_input;
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen i_assert(ctx->hdr_parser_ctx == NULL);
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen i_assert(ctx->part->physical_pos >= ctx->input->v_offset);
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen i_stream_skip(ctx->input, ctx->part->physical_pos -
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen ctx->input->v_offset);
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen /* the header may become truncated by --boundaries. limit the header
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen stream's size to what it's supposed to be to avoid duplicating (and
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen keeping in sync!) all the same complicated logic as in
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen parse_next_header(). */
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen hdr_input = i_stream_create_limit(ctx->input, ctx->part->header_size.physical_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->hdr_parser_ctx =
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen message_parse_header_init(hdr_input, NULL, ctx->hdr_flags);
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen i_stream_unref(&hdr_input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen return preparsed_parse_next_header(ctx, block_r);
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen}
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainenstatic struct message_parser_ctx *
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenmessage_parser_init_int(struct istream *input,
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen enum message_header_parser_flags hdr_flags,
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen enum message_parser_flags flags)
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen{
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen struct message_parser_ctx *ctx;
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen pool_t pool;
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen pool = pool_alloconly_create("Message Parser", 1024);
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen ctx = p_new(pool, struct message_parser_ctx, 1);
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen ctx->parser_pool = pool;
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen ctx->hdr_flags = hdr_flags;
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen ctx->flags = flags;
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen ctx->input = input;
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen i_stream_ref(input);
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen return ctx;
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen}
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainenstruct message_parser_ctx *
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainenmessage_parser_init(pool_t part_pool, struct istream *input,
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen enum message_header_parser_flags hdr_flags,
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen enum message_parser_flags flags)
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen{
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen struct message_parser_ctx *ctx;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen ctx = message_parser_init_int(input, hdr_flags, flags);
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen ctx->part_pool = part_pool;
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen ctx->parts = ctx->part = p_new(part_pool, struct message_part, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->parse_next_block = parse_next_header_init;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ctx;
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen}
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainenstruct message_parser_ctx *
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainenmessage_parser_init_from_parts(struct message_part *parts,
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen struct istream *input,
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen enum message_header_parser_flags hdr_flags,
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen enum message_parser_flags flags)
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen{
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen struct message_parser_ctx *ctx;
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen i_assert(parts != NULL);
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen ctx = message_parser_init_int(input, hdr_flags, flags);
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen ctx->preparsed = TRUE;
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen ctx->parts = ctx->part = parts;
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen return ctx;
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen}
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainenvoid message_parser_deinit(struct message_parser_ctx **_ctx,
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen struct message_part **parts_r)
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen{
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen const char *error;
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen i_assert((**_ctx).preparsed == FALSE);
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen if (message_parser_deinit_from_parts(_ctx, parts_r, &error) < 0)
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen i_panic("message_parser_deinit_from_parts: %s", error);
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen}
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainenint message_parser_deinit_from_parts(struct message_parser_ctx **_ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_part **parts_r,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen const char **error_r)
82c70897a2d0e6144ecc56ca8e0eb9fff768f2c5Timo Sirainen{
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen struct message_parser_ctx *ctx = *_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret = ctx->broken_reason != NULL ? -1 : 0;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen *_ctx = NULL;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen *parts_r = ctx->parts;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen *error_r = ctx->broken_reason;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
82c70897a2d0e6144ecc56ca8e0eb9fff768f2c5Timo Sirainen if (ctx->hdr_parser_ctx != NULL)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen i_stream_unref(&ctx->input);
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen pool_unref(&ctx->parser_pool);
d67ac5f76cc02c227f4997878bb4aef48ee298faTimo Sirainen i_assert(ret < 0 || *parts_r != NULL);
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen return ret;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
c2cb5e469cd11759da22d82083d4fbb564d06dfaTimo Sirainen
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainenint message_parser_parse_next_block(struct message_parser_ctx *ctx,
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen struct message_block *block_r)
4d938f46f4f956ecb802c30ca771922f5539a660Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool eof = FALSE, full;
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen memset(block_r, 0, sizeof(*block_r));
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen while ((ret = ctx->parse_next_block(ctx, block_r)) == 0) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen ret = message_parser_read_more(ctx, block_r, &full);
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen if (ret == 0) {
bfa38f13d605bdd4c6d1f257c46a57bb28c0dd06Timo Sirainen i_assert(!ctx->input->blocking);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if (ret == -1) {
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen i_assert(!eof);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen eof = TRUE;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen block_r->part = ctx->part;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (ret < 0 && ctx->part != NULL) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* Successful EOF or unexpected failure */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen i_assert(ctx->input->eof || ctx->input->closed ||
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen ctx->input->stream_errno != 0 ||
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen ctx->broken_reason != NULL);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen while (ctx->part->parent != NULL) {
7c449f545b10daa47027552f98d916a9805da662Timo Sirainen message_size_add(&ctx->part->parent->body_size,
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen &ctx->part->body_size);
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen message_size_add(&ctx->part->parent->body_size,
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen &ctx->part->header_size);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen ctx->part = ctx->part->parent;
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen }
}
if (block_r->size == 0) {
/* data isn't supposed to be read, so make sure it's NULL */
block_r->data = NULL;
}
return ret;
}
#undef message_parser_parse_header
void message_parser_parse_header(struct message_parser_ctx *ctx,
struct message_size *hdr_size,
message_part_header_callback_t *callback,
void *context)
{
struct message_block block;
int ret;
while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {
callback(block.part, block.hdr, context);
if (block.hdr == NULL)
break;
}
i_assert(ret != 0);
i_assert(ctx->part != NULL);
if (ret < 0) {
/* well, can't return error so fake end of headers */
callback(ctx->part, NULL, context);
}
*hdr_size = ctx->part->header_size;
}
#undef message_parser_parse_body
void message_parser_parse_body(struct message_parser_ctx *ctx,
message_part_header_callback_t *hdr_callback,
void *context)
{
struct message_block block;
int ret;
while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {
if (block.size == 0 && hdr_callback != NULL)
hdr_callback(block.part, block.hdr, context);
}
i_assert(ret != 0);
}