~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to src/lib-mail/message-parser.c

  • Committer: Package Import Robot
  • Author(s): Jaldhar H. Vyas
  • Date: 2013-09-09 00:57:32 UTC
  • mfrom: (1.13.11)
  • mto: (4.8.5 experimental) (1.16.1)
  • mto: This revision was merged to the branch mainline in revision 97.
  • Revision ID: package-import@ubuntu.com-20130909005732-dn1eell8srqbhh0e
Tags: upstream-2.2.5
ImportĀ upstreamĀ versionĀ 2.2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
4
4
#include "str.h"
54
54
                                       struct message_block *block_r);
55
55
static int parse_next_body_to_eof(struct message_parser_ctx *ctx,
56
56
                                  struct message_block *block_r);
 
57
static int preparsed_parse_epilogue_init(struct message_parser_ctx *ctx,
 
58
                                         struct message_block *block_r);
57
59
static int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
58
60
                                            struct message_block *block_r);
59
61
 
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);
270
 
                return 1;
 
272
                if (block_r->size > 0 &&
 
273
                    (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
 
274
                        return 1;
 
275
                return 0;
271
276
        }
272
277
 
273
278
        /* found the LF */
274
279
        block_r->size = (ptr - block_r->data) + 1;
275
280
        parse_body_add_block(ctx, block_r);
276
281
 
277
 
        /* a new MIME part begins */
278
 
        ctx->parse_next_block = parse_next_mime_header_init;
279
 
        return 1;
 
282
        if (ctx->boundaries == NULL || ctx->boundaries->part != ctx->part) {
 
283
                /* epilogue */
 
284
                if (ctx->boundaries != NULL)
 
285
                        ctx->parse_next_block = parse_next_body_to_boundary;
 
286
                else
 
287
                        ctx->parse_next_block = parse_next_body_to_eof;
 
288
        } else {
 
289
                /* a new MIME part begins */
 
290
                ctx->parse_next_block = parse_next_mime_header_init;
 
291
        }
 
292
        if (block_r->size > 0 &&
 
293
            (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
 
294
                return 1;
 
295
        return ctx->parse_next_block(ctx, block_r);
280
296
}
281
297
 
282
298
static int parse_part_finish(struct message_parser_ctx *ctx,
284
300
                             struct message_block *block_r, bool first_line)
285
301
{
286
302
        struct message_part *part;
 
303
        size_t line_size;
287
304
 
288
305
        /* get back to parent MIME part, summing the child MIME part sizes
289
306
           into parent's body sizes */
296
313
        if (boundary->epilogue_found) {
297
314
                /* this boundary isn't needed anymore */
298
315
                ctx->boundaries = boundary->next;
299
 
 
300
 
                if (ctx->boundaries != NULL)
301
 
                        ctx->parse_next_block = parse_next_body_to_boundary;
302
 
                else
303
 
                        ctx->parse_next_block = parse_next_body_to_eof;
304
 
                return ctx->parse_next_block(ctx, block_r);
 
316
        } else {
 
317
                /* forget about the boundaries we possibly skipped */
 
318
                ctx->boundaries = boundary;
305
319
        }
306
320
 
307
 
        /* forget about the boundaries we possibly skipped */
308
 
        ctx->boundaries = boundary;
309
 
 
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>[--] */
 
326
        if (first_line)
 
327
                line_size = 0;
 
328
        else if (block_r->data[0] == '\r') {
 
329
                i_assert(block_r->data[1] == '\n');
 
330
                line_size = 2;
 
331
        } else {
 
332
                i_assert(block_r->data[0] == '\n');
 
333
                line_size = 1;
 
334
        }
 
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);
318
339
 
319
340
        ctx->parse_next_block = parse_next_body_skip_boundary_line;
320
 
        return 1;
 
341
 
 
342
        if ((ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
 
343
                return 1;
 
344
        return ctx->parse_next_block(ctx, block_r);
321
345
}
322
346
 
323
347
static int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
379
403
        } else if (boundary_start == 0) {
380
404
                /* no linefeeds in this block. we can just skip it. */
381
405
                ret = 0;
 
406
                if (block_r->data[block_r->size-1] == '\r') {
 
407
                        /* this may be the beginning of the \r\n--boundary */
 
408
                        block_r->size--;
 
409
                }
382
410
                boundary_start = block_r->size;
383
411
        } else {
384
412
                /* the boundary wasn't found from this data block,
395
423
        }
396
424
        if (block_r->size != 0) {
397
425
                parse_body_add_block(ctx, block_r);
 
426
 
 
427
                if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
 
428
                    (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) == 0)
 
429
                        return 0;
 
430
 
398
431
                return 1;
399
432
        }
400
433
        return ret <= 0 ? ret :
411
444
                return ret;
412
445
 
413
446
        parse_body_add_block(ctx, block_r);
 
447
 
 
448
        if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
 
449
            (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) == 0)
 
450
                return 0;
 
451
 
414
452
        return 1;
415
453
}
416
454
 
426
464
        ctx->part_seen_content_type = TRUE;
427
465
 
428
466
        rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
429
 
        (void)rfc822_skip_lwsp(&parser);
 
467
        rfc822_skip_lwsp(&parser);
430
468
 
431
469
        content_type = t_str_new(64);
432
470
        if (rfc822_parse_content_type(&parser, content_type) < 0)
449
487
            ctx->last_boundary != NULL)
450
488
                return;
451
489
 
452
 
        (void)rfc2231_parse(&parser, &results);
 
490
        rfc2231_parse(&parser, &results);
453
491
        for (; *results != NULL; results += 2) {
454
492
                if (strcasecmp(results[0], "boundary") == 0) {
455
493
                        ctx->last_boundary =
467
505
{
468
506
        struct message_part *part = ctx->part;
469
507
        struct message_header_line *hdr;
470
 
        size_t size;
471
508
        int ret;
472
509
 
473
510
        if (ctx->skip > 0) {
477
514
 
478
515
        ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
479
516
        if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
480
 
                (void)i_stream_get_data(ctx->input, &size);
481
 
                ctx->want_count = size + 1;
 
517
                ctx->want_count = i_stream_get_data_size(ctx->input) + 1;
482
518
                return ret;
483
519
        }
484
520
 
586
622
                        ctx->part = ctx->part->next;
587
623
                        break;
588
624
                }
 
625
 
 
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;
 
637
 
 
638
                        if (parent_end > part_end) {
 
639
                                ctx->parse_next_block = preparsed_parse_epilogue_init;
 
640
                                break;
 
641
                        }
 
642
                }
589
643
                ctx->part = ctx->part->parent;
590
644
        }
591
645
        if (ctx->part == NULL)
602
656
        return ctx->parse_next_block(ctx, block_r);
603
657
}
604
658
 
 
659
static int preparsed_parse_prologue_finish(struct message_parser_ctx *ctx,
 
660
                                           struct message_block *block_r)
 
661
{
 
662
        i_stream_skip(ctx->input, ctx->skip);
 
663
        ctx->skip = 0;
 
664
 
 
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);
 
668
}
 
669
 
605
670
static int preparsed_parse_body_more(struct message_parser_ctx *ctx,
606
671
                                     struct message_block *block_r)
607
672
{
622
687
        return 1;
623
688
}
624
689
 
 
690
static int preparsed_parse_prologue_more(struct message_parser_ctx *ctx,
 
691
                                         struct message_block *block_r)
 
692
{
 
693
        uoff_t boundary_min_start, end_offset;
 
694
        const unsigned char *cur;
 
695
        bool full;
 
696
        int ret;
 
697
 
 
698
        i_assert(ctx->part->children != NULL);
 
699
        end_offset = ctx->part->children->physical_pos;
 
700
 
 
701
        if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
 
702
                return ret;
 
703
 
 
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;
 
708
 
 
709
                /* [\r]\n--boundary[\r]\n */ 
 
710
                if (block_r->size < 5 || *cur != '\n') {
 
711
                        ctx->broken = TRUE;
 
712
                        return -1;
 
713
                }
 
714
                
 
715
                cur--;
 
716
                if (*cur == '\r') cur--;
 
717
 
 
718
                /* find newline just before boundary */
 
719
                for (; cur >= block_r->data; cur--) {
 
720
                        if (*cur == '\n') break;
 
721
                }
 
722
 
 
723
                if (cur[0] != '\n' || cur[1] != '-' || cur[2] != '-') {
 
724
                        ctx->broken = TRUE;
 
725
                        return -1;
 
726
                }
 
727
 
 
728
                if (cur != block_r->data && cur[-1] == '\r') cur--;
 
729
 
 
730
                /* clip boundary */
 
731
                block_r->size = cur - block_r->data;                    
 
732
 
 
733
                ctx->parse_next_block = preparsed_parse_prologue_finish;
 
734
                ctx->skip = block_r->size;
 
735
                return 1;
 
736
        }
 
737
                
 
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;
 
741
        else
 
742
                boundary_min_start = 0;
 
743
 
 
744
        if (ctx->input->v_offset + block_r->size >= boundary_min_start) {
 
745
                if (boundary_min_start <= ctx->input->v_offset)
 
746
                        return 0;
 
747
                block_r->size = boundary_min_start - ctx->input->v_offset;
 
748
        }
 
749
        ctx->skip = block_r->size;
 
750
        return 1;
 
751
}
 
752
 
 
753
static int preparsed_parse_epilogue_more(struct message_parser_ctx *ctx,
 
754
                                         struct message_block *block_r)
 
755
{
 
756
        uoff_t end_offset = ctx->part->physical_pos +
 
757
                ctx->part->header_size.physical_size +
 
758
                ctx->part->body_size.physical_size;
 
759
        bool full;
 
760
        int ret;
 
761
 
 
762
        if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
 
763
                return ret;
 
764
 
 
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;
 
768
        }
 
769
        ctx->skip = block_r->size;
 
770
        return 1;
 
771
}
 
