Mercurial > dovecot > core-2.2
comparison src/lib-imap/imap-bodystructure.c @ 21628:a22181aad13a
lib-imap: imap-bodystructure: Grouped together functions relating to the conversion of BODYSTRUCTURE to BODY.
This only moves code.
author | Stephan Bosch <stephan.bosch@dovecot.fi> |
---|---|
date | Sun, 23 Oct 2016 17:27:07 +0200 |
parents | 6ced094b1759 |
children | 4a61612dab4f |
comparison
equal
deleted
inserted
replaced
21627:6ced094b1759 | 21628:a22181aad13a |
---|---|
519 { | 519 { |
520 if (part->flags & MESSAGE_PART_FLAG_MULTIPART) | 520 if (part->flags & MESSAGE_PART_FLAG_MULTIPART) |
521 part_write_body_multipart(part, dest, extended); | 521 part_write_body_multipart(part, dest, extended); |
522 else | 522 else |
523 part_write_body(part, dest, extended); | 523 part_write_body(part, dest, extended); |
524 } | |
525 | |
526 static int | |
527 imap_bodystructure_strlist_parse(const struct imap_arg *arg, | |
528 pool_t pool, const char *const **list_r) | |
529 { | |
530 const char *item, **list; | |
531 const struct imap_arg *list_args; | |
532 unsigned int list_count, i; | |
533 | |
534 if (arg->type == IMAP_ARG_NIL) { | |
535 *list_r = NULL; | |
536 return 0; | |
537 } | |
538 if (imap_arg_get_nstring(arg, &item)) { | |
539 list = p_new(pool, const char *, 2); | |
540 list[0] = p_strdup(pool, item); | |
541 } else { | |
542 if (!imap_arg_get_list_full(arg, &list_args, &list_count)) | |
543 return -1; | |
544 | |
545 list = p_new(pool, const char *, list_count+1); | |
546 for (i = 0; i < list_count; i++) { | |
547 if (!imap_arg_get_nstring(&list_args[i], &item)) | |
548 return -1; | |
549 list[i] = p_strdup(pool, item); | |
550 } | |
551 } | |
552 *list_r = list; | |
553 return 0; | |
554 } | |
555 | |
556 static int | |
557 imap_bodystructure_params_parse(const struct imap_arg *arg, | |
558 pool_t pool, const struct message_part_param **params_r, | |
559 unsigned int *count_r) | |
560 { | |
561 struct message_part_param *params; | |
562 const struct imap_arg *list_args; | |
563 unsigned int list_count, params_count, i; | |
564 | |
565 if (arg->type == IMAP_ARG_NIL) { | |
566 *params_r = NULL; | |
567 return 0; | |
568 } | |
569 if (!imap_arg_get_list_full(arg, &list_args, &list_count)) | |
570 return -1; | |
571 if ((list_count % 2) != 0) | |
572 return -1; | |
573 | |
574 params_count = list_count/2; | |
575 params = p_new(pool, struct message_part_param, params_count+1); | |
576 for (i = 0; i < params_count; i++) { | |
577 const char *name, *value; | |
578 | |
579 if (!imap_arg_get_nstring(&list_args[i*2+0], &name)) | |
580 return -1; | |
581 if (!imap_arg_get_nstring(&list_args[i*2+1], &value)) | |
582 return -1; | |
583 params[i].name = p_strdup(pool, name); | |
584 params[i].value = p_strdup(pool, value); | |
585 } | |
586 *params_r = params; | |
587 *count_r = params_count; | |
588 return 0; | |
589 } | |
590 | |
591 static int | |
592 imap_bodystructure_parse_args_common(struct message_part *part, | |
593 pool_t pool, const struct imap_arg *args, | |
594 const char **error_r) | |
595 { | |
596 struct message_part_data *data = part->data; | |
597 const struct imap_arg *list_args; | |
598 | |
599 if (args->type == IMAP_ARG_EOL) | |
600 return 0; | |
601 if (args->type == IMAP_ARG_NIL) | |
602 args++; | |
603 else if (!imap_arg_get_list(args, &list_args)) { | |
604 *error_r = "Invalid content-disposition list"; | |
605 return -1; | |
606 } else { | |
607 if (!imap_arg_get_nstring | |
608 (list_args++, &data->content_disposition)) { | |
609 *error_r = "Invalid content-disposition"; | |
610 return -1; | |
611 } | |
612 data->content_disposition = p_strdup(pool, data->content_disposition); | |
613 if (imap_bodystructure_params_parse(list_args, pool, | |
614 &data->content_disposition_params, | |
615 &data->content_disposition_params_count) < 0) { | |
616 *error_r = "Invalid content-disposition params"; | |
617 return -1; | |
618 } | |
619 args++; | |
620 } | |
621 if (args->type == IMAP_ARG_EOL) | |
622 return 0; | |
623 if (imap_bodystructure_strlist_parse | |
624 (args++, pool, &data->content_language) < 0) { | |
625 *error_r = "Invalid content-language"; | |
626 return -1; | |
627 } | |
628 if (args->type == IMAP_ARG_EOL) | |
629 return 0; | |
630 if (!imap_arg_get_nstring | |
631 (args++, &data->content_location)) { | |
632 *error_r = "Invalid content-location"; | |
633 return -1; | |
634 } | |
635 data->content_location = p_strdup(pool, data->content_location); | |
636 return 0; | |
637 } | |
638 | |
639 static int | |
640 imap_bodystructure_parse_args(const struct imap_arg *args, pool_t pool, | |
641 struct message_part *part, | |
642 const char **error_r) | |
643 { | |
644 struct message_part_data *data; | |
645 struct message_part *child_part; | |
646 const struct imap_arg *list_args; | |
647 const char *value, *content_type, *subtype, *error; | |
648 bool multipart, text, message_rfc822, has_lines; | |
649 unsigned int lines; | |
650 uoff_t vsize; | |
651 | |
652 i_assert(part->data == NULL); | |
653 part->data = data = p_new(pool, struct message_part_data, 1); | |
654 | |
655 multipart = FALSE; | |
656 child_part = part->children; | |
657 while (args->type == IMAP_ARG_LIST) { | |
658 if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 || | |
659 child_part == NULL) { | |
660 *error_r = "message_part hierarchy doesn't match BODYSTRUCTURE"; | |
661 return -1; | |
662 } | |
663 | |
664 list_args = imap_arg_as_list(args); | |
665 if (imap_bodystructure_parse_args(list_args, pool, | |
666 child_part, error_r) < 0) | |
667 return -1; | |
668 child_part = child_part->next; | |
669 | |
670 multipart = TRUE; | |
671 args++; | |
672 } | |
673 | |
674 if (multipart) { | |
675 if (child_part != NULL) { | |
676 *error_r = "message_part hierarchy doesn't match BODYSTRUCTURE"; | |
677 return -1; | |
678 } | |
679 data->content_type = "multipart"; | |
680 if (!imap_arg_get_nstring(args++, &data->content_subtype)) { | |
681 *error_r = "Invalid multipart content-type"; | |
682 return -1; | |
683 } | |
684 data->content_subtype = p_strdup(pool, data->content_subtype); | |
685 if (args->type == IMAP_ARG_EOL) | |
686 return 0; | |
687 if (imap_bodystructure_params_parse(args++, pool, | |
688 &data->content_type_params, | |
689 &data->content_type_params_count) < 0) { | |
690 *error_r = "Invalid content params"; | |
691 return -1; | |
692 } | |
693 return imap_bodystructure_parse_args_common | |
694 (part, pool, args, error_r); | |
695 } | |
696 if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0) { | |
697 *error_r = "message_part multipart flag doesn't match BODYSTRUCTURE"; | |
698 return -1; | |
699 } | |
700 | |
701 /* "content type" "subtype" */ | |
702 if (!imap_arg_get_astring(&args[0], &content_type) || | |
703 !imap_arg_get_astring(&args[1], &subtype)) { | |
704 *error_r = "Invalid content-type"; | |
705 return -1; | |
706 } | |
707 data->content_type = p_strdup(pool, content_type); | |
708 data->content_subtype = p_strdup(pool, subtype); | |
709 args += 2; | |
710 | |
711 text = strcasecmp(content_type, "text") == 0; | |
712 message_rfc822 = strcasecmp(content_type, "message") == 0 && | |
713 strcasecmp(subtype, "rfc822") == 0; | |
714 | |
715 #if 0 | |
716 /* Disabled for now. Earlier Dovecot versions handled broken | |
717 Content-Type headers by writing them as "text" "plain" to | |
718 BODYSTRUCTURE reply, but the message_part didn't have | |
719 MESSAGE_PART_FLAG_TEXT. */ | |
720 if (text != ((part->flags & MESSAGE_PART_FLAG_TEXT) != 0)) { | |
721 *error_r = "message_part text flag doesn't match BODYSTRUCTURE"; | |
722 return -1; | |
723 } | |
724 #endif | |
725 if (message_rfc822 != ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) != 0)) { | |
726 *error_r = "message_part message/rfc822 flag doesn't match BODYSTRUCTURE"; | |
727 return -1; | |
728 } | |
729 | |
730 /* ("content type param key" "value" ...) | NIL */ | |
731 if (imap_bodystructure_params_parse(args++, pool, | |
732 &data->content_type_params, | |
733 &data->content_type_params_count) < 0) { | |
734 *error_r = "Invalid content params"; | |
735 return -1; | |
736 } | |
737 | |
738 /* "content id" "content description" "transfer encoding" size */ | |
739 if (!imap_arg_get_nstring(args++, &data->content_id)) { | |
740 *error_r = "Invalid content-id"; | |
741 return -1; | |
742 } | |
743 if (!imap_arg_get_nstring(args++, &data->content_description)) { | |
744 *error_r = "Invalid content-description"; | |
745 return -1; | |
746 } | |
747 if (!imap_arg_get_nstring(args++, &data->content_transfer_encoding)) { | |
748 *error_r = "Invalid content-transfer-encoding"; | |
749 return -1; | |
750 } | |
751 data->content_id = p_strdup(pool, data->content_id); | |
752 data->content_description = p_strdup(pool, data->content_description); | |
753 data->content_transfer_encoding = | |
754 p_strdup(pool, data->content_transfer_encoding); | |
755 if (!imap_arg_get_atom(args++, &value) || | |
756 str_to_uoff(value, &vsize) < 0) { | |
757 *error_r = "Invalid size field"; | |
758 return -1; | |
759 } | |
760 if (vsize != part->body_size.virtual_size) { | |
761 *error_r = "message_part virtual_size doesn't match " | |
762 "size in BODYSTRUCTURE"; | |
763 return -1; | |
764 } | |
765 | |
766 if (text) { | |
767 /* text/xxx - text lines */ | |
768 if (!imap_arg_get_atom(args++, &value) || | |
769 str_to_uint(value, &lines) < 0) { | |
770 *error_r = "Invalid lines field"; | |
771 return -1; | |
772 } | |
773 i_assert(part->children == NULL); | |
774 has_lines = TRUE; | |
775 } else if (message_rfc822) { | |
776 /* message/rfc822 - envelope + bodystructure + text lines */ | |
777 | |
778 i_assert(part->children != NULL && | |
779 part->children->next == NULL); | |
780 | |
781 if (!imap_arg_get_list(&args[1], &list_args)) { | |
782 *error_r = "Child bodystructure list expected"; | |
783 return -1; | |
784 } | |
785 if (imap_bodystructure_parse_args | |
786 (list_args, pool, part->children, error_r) < 0) | |
787 return -1; | |
788 | |
789 if (!imap_arg_get_list(&args[0], &list_args)) { | |
790 *error_r = "Envelope list expected"; | |
791 return -1; | |
792 } | |
793 if (!imap_envelope_parse_args(list_args, pool, | |
794 &part->children->data->envelope, &error)) { | |
795 *error_r = t_strdup_printf | |
796 ("Invalid envelope list: %s", error); | |
797 return -1; | |
798 } | |
799 args += 2; | |
800 if (!imap_arg_get_atom(args++, &value) || | |
801 str_to_uint(value, &lines) < 0) { | |
802 *error_r = "Invalid lines field"; | |
803 return -1; | |
804 } | |
805 has_lines = TRUE; | |
806 } else { | |
807 i_assert(part->children == NULL); | |
808 has_lines = FALSE; | |
809 } | |
810 if (has_lines && lines != part->body_size.lines) { | |
811 *error_r = "message_part lines " | |
812 "doesn't match lines in BODYSTRUCTURE"; | |
813 return -1; | |
814 } | |
815 if (args->type == IMAP_ARG_EOL) | |
816 return 0; | |
817 if (!imap_arg_get_nstring(args++, &data->content_md5)) { | |
818 *error_r = "Invalid content-md5"; | |
819 return -1; | |
820 } | |
821 data->content_md5 = p_strdup(pool, data->content_md5); | |
822 return imap_bodystructure_parse_args_common | |
823 (part, pool, args, error_r); | |
824 } | |
825 | |
826 int imap_bodystructure_parse(const char *bodystructure, | |
827 pool_t pool, struct message_part *parts, | |
828 const char **error_r) | |
829 { | |
830 struct istream *input; | |
831 struct imap_parser *parser; | |
832 const struct imap_arg *args; | |
833 char *error; | |
834 int ret; | |
835 bool fatal; | |
836 | |
837 i_assert(parts != NULL); | |
838 i_assert(parts->next == NULL); | |
839 | |
840 input = i_stream_create_from_data(bodystructure, strlen(bodystructure)); | |
841 (void)i_stream_read(input); | |
842 | |
843 parser = imap_parser_create(input, NULL, (size_t)-1); | |
844 ret = imap_parser_finish_line(parser, 0, | |
845 IMAP_PARSE_FLAG_LITERAL_TYPE, &args); | |
846 if (ret < 0) { | |
847 *error_r = t_strdup_printf("IMAP parser failed: %s", | |
848 imap_parser_get_error(parser, &fatal)); | |
849 } else if (ret == 0) { | |
850 *error_r = "Empty bodystructure"; | |
851 ret = -1; | |
852 } else { | |
853 T_BEGIN { | |
854 ret = imap_bodystructure_parse_args | |
855 (args, pool, parts, error_r); | |
856 if (ret < 0) | |
857 error = i_strdup(*error_r); | |
858 } T_END; | |
859 | |
860 if (ret < 0) { | |
861 *error_r = t_strdup(error); | |
862 i_free(error); | |
863 } | |
864 } | |
865 | |
866 imap_parser_unref(&parser); | |
867 i_stream_destroy(&input); | |
868 return ret; | |
524 } | 869 } |
525 | 870 |
526 static bool str_append_nstring(string_t *str, const struct imap_arg *arg) | 871 static bool str_append_nstring(string_t *str, const struct imap_arg *arg) |
527 { | 872 { |
528 const char *cstr; | 873 const char *cstr; |
589 imap_write_envelope(const struct imap_arg *args, string_t *str) | 934 imap_write_envelope(const struct imap_arg *args, string_t *str) |
590 { | 935 { |
591 imap_write_envelope_list(args, str, TRUE); | 936 imap_write_envelope_list(args, str, TRUE); |
592 } | 937 } |
593 | 938 |
594 static int | |
595 imap_bodystructure_strlist_parse(const struct imap_arg *arg, | |
596 pool_t pool, const char *const **list_r) | |
597 { | |
598 const char *item, **list; | |
599 const struct imap_arg *list_args; | |
600 unsigned int list_count, i; | |
601 | |
602 if (arg->type == IMAP_ARG_NIL) { | |
603 *list_r = NULL; | |
604 return 0; | |
605 } | |
606 if (imap_arg_get_nstring(arg, &item)) { | |
607 list = p_new(pool, const char *, 2); | |
608 list[0] = p_strdup(pool, item); | |
609 } else { | |
610 if (!imap_arg_get_list_full(arg, &list_args, &list_count)) | |
611 return -1; | |
612 | |
613 list = p_new(pool, const char *, list_count+1); | |
614 for (i = 0; i < list_count; i++) { | |
615 if (!imap_arg_get_nstring(&list_args[i], &item)) | |
616 return -1; | |
617 list[i] = p_strdup(pool, item); | |
618 } | |
619 } | |
620 *list_r = list; | |
621 return 0; | |
622 } | |
623 | |
624 static int | |
625 imap_bodystructure_params_parse(const struct imap_arg *arg, | |
626 pool_t pool, const struct message_part_param **params_r, | |
627 unsigned int *count_r) | |
628 { | |
629 struct message_part_param *params; | |
630 const struct imap_arg *list_args; | |
631 unsigned int list_count, params_count, i; | |
632 | |
633 if (arg->type == IMAP_ARG_NIL) { | |
634 *params_r = NULL; | |
635 return 0; | |
636 } | |
637 if (!imap_arg_get_list_full(arg, &list_args, &list_count)) | |
638 return -1; | |
639 if ((list_count % 2) != 0) | |
640 return -1; | |
641 | |
642 params_count = list_count/2; | |
643 params = p_new(pool, struct message_part_param, params_count+1); | |
644 for (i = 0; i < params_count; i++) { | |
645 const char *name, *value; | |
646 | |
647 if (!imap_arg_get_nstring(&list_args[i*2+0], &name)) | |
648 return -1; | |
649 if (!imap_arg_get_nstring(&list_args[i*2+1], &value)) | |
650 return -1; | |
651 params[i].name = p_strdup(pool, name); | |
652 params[i].value = p_strdup(pool, value); | |
653 } | |
654 *params_r = params; | |
655 *count_r = params_count; | |
656 return 0; | |
657 } | |
658 | |
659 static int | |
660 imap_bodystructure_parse_args_common(struct message_part *part, | |
661 pool_t pool, const struct imap_arg *args, | |
662 const char **error_r) | |
663 { | |
664 struct message_part_data *data = part->data; | |
665 const struct imap_arg *list_args; | |
666 | |
667 if (args->type == IMAP_ARG_EOL) | |
668 return 0; | |
669 if (args->type == IMAP_ARG_NIL) | |
670 args++; | |
671 else if (!imap_arg_get_list(args, &list_args)) { | |
672 *error_r = "Invalid content-disposition list"; | |
673 return -1; | |
674 } else { | |
675 if (!imap_arg_get_nstring | |
676 (list_args++, &data->content_disposition)) { | |
677 *error_r = "Invalid content-disposition"; | |
678 return -1; | |
679 } | |
680 data->content_disposition = p_strdup(pool, data->content_disposition); | |
681 if (imap_bodystructure_params_parse(list_args, pool, | |
682 &data->content_disposition_params, | |
683 &data->content_disposition_params_count) < 0) { | |
684 *error_r = "Invalid content-disposition params"; | |
685 return -1; | |
686 } | |
687 args++; | |
688 } | |
689 if (args->type == IMAP_ARG_EOL) | |
690 return 0; | |
691 if (imap_bodystructure_strlist_parse | |
692 (args++, pool, &data->content_language) < 0) { | |
693 *error_r = "Invalid content-language"; | |
694 return -1; | |
695 } | |
696 if (args->type == IMAP_ARG_EOL) | |
697 return 0; | |
698 if (!imap_arg_get_nstring | |
699 (args++, &data->content_location)) { | |
700 *error_r = "Invalid content-location"; | |
701 return -1; | |
702 } | |
703 data->content_location = p_strdup(pool, data->content_location); | |
704 return 0; | |
705 } | |
706 | |
707 static int | |
708 imap_bodystructure_parse_args(const struct imap_arg *args, pool_t pool, | |
709 struct message_part *part, | |
710 const char **error_r) | |
711 { | |
712 struct message_part_data *data; | |
713 struct message_part *child_part; | |
714 const struct imap_arg *list_args; | |
715 const char *value, *content_type, *subtype, *error; | |
716 bool multipart, text, message_rfc822, has_lines; | |
717 unsigned int lines; | |
718 uoff_t vsize; | |
719 | |
720 i_assert(part->data == NULL); | |
721 part->data = data = p_new(pool, struct message_part_data, 1); | |
722 | |
723 multipart = FALSE; | |
724 child_part = part->children; | |
725 while (args->type == IMAP_ARG_LIST) { | |
726 if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 || | |
727 child_part == NULL) { | |
728 *error_r = "message_part hierarchy doesn't match BODYSTRUCTURE"; | |
729 return -1; | |
730 } | |
731 | |
732 list_args = imap_arg_as_list(args); | |
733 if (imap_bodystructure_parse_args(list_args, pool, | |
734 child_part, error_r) < 0) | |
735 return -1; | |
736 child_part = child_part->next; | |
737 | |
738 multipart = TRUE; | |
739 args++; | |
740 } | |
741 | |
742 if (multipart) { | |
743 if (child_part != NULL) { | |
744 *error_r = "message_part hierarchy doesn't match BODYSTRUCTURE"; | |
745 return -1; | |
746 } | |
747 data->content_type = "multipart"; | |
748 if (!imap_arg_get_nstring(args++, &data->content_subtype)) { | |
749 *error_r = "Invalid multipart content-type"; | |
750 return -1; | |
751 } | |
752 data->content_subtype = p_strdup(pool, data->content_subtype); | |
753 if (args->type == IMAP_ARG_EOL) | |
754 return 0; | |
755 if (imap_bodystructure_params_parse(args++, pool, | |
756 &data->content_type_params, | |
757 &data->content_type_params_count) < 0) { | |
758 *error_r = "Invalid content params"; | |
759 return -1; | |
760 } | |
761 return imap_bodystructure_parse_args_common | |
762 (part, pool, args, error_r); | |
763 } | |
764 if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0) { | |
765 *error_r = "message_part multipart flag doesn't match BODYSTRUCTURE"; | |
766 return -1; | |
767 } | |
768 | |
769 /* "content type" "subtype" */ | |
770 if (!imap_arg_get_astring(&args[0], &content_type) || | |
771 !imap_arg_get_astring(&args[1], &subtype)) { | |
772 *error_r = "Invalid content-type"; | |
773 return -1; | |
774 } | |
775 data->content_type = p_strdup(pool, content_type); | |
776 data->content_subtype = p_strdup(pool, subtype); | |
777 args += 2; | |
778 | |
779 text = strcasecmp(content_type, "text") == 0; | |
780 message_rfc822 = strcasecmp(content_type, "message") == 0 && | |
781 strcasecmp(subtype, "rfc822") == 0; | |
782 | |
783 #if 0 | |
784 /* Disabled for now. Earlier Dovecot versions handled broken | |
785 Content-Type headers by writing them as "text" "plain" to | |
786 BODYSTRUCTURE reply, but the message_part didn't have | |
787 MESSAGE_PART_FLAG_TEXT. */ | |
788 if (text != ((part->flags & MESSAGE_PART_FLAG_TEXT) != 0)) { | |
789 *error_r = "message_part text flag doesn't match BODYSTRUCTURE"; | |
790 return -1; | |
791 } | |
792 #endif | |
793 if (message_rfc822 != ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) != 0)) { | |
794 *error_r = "message_part message/rfc822 flag doesn't match BODYSTRUCTURE"; | |
795 return -1; | |
796 } | |
797 | |
798 /* ("content type param key" "value" ...) | NIL */ | |
799 if (imap_bodystructure_params_parse(args++, pool, | |
800 &data->content_type_params, | |
801 &data->content_type_params_count) < 0) { | |
802 *error_r = "Invalid content params"; | |
803 return -1; | |
804 } | |
805 | |
806 /* "content id" "content description" "transfer encoding" size */ | |
807 if (!imap_arg_get_nstring(args++, &data->content_id)) { | |
808 *error_r = "Invalid content-id"; | |
809 return -1; | |
810 } | |
811 if (!imap_arg_get_nstring(args++, &data->content_description)) { | |
812 *error_r = "Invalid content-description"; | |
813 return -1; | |
814 } | |
815 if (!imap_arg_get_nstring(args++, &data->content_transfer_encoding)) { | |
816 *error_r = "Invalid content-transfer-encoding"; | |
817 return -1; | |
818 } | |
819 data->content_id = p_strdup(pool, data->content_id); | |
820 data->content_description = p_strdup(pool, data->content_description); | |
821 data->content_transfer_encoding = | |
822 p_strdup(pool, data->content_transfer_encoding); | |
823 if (!imap_arg_get_atom(args++, &value) || | |
824 str_to_uoff(value, &vsize) < 0) { | |
825 *error_r = "Invalid size field"; | |
826 return -1; | |
827 } | |
828 if (vsize != part->body_size.virtual_size) { | |
829 *error_r = "message_part virtual_size doesn't match " | |
830 "size in BODYSTRUCTURE"; | |
831 return -1; | |
832 } | |
833 | |
834 if (text) { | |
835 /* text/xxx - text lines */ | |
836 if (!imap_arg_get_atom(args++, &value) || | |
837 str_to_uint(value, &lines) < 0) { | |
838 *error_r = "Invalid lines field"; | |
839 return -1; | |
840 } | |
841 i_assert(part->children == NULL); | |
842 has_lines = TRUE; | |
843 } else if (message_rfc822) { | |
844 /* message/rfc822 - envelope + bodystructure + text lines */ | |
845 | |
846 i_assert(part->children != NULL && | |
847 part->children->next == NULL); | |
848 | |
849 if (!imap_arg_get_list(&args[1], &list_args)) { | |
850 *error_r = "Child bodystructure list expected"; | |
851 return -1; | |
852 } | |
853 if (imap_bodystructure_parse_args | |
854 (list_args, pool, part->children, error_r) < 0) | |
855 return -1; | |
856 | |
857 if (!imap_arg_get_list(&args[0], &list_args)) { | |
858 *error_r = "Envelope list expected"; | |
859 return -1; | |
860 } | |
861 if (!imap_envelope_parse_args(list_args, pool, | |
862 &part->children->data->envelope, &error)) { | |
863 *error_r = t_strdup_printf | |
864 ("Invalid envelope list: %s", error); | |
865 return -1; | |
866 } | |
867 args += 2; | |
868 if (!imap_arg_get_atom(args++, &value) || | |
869 str_to_uint(value, &lines) < 0) { | |
870 *error_r = "Invalid lines field"; | |
871 return -1; | |
872 } | |
873 has_lines = TRUE; | |
874 } else { | |
875 i_assert(part->children == NULL); | |
876 has_lines = FALSE; | |
877 } | |
878 if (has_lines && lines != part->body_size.lines) { | |
879 *error_r = "message_part lines " | |
880 "doesn't match lines in BODYSTRUCTURE"; | |
881 return -1; | |
882 } | |
883 if (args->type == IMAP_ARG_EOL) | |
884 return 0; | |
885 if (!imap_arg_get_nstring(args++, &data->content_md5)) { | |
886 *error_r = "Invalid content-md5"; | |
887 return -1; | |
888 } | |
889 data->content_md5 = p_strdup(pool, data->content_md5); | |
890 return imap_bodystructure_parse_args_common | |
891 (part, pool, args, error_r); | |
892 } | |
893 | |
894 int imap_bodystructure_parse(const char *bodystructure, | |
895 pool_t pool, struct message_part *parts, | |
896 const char **error_r) | |
897 { | |
898 struct istream *input; | |
899 struct imap_parser *parser; | |
900 const struct imap_arg *args; | |
901 char *error; | |
902 int ret; | |
903 bool fatal; | |
904 | |
905 i_assert(parts != NULL); | |
906 i_assert(parts->next == NULL); | |
907 | |
908 input = i_stream_create_from_data(bodystructure, strlen(bodystructure)); | |
909 (void)i_stream_read(input); | |
910 | |
911 parser = imap_parser_create(input, NULL, (size_t)-1); | |
912 ret = imap_parser_finish_line(parser, 0, | |
913 IMAP_PARSE_FLAG_LITERAL_TYPE, &args); | |
914 if (ret < 0) { | |
915 *error_r = t_strdup_printf("IMAP parser failed: %s", | |
916 imap_parser_get_error(parser, &fatal)); | |
917 } else if (ret == 0) { | |
918 *error_r = "Empty bodystructure"; | |
919 ret = -1; | |
920 } else { | |
921 T_BEGIN { | |
922 ret = imap_bodystructure_parse_args | |
923 (args, pool, parts, error_r); | |
924 if (ret < 0) | |
925 error = i_strdup(*error_r); | |
926 } T_END; | |
927 | |
928 if (ret < 0) { | |
929 *error_r = t_strdup(error); | |
930 i_free(error); | |
931 } | |
932 } | |
933 | |
934 imap_parser_unref(&parser); | |
935 i_stream_destroy(&input); | |
936 return ret; | |
937 } | |
938 | |
939 static int imap_parse_bodystructure_args(const struct imap_arg *args, | 939 static int imap_parse_bodystructure_args(const struct imap_arg *args, |
940 string_t *str, const char **error_r) | 940 string_t *str, const char **error_r) |
941 { | 941 { |
942 const struct imap_arg *subargs; | 942 const struct imap_arg *subargs; |
943 const struct imap_arg *list_args; | 943 const struct imap_arg *list_args; |