From: Timo Sirainen Date: Thu, 23 Apr 2020 08:47:18 +0000 (+0300) Subject: lib-mail: Move message_parser_init_from_parts() handling to its own file X-Git-Tag: 2.3.11.2~57 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=06beaf3038c307ef99325efbf683788d59f96df4;p=thirdparty%2Fdovecot%2Fcore.git lib-mail: Move message_parser_init_from_parts() handling to its own file This helps to see what code they have in common. --- diff --git a/src/lib-mail/Makefile.am b/src/lib-mail/Makefile.am index 8fe43d69d0..57d9e2b8c4 100644 --- a/src/lib-mail/Makefile.am +++ b/src/lib-mail/Makefile.am @@ -28,6 +28,7 @@ libmail_la_SOURCES = \ message-header-parser.c \ message-id.c \ message-parser.c \ + message-parser-from-parts.c \ message-part.c \ message-part-data.c \ message-part-serialize.c \ @@ -42,7 +43,8 @@ libmail_la_SOURCES = \ rfc822-parser.c noinst_HEADERS = \ - html-entities.h + html-entities.h \ + message-parser-private.h headers = \ istream-attachment-connector.h \ diff --git a/src/lib-mail/message-parser-from-parts.c b/src/lib-mail/message-parser-from-parts.c new file mode 100644 index 0000000000..b23055ab9b --- /dev/null +++ b/src/lib-mail/message-parser-from-parts.c @@ -0,0 +1,366 @@ +/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "istream.h" +#include "message-parser-private.h" + +static int preparsed_parse_epilogue_init(struct message_parser_ctx *ctx, + struct message_block *block_r); +static int preparsed_parse_next_header_init(struct message_parser_ctx *ctx, + struct message_block *block_r); + +static int preparsed_parse_eof(struct message_parser_ctx *ctx ATTR_UNUSED, + struct message_block *block_r ATTR_UNUSED) +{ + return -1; +} + +static void preparsed_skip_to_next(struct message_parser_ctx *ctx) +{ + ctx->parse_next_block = preparsed_parse_next_header_init; + while (ctx->part != NULL) { + if (ctx->part->next != NULL) { + ctx->part = ctx->part->next; + break; + } + + /* parse epilogue of multipart parent if requested */ + if (ctx->part->parent != NULL && + (ctx->part->parent->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 && + (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) != 0) { + /* check for presence of epilogue */ + uoff_t part_end = ctx->part->physical_pos + + ctx->part->header_size.physical_size + + ctx->part->body_size.physical_size; + uoff_t parent_end = ctx->part->parent->physical_pos + + ctx->part->parent->header_size.physical_size + + ctx->part->parent->body_size.physical_size; + + if (parent_end > part_end) { + ctx->parse_next_block = preparsed_parse_epilogue_init; + break; + } + } + ctx->part = ctx->part->parent; + } + if (ctx->part == NULL) + ctx->parse_next_block = preparsed_parse_eof; +} + +static int preparsed_parse_body_finish(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + i_stream_skip(ctx->input, ctx->skip); + ctx->skip = 0; + + preparsed_skip_to_next(ctx); + return ctx->parse_next_block(ctx, block_r); +} + +static int preparsed_parse_prologue_finish(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + i_stream_skip(ctx->input, ctx->skip); + ctx->skip = 0; + + ctx->parse_next_block = preparsed_parse_next_header_init; + ctx->part = ctx->part->children; + return ctx->parse_next_block(ctx, block_r); +} + +static int preparsed_parse_body_more(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + uoff_t end_offset = ctx->part->physical_pos + + ctx->part->header_size.physical_size + + ctx->part->body_size.physical_size; + bool full; + int ret; + + if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) + return ret; + + if (ctx->input->v_offset + block_r->size >= end_offset) { + block_r->size = end_offset - ctx->input->v_offset; + ctx->parse_next_block = preparsed_parse_body_finish; + } + ctx->skip = block_r->size; + return 1; +} + +static int preparsed_parse_prologue_more(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + uoff_t boundary_min_start, end_offset; + const unsigned char *cur; + bool full; + int ret; + + i_assert(ctx->part->children != NULL); + end_offset = ctx->part->children->physical_pos; + + if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) + return ret; + + if (ctx->input->v_offset + block_r->size >= end_offset) { + /* we've got the full prologue: clip off the initial boundary */ + block_r->size = end_offset - ctx->input->v_offset; + cur = block_r->data + block_r->size - 1; + + /* [\r]\n--boundary[\r]\n */ + if (block_r->size < 5 || *cur != '\n') { + ctx->broken_reason = "Prologue boundary end not at expected position"; + return -1; + } + + cur--; + if (*cur == '\r') cur--; + + /* find newline just before boundary */ + for (; cur >= block_r->data; cur--) { + if (*cur == '\n') break; + } + + if (cur[0] != '\n' || cur[1] != '-' || cur[2] != '-') { + ctx->broken_reason = "Prologue boundary beginning not at expected position"; + return -1; + } + + if (cur != block_r->data && cur[-1] == '\r') cur--; + + /* clip boundary */ + block_r->size = cur - block_r->data; + + ctx->parse_next_block = preparsed_parse_prologue_finish; + ctx->skip = block_r->size; + return 1; + } + + /* retain enough data in the stream buffer to contain initial boundary */ + if (end_offset > BOUNDARY_END_MAX_LEN) + boundary_min_start = end_offset - BOUNDARY_END_MAX_LEN; + else + boundary_min_start = 0; + + if (ctx->input->v_offset + block_r->size >= boundary_min_start) { + if (boundary_min_start <= ctx->input->v_offset) + return 0; + block_r->size = boundary_min_start - ctx->input->v_offset; + } + ctx->skip = block_r->size; + return 1; +} + +static int preparsed_parse_epilogue_more(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + uoff_t end_offset = ctx->part->physical_pos + + ctx->part->header_size.physical_size + + ctx->part->body_size.physical_size; + bool full; + int ret; + + if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) + return ret; + + if (ctx->input->v_offset + block_r->size >= end_offset) { + block_r->size = end_offset - ctx->input->v_offset; + ctx->parse_next_block = preparsed_parse_body_finish; + } + ctx->skip = block_r->size; + return 1; +} + +static int preparsed_parse_epilogue_boundary(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + uoff_t end_offset = ctx->part->physical_pos + + ctx->part->header_size.physical_size + + ctx->part->body_size.physical_size; + const unsigned char *data, *cur; + size_t size; + bool full; + int ret; + + if (end_offset - ctx->input->v_offset < 7) { + ctx->broken_reason = "Epilogue position is wrong"; + return -1; + } + + if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) + return ret; + + /* [\r]\n--boundary--[\r]\n */ + if (block_r->size < 7) { + ctx->want_count = 7; + return 0; + } + + data = block_r->data; + size = block_r->size; + cur = data; + + if (*cur == '\r') cur++; + + if (cur[0] != '\n' || cur[1] != '-' || data[2] != '-') { + ctx->broken_reason = "Epilogue boundary start not at expected position"; + return -1; + } + + /* find the end of the line */ + cur += 3; + if ((cur = memchr(cur, '\n', size - (cur-data))) == NULL) { + if (end_offset < ctx->input->v_offset + size) { + ctx->broken_reason = "Epilogue boundary end not at expected position"; + return -1; + } else if (ctx->input->v_offset + size < end_offset && + size < BOUNDARY_END_MAX_LEN && + !ctx->input->eof && !full) { + ctx->want_count = BOUNDARY_END_MAX_LEN; + return 0; + } + } + + block_r->size = 0; + ctx->parse_next_block = preparsed_parse_epilogue_more; + ctx->skip = cur - data + 1; + return 0; +} + +static int preparsed_parse_body_init(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + uoff_t offset = ctx->part->physical_pos + + ctx->part->header_size.physical_size; + + if (offset < ctx->input->v_offset) { + /* header was actually larger than the cached size suggested */ + ctx->broken_reason = "Header larger than its cached size"; + return -1; + } + i_stream_skip(ctx->input, offset - ctx->input->v_offset); + + /* multipart messages may begin with --boundary--, which makes them + not have any children. */ + if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 || + ctx->part->children == NULL) + ctx->parse_next_block = preparsed_parse_body_more; + else + ctx->parse_next_block = preparsed_parse_prologue_more; + return ctx->parse_next_block(ctx, block_r); +} + +static int preparsed_parse_epilogue_init(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + uoff_t offset = ctx->part->physical_pos + + ctx->part->header_size.physical_size + + ctx->part->body_size.physical_size; + + ctx->part = ctx->part->parent; + + if (offset < ctx->input->v_offset) { + /* last child was actually larger than the cached size + suggested */ + ctx->broken_reason = "Part larger than its cached size"; + return -1; + } + i_stream_skip(ctx->input, offset - ctx->input->v_offset); + + ctx->parse_next_block = preparsed_parse_epilogue_boundary; + return ctx->parse_next_block(ctx, block_r); +} + +static int preparsed_parse_finish_header(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + if (ctx->part->children != NULL) { + if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 && + (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) != 0) + ctx->parse_next_block = preparsed_parse_body_init; + else { + ctx->parse_next_block = preparsed_parse_next_header_init; + ctx->part = ctx->part->children; + } + } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) { + ctx->parse_next_block = preparsed_parse_body_init; + } else { + preparsed_skip_to_next(ctx); + } + return ctx->parse_next_block(ctx, block_r); +} + +static int preparsed_parse_next_header(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + struct message_header_line *hdr; + int ret; + + ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr); + if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) { + ctx->want_count = i_stream_get_data_size(ctx->input) + 1; + return ret; + } + + if (hdr != NULL) { + block_r->hdr = hdr; + block_r->size = 0; + return 1; + } + message_parse_header_deinit(&ctx->hdr_parser_ctx); + + ctx->parse_next_block = preparsed_parse_finish_header; + + /* return empty block as end of headers */ + block_r->hdr = NULL; + block_r->size = 0; + + i_assert(ctx->skip == 0); + if (ctx->input->v_offset != ctx->part->physical_pos + + ctx->part->header_size.physical_size) { + ctx->broken_reason = "Cached header size mismatch"; + return -1; + } + return 1; +} + +static int preparsed_parse_next_header_init(struct message_parser_ctx *ctx, + struct message_block *block_r) +{ + struct istream *hdr_input; + + i_assert(ctx->hdr_parser_ctx == NULL); + + i_assert(ctx->part->physical_pos >= ctx->input->v_offset); + i_stream_skip(ctx->input, ctx->part->physical_pos - + ctx->input->v_offset); + + /* the header may become truncated by --boundaries. limit the header + stream's size to what it's supposed to be to avoid duplicating (and + keeping in sync!) all the same complicated logic as in + parse_next_header(). */ + hdr_input = i_stream_create_limit(ctx->input, ctx->part->header_size.physical_size); + ctx->hdr_parser_ctx = + message_parse_header_init(hdr_input, NULL, ctx->hdr_flags); + i_stream_unref(&hdr_input); + + ctx->parse_next_block = preparsed_parse_next_header; + return preparsed_parse_next_header(ctx, block_r); +} + +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; + + i_assert(parts != NULL); + + ctx = message_parser_init_int(input, hdr_flags, flags); + ctx->preparsed = TRUE; + ctx->parts = ctx->part = parts; + ctx->parse_next_block = preparsed_parse_next_header_init; + return ctx; +} diff --git a/src/lib-mail/message-parser-private.h b/src/lib-mail/message-parser-private.h new file mode 100644 index 0000000000..98a576eda4 --- /dev/null +++ b/src/lib-mail/message-parser-private.h @@ -0,0 +1,55 @@ +#ifndef MESSAGE_PARSER_PRIVATE_H +#define MESSAGE_PARSER_PRIVATE_H + +#include "message-parser.h" + +/* RFC-2046 requires boundaries are max. 70 chars + "--" prefix + "--" suffix. + We'll add a bit more just in case. */ +#define BOUNDARY_END_MAX_LEN (70 + 2 + 2 + 10) + +struct message_boundary { + struct message_boundary *next; + + struct message_part *part; + const char *boundary; + size_t len; + + bool epilogue_found:1; +}; + +struct message_parser_ctx { + pool_t parser_pool, part_pool; + struct istream *input; + struct message_part *parts, *part; + const char *broken_reason; + + enum message_header_parser_flags hdr_flags; + enum message_parser_flags flags; + + const char *last_boundary; + struct message_boundary *boundaries; + + size_t skip; + char last_chr; + unsigned int want_count; + + struct message_header_parser_ctx *hdr_parser_ctx; + unsigned int prev_hdr_newline_size; + + int (*parse_next_block)(struct message_parser_ctx *ctx, + struct message_block *block_r); + + bool part_seen_content_type:1; + bool multipart:1; + bool preparsed:1; + bool eof:1; +}; + +struct message_parser_ctx * +message_parser_init_int(struct istream *input, + enum message_header_parser_flags hdr_flags, + enum message_parser_flags flags); +int message_parser_read_more(struct message_parser_ctx *ctx, + struct message_block *block_r, bool *full_r); + +#endif diff --git a/src/lib-mail/message-parser.c b/src/lib-mail/message-parser.c index e7a4f4cc31..653f964118 100644 --- a/src/lib-mail/message-parser.c +++ b/src/lib-mail/message-parser.c @@ -6,49 +6,7 @@ #include "istream.h" #include "rfc822-parser.h" #include "rfc2231-parser.h" -#include "message-parser.h" - -/* RFC-2046 requires boundaries are max. 70 chars + "--" prefix + "--" suffix. - We'll add a bit more just in case. */ -#define BOUNDARY_END_MAX_LEN (70 + 2 + 2 + 10) - -struct message_boundary { - struct message_boundary *next; - - struct message_part *part; - const char *boundary; - size_t len; - - bool epilogue_found:1; -}; - -struct message_parser_ctx { - pool_t parser_pool, part_pool; - struct istream *input; - struct message_part *parts, *part; - const char *broken_reason; - - enum message_header_parser_flags hdr_flags; - enum message_parser_flags flags; - - const char *last_boundary; - struct message_boundary *boundaries; - - size_t skip; - char last_chr; - unsigned int want_count; - - struct message_header_parser_ctx *hdr_parser_ctx; - unsigned int prev_hdr_newline_size; - - int (*parse_next_block)(struct message_parser_ctx *ctx, - struct message_block *block_r); - - bool part_seen_content_type:1; - bool multipart:1; - bool preparsed:1; - bool eof:1; -}; +#include "message-parser-private.h" message_part_header_callback_t *null_message_part_header_callback = NULL; @@ -58,10 +16,6 @@ static int parse_next_body_to_boundary(struct message_parser_ctx *ctx, struct message_block *block_r); static int parse_next_body_to_eof(struct message_parser_ctx *ctx, struct message_block *block_r); -static int preparsed_parse_epilogue_init(struct message_parser_ctx *ctx, - struct message_block *block_r); -static int preparsed_parse_next_header_init(struct message_parser_ctx *ctx, - struct message_block *block_r); static struct message_boundary * boundary_find(struct message_boundary *boundaries, @@ -122,8 +76,8 @@ static void parse_body_add_block(struct message_parser_ctx *ctx, ctx->part->body_size.virtual_size += block->size + missing_cr_count; } -static int message_parser_read_more(struct message_parser_ctx *ctx, - struct message_block *block_r, bool *full_r) +int message_parser_read_more(struct message_parser_ctx *ctx, + struct message_block *block_r, bool *full_r) { int ret; @@ -692,346 +646,7 @@ static int parse_next_header_init(struct message_parser_ctx *ctx, return parse_next_header(ctx, block_r); } -static int preparsed_parse_eof(struct message_parser_ctx *ctx ATTR_UNUSED, - struct message_block *block_r ATTR_UNUSED) -{ - return -1; -} - -static void preparsed_skip_to_next(struct message_parser_ctx *ctx) -{ - ctx->parse_next_block = preparsed_parse_next_header_init; - while (ctx->part != NULL) { - if (ctx->part->next != NULL) { - ctx->part = ctx->part->next; - break; - } - - /* parse epilogue of multipart parent if requested */ - if (ctx->part->parent != NULL && - (ctx->part->parent->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 && - (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) != 0) { - /* check for presence of epilogue */ - uoff_t part_end = ctx->part->physical_pos + - ctx->part->header_size.physical_size + - ctx->part->body_size.physical_size; - uoff_t parent_end = ctx->part->parent->physical_pos + - ctx->part->parent->header_size.physical_size + - ctx->part->parent->body_size.physical_size; - - if (parent_end > part_end) { - ctx->parse_next_block = preparsed_parse_epilogue_init; - break; - } - } - ctx->part = ctx->part->parent; - } - if (ctx->part == NULL) - ctx->parse_next_block = preparsed_parse_eof; -} - -static int preparsed_parse_body_finish(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - i_stream_skip(ctx->input, ctx->skip); - ctx->skip = 0; - - preparsed_skip_to_next(ctx); - return ctx->parse_next_block(ctx, block_r); -} - -static int preparsed_parse_prologue_finish(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - i_stream_skip(ctx->input, ctx->skip); - ctx->skip = 0; - - ctx->parse_next_block = preparsed_parse_next_header_init; - ctx->part = ctx->part->children; - return ctx->parse_next_block(ctx, block_r); -} - -static int preparsed_parse_body_more(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - uoff_t end_offset = ctx->part->physical_pos + - ctx->part->header_size.physical_size + - ctx->part->body_size.physical_size; - bool full; - int ret; - - if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) - return ret; - - if (ctx->input->v_offset + block_r->size >= end_offset) { - block_r->size = end_offset - ctx->input->v_offset; - ctx->parse_next_block = preparsed_parse_body_finish; - } - ctx->skip = block_r->size; - return 1; -} - -static int preparsed_parse_prologue_more(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - uoff_t boundary_min_start, end_offset; - const unsigned char *cur; - bool full; - int ret; - - i_assert(ctx->part->children != NULL); - end_offset = ctx->part->children->physical_pos; - - if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) - return ret; - - if (ctx->input->v_offset + block_r->size >= end_offset) { - /* we've got the full prologue: clip off the initial boundary */ - block_r->size = end_offset - ctx->input->v_offset; - cur = block_r->data + block_r->size - 1; - - /* [\r]\n--boundary[\r]\n */ - if (block_r->size < 5 || *cur != '\n') { - ctx->broken_reason = "Prologue boundary end not at expected position"; - return -1; - } - - cur--; - if (*cur == '\r') cur--; - - /* find newline just before boundary */ - for (; cur >= block_r->data; cur--) { - if (*cur == '\n') break; - } - - if (cur[0] != '\n' || cur[1] != '-' || cur[2] != '-') { - ctx->broken_reason = "Prologue boundary beginning not at expected position"; - return -1; - } - - if (cur != block_r->data && cur[-1] == '\r') cur--; - - /* clip boundary */ - block_r->size = cur - block_r->data; - - ctx->parse_next_block = preparsed_parse_prologue_finish; - ctx->skip = block_r->size; - return 1; - } - - /* retain enough data in the stream buffer to contain initial boundary */ - if (end_offset > BOUNDARY_END_MAX_LEN) - boundary_min_start = end_offset - BOUNDARY_END_MAX_LEN; - else - boundary_min_start = 0; - - if (ctx->input->v_offset + block_r->size >= boundary_min_start) { - if (boundary_min_start <= ctx->input->v_offset) - return 0; - block_r->size = boundary_min_start - ctx->input->v_offset; - } - ctx->skip = block_r->size; - return 1; -} - -static int preparsed_parse_epilogue_more(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - uoff_t end_offset = ctx->part->physical_pos + - ctx->part->header_size.physical_size + - ctx->part->body_size.physical_size; - bool full; - int ret; - - if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) - return ret; - - if (ctx->input->v_offset + block_r->size >= end_offset) { - block_r->size = end_offset - ctx->input->v_offset; - ctx->parse_next_block = preparsed_parse_body_finish; - } - ctx->skip = block_r->size; - return 1; -} - -static int preparsed_parse_epilogue_boundary(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - uoff_t end_offset = ctx->part->physical_pos + - ctx->part->header_size.physical_size + - ctx->part->body_size.physical_size; - const unsigned char *data, *cur; - size_t size; - bool full; - int ret; - - if (end_offset - ctx->input->v_offset < 7) { - ctx->broken_reason = "Epilogue position is wrong"; - return -1; - } - - if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) - return ret; - - /* [\r]\n--boundary--[\r]\n */ - if (block_r->size < 7) { - ctx->want_count = 7; - return 0; - } - - data = block_r->data; - size = block_r->size; - cur = data; - - if (*cur == '\r') cur++; - - if (cur[0] != '\n' || cur[1] != '-' || data[2] != '-') { - ctx->broken_reason = "Epilogue boundary start not at expected position"; - return -1; - } - - /* find the end of the line */ - cur += 3; - if ((cur = memchr(cur, '\n', size - (cur-data))) == NULL) { - if (end_offset < ctx->input->v_offset + size) { - ctx->broken_reason = "Epilogue boundary end not at expected position"; - return -1; - } else if (ctx->input->v_offset + size < end_offset && - size < BOUNDARY_END_MAX_LEN && - !ctx->input->eof && !full) { - ctx->want_count = BOUNDARY_END_MAX_LEN; - return 0; - } - } - - block_r->size = 0; - ctx->parse_next_block = preparsed_parse_epilogue_more; - ctx->skip = cur - data + 1; - return 0; -} - -static int preparsed_parse_body_init(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - uoff_t offset = ctx->part->physical_pos + - ctx->part->header_size.physical_size; - - if (offset < ctx->input->v_offset) { - /* header was actually larger than the cached size suggested */ - ctx->broken_reason = "Header larger than its cached size"; - return -1; - } - i_stream_skip(ctx->input, offset - ctx->input->v_offset); - - /* multipart messages may begin with --boundary--, which makes them - not have any children. */ - if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 || - ctx->part->children == NULL) - ctx->parse_next_block = preparsed_parse_body_more; - else - ctx->parse_next_block = preparsed_parse_prologue_more; - return ctx->parse_next_block(ctx, block_r); -} - -static int preparsed_parse_epilogue_init(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - uoff_t offset = ctx->part->physical_pos + - ctx->part->header_size.physical_size + - ctx->part->body_size.physical_size; - - ctx->part = ctx->part->parent; - - if (offset < ctx->input->v_offset) { - /* last child was actually larger than the cached size - suggested */ - ctx->broken_reason = "Part larger than its cached size"; - return -1; - } - i_stream_skip(ctx->input, offset - ctx->input->v_offset); - - ctx->parse_next_block = preparsed_parse_epilogue_boundary; - return ctx->parse_next_block(ctx, block_r); -} - -static int preparsed_parse_finish_header(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - if (ctx->part->children != NULL) { - if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 && - (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) != 0) - ctx->parse_next_block = preparsed_parse_body_init; - else { - ctx->parse_next_block = preparsed_parse_next_header_init; - ctx->part = ctx->part->children; - } - } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) { - ctx->parse_next_block = preparsed_parse_body_init; - } else { - preparsed_skip_to_next(ctx); - } - return ctx->parse_next_block(ctx, block_r); -} - -static int preparsed_parse_next_header(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - struct message_header_line *hdr; - int ret; - - ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr); - if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) { - ctx->want_count = i_stream_get_data_size(ctx->input) + 1; - return ret; - } - - if (hdr != NULL) { - block_r->hdr = hdr; - block_r->size = 0; - return 1; - } - message_parse_header_deinit(&ctx->hdr_parser_ctx); - - ctx->parse_next_block = preparsed_parse_finish_header; - - /* return empty block as end of headers */ - block_r->hdr = NULL; - block_r->size = 0; - - i_assert(ctx->skip == 0); - if (ctx->input->v_offset != ctx->part->physical_pos + - ctx->part->header_size.physical_size) { - ctx->broken_reason = "Cached header size mismatch"; - return -1; - } - return 1; -} - -static int preparsed_parse_next_header_init(struct message_parser_ctx *ctx, - struct message_block *block_r) -{ - struct istream *hdr_input; - - i_assert(ctx->hdr_parser_ctx == NULL); - - i_assert(ctx->part->physical_pos >= ctx->input->v_offset); - i_stream_skip(ctx->input, ctx->part->physical_pos - - ctx->input->v_offset); - - /* the header may become truncated by --boundaries. limit the header - stream's size to what it's supposed to be to avoid duplicating (and - keeping in sync!) all the same complicated logic as in - parse_next_header(). */ - hdr_input = i_stream_create_limit(ctx->input, ctx->part->header_size.physical_size); - ctx->hdr_parser_ctx = - message_parse_header_init(hdr_input, NULL, ctx->hdr_flags); - i_stream_unref(&hdr_input); - - ctx->parse_next_block = preparsed_parse_next_header; - return preparsed_parse_next_header(ctx, block_r); -} - -static struct message_parser_ctx * +struct message_parser_ctx * message_parser_init_int(struct istream *input, enum message_header_parser_flags hdr_flags, enum message_parser_flags flags) @@ -1063,23 +678,6 @@ message_parser_init(pool_t part_pool, struct istream *input, return ctx; } -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; - - i_assert(parts != NULL); - - ctx = message_parser_init_int(input, hdr_flags, flags); - ctx->preparsed = TRUE; - ctx->parts = ctx->part = parts; - ctx->parse_next_block = preparsed_parse_next_header_init; - return ctx; -} - void message_parser_deinit(struct message_parser_ctx **_ctx, struct message_part **parts_r) {