772
 
 
773
static int preparsed_parse_epilogue_boundary(struct message_parser_ctx *ctx,
 
774
                                             struct message_block *block_r)
 
775
{
 
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;
 
780
        size_t size;
 
781
        bool full;
 
782
        int ret;
 
783
 
 
784
        if (end_offset - ctx->input->v_offset < 7) {
 
785
                ctx->broken = TRUE;
 
786
                return -1;
 
787
        }
 
788
 
 
789
        if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
 
790
                return ret;
 
791
 
 
792
        /* [\r]\n--boundary--[\r]\n */
 
793
        if (block_r->size < 7) {
 
794
                ctx->want_count = 7;
 
795
                return 0;
 
796
        }
 
797
 
 
798
        data = block_r->data;
 
799
        size = block_r->size;
 
800
        cur = data;
 
801
 
 
802
        if (*cur == '\r') cur++;
 
803
 
 
804
        if (cur[0] != '\n' || cur[1] != '-' || data[2] != '-') {
 
805
                ctx->broken = TRUE;
 
806
                return -1;
 
807
        }
 
808
 
 
809
        /* find the end of the line */
 
810
        cur += 3;
 
811
        if ((cur = memchr(cur, '\n', size - (cur-data))) == NULL) {
 
812
                if (end_offset < ctx->input->v_offset + size) {
 
813
                        ctx->broken = TRUE;
 
814
                        return -1;
 
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;
 
819
                        return 0;
 
820
                }
 
821
        }
 
822
 
 
823
        block_r->size = 0;
 
824
        ctx->parse_next_block = preparsed_parse_epilogue_more;
 
825
        ctx->skip = cur - data + 1;
 
826
        return 0;
 
827
}
 
