--- /dev/null
+/* 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;
+}
#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;
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,
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;
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)
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)
{