267
269
ptr = memchr(block_r->data, '\n', block_r->size);
268
270
if (ptr == NULL) {
269
271
parse_body_add_block(ctx, block_r);
272
if (block_r->size > 0 &&
273
(ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
273
278
/* found the LF */
274
279
block_r->size = (ptr - block_r->data) + 1;
275
280
parse_body_add_block(ctx, block_r);
277
/* a new MIME part begins */
278
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);
282
298
static int parse_part_finish(struct message_parser_ctx *ctx,
296
313
if (boundary->epilogue_found) {
297
314
/* this boundary isn't needed anymore */
298
315
ctx->boundaries = boundary->next;
300
if (ctx->boundaries != NULL)
301
ctx->parse_next_block = parse_next_body_to_boundary;
303
ctx->parse_next_block = parse_next_body_to_eof;
304
return ctx->parse_next_block(ctx, block_r);
317
/* forget about the boundaries we possibly skipped */
318
ctx->boundaries = boundary;
307
/* forget about the boundaries we possibly skipped */
308
ctx->boundaries = boundary;
310
321
/* the boundary itself should already be in buffer. add that. */
311
322
block_r->data = i_stream_get_data(ctx->input, &block_r->size);
312
i_assert(block_r->size >= ctx->skip + 2 + boundary->len +
313
(first_line ? 0 : 1));
323
i_assert(block_r->size >= ctx->skip);
314
324
block_r->data += ctx->skip;
315
/* [\n]--<boundary> */
316
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;
317
338
parse_body_add_block(ctx, block_r);
319
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);
323
347
static int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
586
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;
589
643
ctx->part = ctx->part->parent;
591
645
if (ctx->part == NULL)
602
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);
605
670
static int preparsed_parse_body_more(struct message_parser_ctx *ctx,
606
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;
625
829
static int preparsed_parse_body_init(struct message_parser_ctx *ctx,
626
830
struct message_block *block_r)
636
840
i_stream_skip(ctx->input, offset - ctx->input->v_offset);
638
ctx->parse_next_block = preparsed_parse_body_more;
639
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);
642
873
static int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
643
874
struct message_block *block_r)
645
876
if (ctx->part->children != NULL) {
646
ctx->parse_next_block = preparsed_parse_next_header_init;
647
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;
648
884
} else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
649
885
ctx->parse_next_block = preparsed_parse_body_init;