828
 
625
829
static int preparsed_parse_body_init(struct message_parser_ctx *ctx,
626
830
                                     struct message_block *block_r)
627
831
{
635
839
        }
636
840
        i_stream_skip(ctx->input, offset - ctx->input->v_offset);
637
841
 
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;
 
847
        else
 
848
                ctx->parse_next_block = preparsed_parse_prologue_more;
 
849
        return ctx->parse_next_block(ctx, block_r);
 
850
}
 
851
 
 
852
static int preparsed_parse_epilogue_init(struct message_parser_ctx *ctx,
 
853
                                         struct message_block *block_r)
 
854
{
 
855
        uoff_t offset = ctx->part->physical_pos +
 
856
                ctx->part->header_size.physical_size +
 
857
                ctx->part->body_size.physical_size;
 
858
 
 
859
        ctx->part = ctx->part->parent;
 
860
 
 
861
        if (offset < ctx->input->v_offset) {
 
862
                /* last child was actually larger than the cached size
 
863
                   suggested */
 
864
                ctx->broken = TRUE;
 
865
                return -1;
 
866
        }
 
867
        i_stream_skip(ctx->input, offset - ctx->input->v_offset);
 
868
 
 
869
        ctx->parse_next_block = preparsed_parse_epilogue_boundary;
 
870
        return ctx->parse_next_block(ctx, block_r);
640
871
}
641
872
 
642
873
static int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
643
874
                                         struct message_block *block_r)
644
875
{
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;
 
880
                else {
 
881
                        ctx->parse_next_block = preparsed_parse_next_header_init;
 
882
                        ctx->part = ctx->part->children;
 
883
                }
648
884
        } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
649
885
                ctx->parse_next_block = preparsed_parse_body_init;
650
886
        } else {
657
893
                                       struct message_block *block_r)
658
894
{
659
895
        struct message_header_line *hdr;
660
 
        size_t size;
661
896
        int ret;
662
897
 
663
898
        ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
664
899
        if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
665
 
                (void)i_stream_get_data(ctx->input, &size);
666
 
                ctx->want_count = size + 1;
 
900
                ctx->want_count = i_stream_get_data_size(ctx->input) + 1;
667
901
                return ret;
668
902
        }
669
903