message-parser.c revision 2db031260f1ff8b40dcf7fb39c8c10a90e9b8c5c
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2002-2007 Dovecot authors, see the included COPYING file */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "lib.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "str.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "istream.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "rfc822-parser.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "message-parser.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen/* RFC-2046 requires boundaries are max. 70 chars + "--" prefix + "--" suffix.
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen We'll add a bit more just in case. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#define BOUNDARY_END_MAX_LEN (70 + 2 + 2 + 10)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstruct message_boundary {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_boundary *next;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_part *part;
25d624dd86700c82cd28427f3d3bebe7c8f7f459Timo Sirainen const char *boundary;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen size_t len;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int epilogue_found:1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen};
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstruct message_parser_ctx {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen pool_t parser_pool, part_pool;
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen struct istream *input;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_part *parts, *part;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen enum message_header_parser_flags hdr_flags;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen enum message_parser_flags flags;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char *last_boundary;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_boundary *boundaries;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen size_t skip;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen char last_chr;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int want_count;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_header_parser_ctx *hdr_parser_ctx;
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen int (*parse_next_block)(struct message_parser_ctx *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_block *block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int part_seen_content_type:1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen};
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmessage_part_header_callback_t *null_message_part_header_callback = NULL;
bd63b5b860658b01b1f46f26d406e1e4a9dc019aTimo Sirainen
15a07b47846c47a81d69a14d649564e222d6f742Timo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
cd2cd224d3216a243d55c71c298a5b7684de0ac4Timo Sirainen struct message_block *block_r);
c1faff067b29fb48426cb84260adba563e93189aTimo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen struct message_block *block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_block *block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct message_block *block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainenstatic struct message_boundary *
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenboundary_find(struct message_boundary *boundaries,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const unsigned char *data, size_t len)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen /* As MIME spec says: search from latest one to oldest one so that we
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen don't break if the same boundary is used in nested parts. Also the
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen full message line doesn't have to match the boundary, only the
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen beginning. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen while (boundaries != NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (boundaries->len <= len &&
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen memcmp(boundaries->boundary, data, boundaries->len) == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return boundaries;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen boundaries = boundaries->next;
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen return NULL;
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen}
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainenstatic void parse_body_add_block(struct message_parser_ctx *ctx,
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen struct message_block *block)
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int missing_cr_count = 0;
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen const unsigned char *data = block->data;
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen size_t i;
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block->hdr = NULL;
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen for (i = 0; i < block->size; i++) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (data[i] <= '\n') {
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen if (data[i] == '\n') {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->part->body_size.lines++;
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen if ((i > 0 && data[i-1] != '\r') ||
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (i == 0 && ctx->last_chr != '\r'))
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen missing_cr_count++;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen } else if (data[i] == '\0')
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->part->body_size.physical_size += block->size;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->part->body_size.virtual_size += block->size + missing_cr_count;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->last_chr = data[i-1];
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->skip += block->size;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int message_parser_read_more(struct message_parser_ctx *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_block *block_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen int ret;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
411f318ed3a25fa66c1b932e10df43841e2725c9Timo Sirainen if (ctx->skip > 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->skip = 0;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ret = i_stream_read_data(ctx->input, &block_r->data,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen &block_r->size, ctx->want_count);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ret <= 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ret < 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return ret;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (!ctx->input->eof) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_assert(!ctx->input->blocking);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return 0;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->want_count = 1;
411f318ed3a25fa66c1b932e10df43841e2725c9Timo Sirainen return 1;
411f318ed3a25fa66c1b932e10df43841e2725c9Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic struct message_part *
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmessage_part_append(pool_t pool, struct message_part *parent)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_part *part, **list;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen part = p_new(pool, struct message_part, 1);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen part->parent = parent;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
3a9eb305fd4aad5502cb7e64625874385ab5bc19Timo Sirainen /* set child position */
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen part->physical_pos =
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen parent->physical_pos +
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen parent->body_size.physical_size +
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen parent->header_size.physical_size;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen list = &part->parent->children;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen while (*list != NULL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen list = &(*list)->next;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen *list = part;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return part;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic void parse_next_body_multipart_init(struct message_parser_ctx *ctx)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_boundary *b;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen b = p_new(ctx->parser_pool, struct message_boundary, 1);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen b->part = ctx->part;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen b->boundary = ctx->last_boundary;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen b->len = strlen(b->boundary);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen b->next = ctx->boundaries;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->boundaries = b;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->last_boundary = NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic void parse_next_body_message_rfc822_init(struct message_parser_ctx *ctx)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainenstatic int
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainenboundary_line_find(struct message_parser_ctx *ctx,
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen const unsigned char *data, size_t size, bool full,
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen struct message_boundary **boundary_r)
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen{
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen size_t i;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen *boundary_r = NULL;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (size < 2) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen i_assert(!full);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (ctx->input->eof)
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen return -1;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen ctx->want_count = 2;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen return 0;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen }
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (data[0] != '-' || data[1] != '-') {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* not a boundary, just skip this line */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen return -1;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen }
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* need to find the end of line */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen for (i = 2; i < size; i++) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (data[i] == '\n')
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen break;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen }
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (i == size && i < BOUNDARY_END_MAX_LEN &&
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen !ctx->input->eof && !full) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* no LF found */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen ctx->want_count = BOUNDARY_END_MAX_LEN;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen return 0;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen }
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen data += 2;
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen size -= 2;
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen *boundary_r = boundary_find(ctx->boundaries, data, size);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (*boundary_r == NULL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return -1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen (*boundary_r)->epilogue_found =
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen size >= (*boundary_r)->len + 2 &&
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen memcmp(data + (*boundary_r)->len, "--", 2) == 0;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainenstatic int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx,
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen struct message_block *block_r)
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen size_t i;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen int ret;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen return ret;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen for (i = 0; i < block_r->size; i++) {
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if (block_r->data[i] == '\n')
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen break;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen }
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if (i == block_r->size) {
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen parse_body_add_block(ctx, block_r);
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen return 1;
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen }
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen /* found the LF */
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen block_r->size = i + 1;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen parse_body_add_block(ctx, block_r);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen /* a new MIME part begins */
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_IS_MIME;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen ctx->parse_next_block = parse_next_header_init;
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen return parse_next_header_init(ctx, block_r);
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainenstatic int parse_part_finish(struct message_parser_ctx *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_boundary *boundary,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_block *block_r, bool first_line)
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen{
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen struct message_part *part;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if (boundary == NULL) {
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen /* message ended unexpectedly */
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen return -1;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen }
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen /* get back to parent MIME part, summing the child MIME part sizes
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen into parent's body sizes */
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen for (part = ctx->part; part != boundary->part; part = part->parent) {
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen message_size_add(&part->parent->body_size, &part->body_size);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen message_size_add(&part->parent->body_size, &part->header_size);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen }
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen ctx->part = part;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (boundary->epilogue_found) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* this boundary isn't needed anymore */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->boundaries = boundary->next;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ctx->boundaries != NULL)
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen else
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return ctx->parse_next_block(ctx, block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* forget about the boundaries we possibly skipped */
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen ctx->boundaries = boundary;
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* the boundary itself should already be in buffer. add that. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->data = i_stream_get_data(ctx->input, &block_r->size);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_assert(block_r->size >= ctx->skip + 2 + boundary->len +
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (first_line ? 0 : 1));
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->data += ctx->skip;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* [\n]--<boundary> */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->size = (first_line ? 0 : 1) + 2 + boundary->len;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen parse_body_add_block(ctx, block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ctx->parse_next_block = parse_next_body_skip_boundary_line;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return 1;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen}
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_block *block_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_boundary *boundary = NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const unsigned char *data;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen size_t i, boundary_start;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen int ret;
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen bool eof, full;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) == 0 ||
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->size == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return ret;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen eof = ret == -1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen full = ret == -2;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
ec5fec7eab19e134a2607b7e224b3e14a1771ee0Timo Sirainen data = block_r->data;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ctx->last_chr == '\n') {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* handle boundary in first line of message. alternatively
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen it's an empty line. */
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen ret = boundary_line_find(ctx, block_r->data,
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen block_r->size, full, &boundary);
ec5fec7eab19e134a2607b7e224b3e14a1771ee0Timo Sirainen if (ret >= 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ret == 0)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return 0;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return parse_part_finish(ctx, boundary, block_r, TRUE);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen for (i = boundary_start = 0; i < block_r->size; i++) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* skip to beginning of the next line. the first line was
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen handled already. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen size_t next_line_idx = block_r->size;
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen for (; i < block_r->size; i++) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (data[i] == '\n') {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen boundary_start = i;
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen if (i > 0 && data[i-1] == '\r')
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen boundary_start--;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen next_line_idx = i + 1;
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen break;
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen }
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen }
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen if (boundary_start != 0) {
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen /* we can skip the first lines. input buffer can't be
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen full anymore. */
e593e507ee5ea3869271a631874c5c4b5c7a294dTimo Sirainen full = FALSE;
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen } else if (next_line_idx == block_r->size) {
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen /* no linefeeds in this block. we can just skip it. */
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen boundary_start = block_r->size;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen full = FALSE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
ec5fec7eab19e134a2607b7e224b3e14a1771ee0Timo Sirainen ret = boundary_line_find(ctx, block_r->data + next_line_idx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->size - next_line_idx, full,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen &boundary);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ret >= 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* found / need more data */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ret == 0 && boundary_start == 0)
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen ctx->want_count += next_line_idx;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen break;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (i >= block_r->size) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* the boundary wasn't found from this data block,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen we'll need more data. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (eof)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ret = -1;
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen else {
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen ret = 0;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->want_count = (block_r->size - boundary_start) + 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_assert(!(ret == 0 && full));
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ret >= 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* leave CR+LF + last line to buffer */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->size = boundary_start;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (block_r->size != 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen parse_body_add_block(ctx, block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return ret <= 0 ? ret :
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen parse_part_finish(ctx, boundary, block_r, FALSE);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_block *block_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen int ret;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return ret;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen parse_body_add_block(ctx, block_r);
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen return 1;
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen}
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic void parse_content_type(struct message_parser_ctx *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_header_line *hdr)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct rfc822_parser_context parser;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char *key, *value;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen string_t *content_type;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ctx->part_seen_content_type)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->part_seen_content_type = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (void)rfc822_skip_lwsp(&parser);
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen content_type = t_str_new(64);
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen if (rfc822_parse_content_type(&parser, content_type) < 0)
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen return;
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen if (strcasecmp(str_c(content_type), "message/rfc822") == 0)
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen else if (strncasecmp(str_c(content_type), "text", 4) == 0 &&
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen (str_len(content_type) == 4 ||
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen str_data(content_type)[4] == '/'))
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_TEXT;
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen else if (strncasecmp(str_c(content_type), "multipart/", 10) == 0) {
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART;
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen if (strcasecmp(str_c(content_type)+10, "digest") == 0)
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART_DIGEST;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->last_boundary != NULL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen while (rfc822_parse_content_param(&parser, &key, &value) > 0) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (strcasecmp(key, "boundary") == 0) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen ctx->last_boundary = p_strdup(ctx->parser_pool, value);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen break;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen#define MUTEX_FLAGS \
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (MESSAGE_PART_FLAG_MESSAGE_RFC822 | MESSAGE_PART_FLAG_MULTIPART)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic int parse_next_header(struct message_parser_ctx *ctx,
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen struct message_block *block_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen struct message_part *part = ctx->part;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen struct message_header_line *hdr;
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen size_t size;
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen int ret;
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen if (ctx->skip > 0) {
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen ctx->skip = 0;
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen }
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen (void)i_stream_get_data(ctx->input, &size);
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen ctx->want_count = size + 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return ret;
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen if (hdr != NULL) {
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen if (hdr->eoh)
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen ;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcasecmp(hdr->name, "Mime-Version") == 0) {
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen /* it's MIME. Content-* headers are valid */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen part->flags |= MESSAGE_PART_FLAG_IS_MIME;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen } else if (strcasecmp(hdr->name, "Content-Type") == 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if ((ctx->flags &
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen MESSAGE_PARSER_FLAG_MIME_VERSION_STRICT) == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen part->flags |= MESSAGE_PART_FLAG_IS_MIME;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (hdr->continues)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen hdr->use_full_value = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen t_push();
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen parse_content_type(ctx, hdr);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen t_pop();
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->hdr = hdr;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->size = 0;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen return 1;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen }
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen /* end of headers */
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen ctx->last_boundary == NULL) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* multipart type but no message boundary */
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen part->flags = 0;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen }
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen if ((part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen /* It's not MIME. Reset everything we found from
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen Content-Type. */
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen part->flags = 0;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen ctx->last_boundary = NULL;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen }
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen if (!ctx->part_seen_content_type ||
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen (part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (part->parent != NULL &&
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen (part->parent->flags &
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen MESSAGE_PART_FLAG_MULTIPART_DIGEST) != 0) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* when there's no content-type specified and we're
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen below multipart/digest, assume message/rfc822
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen content-type */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen } else {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* otherwise we default to text/plain */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen part->flags |= MESSAGE_PART_FLAG_TEXT;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen }
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen }
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen if (message_parse_header_has_nuls(ctx->hdr_parser_ctx))
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen i_assert((part->flags & MUTEX_FLAGS) != MUTEX_FLAGS);
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen ctx->last_chr = '\n';
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen if (ctx->last_boundary != NULL) {
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen parse_next_body_multipart_init(ctx);
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen } else if (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) {
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen parse_next_body_message_rfc822_init(ctx);
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen ctx->parse_next_block = parse_next_header_init;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen } else if (ctx->boundaries != NULL)
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen else
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen ctx->want_count = 1;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen /* return empty block as end of headers */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->hdr = NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->size = 0;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen return 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_block *block_r)
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_assert(ctx->hdr_parser_ctx == NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->hdr_parser_ctx =
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen message_parse_header_init(ctx->input, &ctx->part->header_size,
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen ctx->hdr_flags);
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen ctx->part_seen_content_type = FALSE;
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->parse_next_block = parse_next_header;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return parse_next_header(ctx, block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int preparsed_parse_eof(struct message_parser_ctx *ctx ATTR_UNUSED,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_block *block_r ATTR_UNUSED)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return -1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic void preparsed_skip_to_next(struct message_parser_ctx *ctx)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen while (ctx->part != NULL) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ctx->part->next != NULL) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->part = ctx->part->next;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen break;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->part = ctx->part->parent;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ctx->part == NULL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->parse_next_block = preparsed_parse_eof;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic int preparsed_parse_body_finish(struct message_parser_ctx *ctx,
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen struct message_block *block_r)
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen{
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen i_stream_skip(ctx->input, ctx->skip);
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen ctx->skip = 0;
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen preparsed_skip_to_next(ctx);
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen return ctx->parse_next_block(ctx, block_r);
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen}
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainenstatic int preparsed_parse_body_more(struct message_parser_ctx *ctx,
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen struct message_block *block_r)
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen{
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen uoff_t end_offset = ctx->part->physical_pos +
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen ctx->part->header_size.physical_size +
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ctx->part->body_size.physical_size;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen int ret;
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen ret = message_parser_read_more(ctx, block_r);
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen if (ret <= 0)
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen return ret;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen if (ctx->input->v_offset + block_r->size >= end_offset) {
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen block_r->size = end_offset - ctx->input->v_offset;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen ctx->parse_next_block = preparsed_parse_body_finish;
411f318ed3a25fa66c1b932e10df43841e2725c9Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->skip = block_r->size;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainenstatic int preparsed_parse_body_init(struct message_parser_ctx *ctx,
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen struct message_block *block_r)
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen{
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen uoff_t offset = ctx->part->physical_pos +
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen ctx->part->header_size.physical_size;
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen i_assert(offset >= ctx->input->v_offset);
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen i_stream_skip(ctx->input, offset - ctx->input->v_offset);
bd4de9c8152e6ea032c1cb1df8b79635ff5ddf9eTimo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen ctx->parse_next_block = preparsed_parse_body_more;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return preparsed_parse_body_more(ctx, block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_block *block_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen if (ctx->part->children != NULL) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->part = ctx->part->children;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->parse_next_block = preparsed_parse_body_init;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen } else {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen preparsed_skip_to_next(ctx);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen return ctx->parse_next_block(ctx, block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainenstatic int preparsed_parse_next_header(struct message_parser_ctx *ctx,
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen struct message_block *block_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_header_line *hdr;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen size_t size;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen int ret;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (void)i_stream_get_data(ctx->input, &size);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->want_count = size + 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return ret;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (hdr != NULL) {
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen block_r->hdr = hdr;
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen block_r->size = 0;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->parse_next_block = preparsed_parse_finish_header;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* return empty block as end of headers */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->hdr = NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen block_r->size = 0;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct message_block *block_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(ctx->hdr_parser_ctx == NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
cd2cd224d3216a243d55c71c298a5b7684de0ac4Timo Sirainen i_assert(ctx->part->physical_pos >= ctx->input->v_offset);
cd2cd224d3216a243d55c71c298a5b7684de0ac4Timo Sirainen i_stream_skip(ctx->input, ctx->part->physical_pos -
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen ctx->input->v_offset);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->hdr_parser_ctx =
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen message_parse_header_init(ctx->input, NULL, ctx->hdr_flags);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
cd2cd224d3216a243d55c71c298a5b7684de0ac4Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return preparsed_parse_next_header(ctx, block_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstruct message_parser_ctx *
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmessage_parser_init(pool_t part_pool, struct istream *input,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen enum message_header_parser_flags hdr_flags,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen enum message_parser_flags flags)
cd2cd224d3216a243d55c71c298a5b7684de0ac4Timo Sirainen{
ac0fed903142d28ae3a1d5d00d2097fdf161b138Timo Sirainen struct message_parser_ctx *ctx;
ac0fed903142d28ae3a1d5d00d2097fdf161b138Timo Sirainen pool_t pool;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen pool = pool_alloconly_create("Message Parser", 1024);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx = p_new(pool, struct message_parser_ctx, 1);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->parser_pool = pool;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->part_pool = part_pool;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->hdr_flags = hdr_flags;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->flags = flags;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->input = input;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ctx->parts = ctx->part = part_pool == NULL ? NULL :
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen p_new(part_pool, struct message_part, 1);
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen ctx->parse_next_block = parse_next_header_init;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_stream_ref(input);
23fdad6c7e2581921f511e24cd9371c9eaebcef9Timo Sirainen return ctx;
23fdad6c7e2581921f511e24cd9371c9eaebcef9Timo Sirainen}
8552b0cad8ffe9ccb8270577ba28b8010c89af11Timo Sirainen
struct message_parser_ctx *
message_parser_init_from_parts(struct message_part *parts,
struct istream *input,
enum message_header_parser_flags hdr_flags,
enum message_parser_flags flags)
{
struct message_parser_ctx *ctx;
ctx = message_parser_init(NULL, input, hdr_flags, flags);
ctx->parts = ctx->part = parts;
ctx->parse_next_block = preparsed_parse_next_header_init;
return ctx;
}
struct message_part *message_parser_deinit(struct message_parser_ctx **_ctx)
{
struct message_parser_ctx *ctx = *_ctx;
struct message_part *parts = ctx->parts;
*_ctx = NULL;
i_stream_unref(&ctx->input);
pool_unref(&ctx->parser_pool);
return parts;
}
int message_parser_parse_next_block(struct message_parser_ctx *ctx,
struct message_block *block_r)
{
int ret;
bool eof = FALSE;
while ((ret = ctx->parse_next_block(ctx, block_r)) == 0) {
ret = message_parser_read_more(ctx, block_r);
if (ret == 0) {
i_assert(!ctx->input->blocking);
return 0;
}
if (ret == -1) {
i_assert(!eof);
eof = TRUE;
}
}
block_r->part = ctx->part;
if (ret < 0 && ctx->part != NULL) {
i_assert(ctx->input->eof);
while (ctx->part->parent != NULL) {
message_size_add(&ctx->part->parent->body_size,
&ctx->part->body_size);
message_size_add(&ctx->part->parent->body_size,
&ctx->part->header_size);
ctx->part = ctx->part->parent;
}
}
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);
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);
}