264
269
ptr = memchr(block_r->data, '\n', block_r->size);
265
270
if (ptr == NULL) {
266
271
parse_body_add_block(ctx, block_r);
272
if (block_r->size > 0 &&
273
(ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
270
278
/* found the LF */
271
279
block_r->size = (ptr - block_r->data) + 1;
272
280
parse_body_add_block(ctx, block_r);
274
/* a new MIME part begins */
275
ctx->parse_next_block = parse_next_mime_header_init;
282
if (ctx->boundaries == NULL || ctx->boundaries->part != ctx->part) {
284
if (ctx->boundaries != NULL)
285
ctx->parse_next_block = parse_next_body_to_boundary;
287
ctx->parse_next_block = parse_next_body_to_eof;
289
/* a new MIME part begins */
290
ctx->parse_next_block = parse_next_mime_header_init;
292
if (block_r->size > 0 &&
293
(ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
295
return ctx->parse_next_block(ctx, block_r);
279
298
static int parse_part_finish(struct message_parser_ctx *ctx,
293
313
if (boundary->epilogue_found) {
294
314
/* this boundary isn't needed anymore */
295
315
ctx->boundaries = boundary->next;
297
if (ctx->boundaries != NULL)
298
ctx->parse_next_block = parse_next_body_to_boundary;
300
ctx->parse_next_block = parse_next_body_to_eof;
301
return ctx->parse_next_block(ctx, block_r);
317
/* forget about the boundaries we possibly skipped */
318
ctx->boundaries = boundary;
304
/* forget about the boundaries we possibly skipped */
305
ctx->boundaries = boundary;
307
321
/* the boundary itself should already be in buffer. add that. */
308
322
block_r->data = i_stream_get_data(ctx->input, &block_r->size);
309
i_assert(block_r->size >= ctx->skip + 2 + boundary->len +
310
(first_line ? 0 : 1));
323
i_assert(block_r->size >= ctx->skip);
311
324
block_r->data += ctx->skip;
312
/* [\n]--<boundary> */
313
block_r->size = (first_line ? 0 : 1) + 2 + boundary->len;
325
/* [[\r]\n]--<boundary>[--] */
328
else if (block_r->data[0] == '\r') {
329
i_assert(block_r->data[1] == '\n');
332
i_assert(block_r->data[0] == '\n');
335
line_size += 2 + boundary->len + (boundary->epilogue_found ? 2 : 0);
336
i_assert(block_r->size >= ctx->skip + line_size);
337
block_r->size = line_size;
314
338
parse_body_add_block(ctx, block_r);
316
340
ctx->parse_next_block = parse_next_body_skip_boundary_line;
342
if ((ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
344
return ctx->parse_next_block(ctx, block_r);
320
347
static int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
583
622
ctx->part = ctx->part->next;
626
/* parse epilogue of multipart parent if requested */
627
if (ctx->part->parent != NULL &&
628
(ctx->part->parent->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
629
(ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) != 0) {
630
/* check for presence of epilogue */
631
uoff_t part_end = ctx->part->physical_pos +
632
ctx->part->header_size.physical_size +
633
ctx->part->body_size.physical_size;
634
uoff_t parent_end = ctx->part->parent->physical_pos +
635
ctx->part->parent->header_size.physical_size +
636
ctx->part->parent->body_size.physical_size;
638
if (parent_end > part_end) {
639
ctx->parse_next_block = preparsed_parse_epilogue_init;
586
643
ctx->part = ctx->part->parent;
588
645
if (ctx->part == NULL)
599
656
return ctx->parse_next_block(ctx, block_r);
659
static int preparsed_parse_prologue_finish(struct message_parser_ctx *ctx,
660
struct message_block *block_r)
662
i_stream_skip(ctx->input, ctx->skip);
665
ctx->parse_next_block = preparsed_parse_next_header_init;
666
ctx->part = ctx->part->children;
667
return ctx->parse_next_block(ctx, block_r);
602
670
static int preparsed_parse_body_more(struct message_parser_ctx *ctx,
603
671
struct message_block *block_r)
690
static int preparsed_parse_prologue_more(struct message_parser_ctx *ctx,
691
struct message_block *block_r)
693
uoff_t boundary_min_start, end_offset;
694
const unsigned char *cur;
698
i_assert(ctx->part->children != NULL);
699
end_offset = ctx->part->children->physical_pos;
701
if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
704
if (ctx->input->v_offset + block_r->size >= end_offset) {
705
/* we've got the full prologue: clip off the initial boundary */
706
block_r->size = end_offset - ctx->input->v_offset;
707
cur = block_r->data + block_r->size - 1;
709
/* [\r]\n--boundary[\r]\n */
710
if (block_r->size < 5 || *cur != '\n') {
716
if (*cur == '\r') cur--;
718
/* find newline just before boundary */
719
for (; cur >= block_r->data; cur--) {
720
if (*cur == '\n') break;
723
if (cur[0] != '\n' || cur[1] != '-' || cur[2] != '-') {
728
if (cur != block_r->data && cur[-1] == '\r') cur--;
731
block_r->size = cur - block_r->data;
733
ctx->parse_next_block = preparsed_parse_prologue_finish;
734
ctx->skip = block_r->size;
738
/* retain enough data in the stream buffer to contain initial boundary */
739
if (end_offset > BOUNDARY_END_MAX_LEN)
740
boundary_min_start = end_offset - BOUNDARY_END_MAX_LEN;
742
boundary_min_start = 0;
744
if (ctx->input->v_offset + block_r->size >= boundary_min_start) {
745
if (boundary_min_start <= ctx->input->v_offset)
747
block_r->size = boundary_min_start - ctx->input->v_offset;
749
ctx->skip = block_r->size;
753
static int preparsed_parse_epilogue_more(struct message_parser_ctx *ctx,
754
struct message_block *block_r)
756
uoff_t end_offset = ctx->part->physical_pos +
757
ctx->part->header_size.physical_size +
758
ctx->part->body_size.physical_size;
762
if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
765
if (ctx->input->v_offset + block_r->size >= end_offset) {
766
block_r->size = end_offset - ctx->input->v_offset;
767
ctx->parse_next_block = preparsed_parse_body_finish;
769
ctx->skip = block_r->size;
773
static int preparsed_parse_epilogue_boundary(struct message_parser_ctx *ctx,
774
struct message_block *block_r)
776
uoff_t end_offset = ctx->part->physical_pos +
777
ctx->part->header_size.physical_size +
778
ctx->part->body_size.physical_size;
779
const unsigned char *data, *cur;
784
if (end_offset - ctx->input->v_offset < 7) {
789
if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
792
/* [\r]\n--boundary--[\r]\n */
793
if (block_r->size < 7) {
798
data = block_r->data;
799
size = block_r->size;
802
if (*cur == '\r') cur++;
804
if (cur[0] != '\n' || cur[1] != '-' || data[2] != '-') {
809
/* find the end of the line */
811
if ((cur = memchr(cur, '\n', size - (cur-data))) == NULL) {
812
if (end_offset < ctx->input->v_offset + size) {
815
} else if (ctx->input->v_offset + size < end_offset &&
816
size < BOUNDARY_END_MAX_LEN &&
817
!ctx->input->eof && !full) {
818
ctx->want_count = BOUNDARY_END_MAX_LEN;
824
ctx->parse_next_block = preparsed_parse_epilogue_more;
825
ctx->skip = cur - data + 1;
622
829
static int preparsed_parse_body_init(struct message_parser_ctx *ctx,
623
830
struct message_block *block_r)
633
840
i_stream_skip(ctx->input, offset - ctx->input->v_offset);
635
ctx->parse_next_block = preparsed_parse_body_more;
636
return preparsed_parse_body_more(ctx, block_r);
842
/* multipart messages may begin with --boundary--, which makes them
843
not have any children. */
844
if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
845
ctx->part->children == NULL)
846
ctx->parse_next_block = preparsed_parse_body_more;
848
ctx->parse_next_block = preparsed_parse_prologue_more;
849
return ctx->parse_next_block(ctx, block_r);
852
static int preparsed_parse_epilogue_init(struct message_parser_ctx *ctx,
853
struct message_block *block_r)
855
uoff_t offset = ctx->part->physical_pos +
856
ctx->part->header_size.physical_size +
857
ctx->part->body_size.physical_size;
859
ctx->part = ctx->part->parent;
861
if (offset < ctx->input->v_offset) {
862
/* last child was actually larger than the cached size
867
i_stream_skip(ctx->input, offset - ctx->input->v_offset);
869
ctx->parse_next_block = preparsed_parse_epilogue_boundary;
870
return ctx->parse_next_block(ctx, block_r);
639
873
static int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
640
874
struct message_block *block_r)
642
876
if (ctx->part->children != NULL) {
643
ctx->parse_next_block = preparsed_parse_next_header_init;
644
ctx->part = ctx->part->children;
877
if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
878
(ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) != 0)
879
ctx->parse_next_block = preparsed_parse_body_init;
881
ctx->parse_next_block = preparsed_parse_next_header_init;
882
ctx->part = ctx->part->children;
645
884
} else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
646
885
ctx->parse_next_block = preparsed_parse_body_init;