Mercurial > libpst
comparison src/readpst.c @ 141:fd4297884319
improve decoding of multipart/report and message/rfc822 mime types
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Sat, 14 Feb 2009 11:02:37 -0800 |
parents | 1b3922080ca8 |
children | 2189a6b8134e |
comparison
equal
deleted
inserted
replaced
140:fc6c54c453e5 | 141:fd4297884319 |
---|---|
38 char* mk_separate_dir(char *dir); | 38 char* mk_separate_dir(char *dir); |
39 int close_separate_dir(); | 39 int close_separate_dir(); |
40 int mk_separate_file(struct file_ll *f); | 40 int mk_separate_file(struct file_ll *f); |
41 char* my_stristr(char *haystack, char *needle); | 41 char* my_stristr(char *haystack, char *needle); |
42 void check_filename(char *fname); | 42 void check_filename(char *fname); |
43 void write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst); | 43 void write_separate_attachment(char f_name[], pst_item_attach* attach, int attach_num, pst_file* pst); |
44 void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char *boundary, pst_file* pst); | 44 void write_embedded_message(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pf, char** extra_mime_headers); |
45 void write_inline_attachment(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pst); | |
45 void header_has_field(char *header, char *field, int *flag); | 46 void header_has_field(char *header, char *field, int *flag); |
47 void header_get_subfield(char *field, const char *subfield, char *body_subfield, size_t size_subfield); | |
46 char* header_get_field(char *header, char *field); | 48 char* header_get_field(char *header, char *field); |
49 char* header_end_field(char *field); | |
47 void header_strip_field(char *header, char *field); | 50 void header_strip_field(char *header, char *field); |
48 int test_base64(char *body); | 51 int test_base64(char *body); |
49 void find_html_charset(char *html, char *charset, size_t charsetlen); | 52 void find_html_charset(char *html, char *charset, size_t charsetlen); |
53 void find_rfc822_headers(char** extra_mime_headers); | |
50 void write_body_part(FILE* f_output, char *body, char *mime, char *charset, char *boundary); | 54 void write_body_part(FILE* f_output, char *body, char *mime, char *charset, char *boundary); |
51 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf); | 55 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf, char** extra_mime_headers); |
52 void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]); | 56 void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]); |
53 void write_appointment(FILE* f_output, pst_item_appointment* appointment, | 57 void write_appointment(FILE* f_output, pst_item_appointment* appointment, |
54 pst_item_email* email, FILETIME* create_date, FILETIME* modify_date); | 58 pst_item_email* email, FILETIME* create_date, FILETIME* modify_date); |
55 void create_enter_dir(struct file_ll* f, pst_item *item); | 59 void create_enter_dir(struct file_ll* f, pst_item *item); |
56 void close_enter_dir(struct file_ll *f); | 60 void close_enter_dir(struct file_ll *f); |
86 // Output Quiet is provided so that only errors are printed | 90 // Output Quiet is provided so that only errors are printed |
87 #define OUTPUT_QUIET 1 | 91 #define OUTPUT_QUIET 1 |
88 | 92 |
89 // default mime-type for attachments that have a null mime-type | 93 // default mime-type for attachments that have a null mime-type |
90 #define MIME_TYPE_DEFAULT "application/octet-stream" | 94 #define MIME_TYPE_DEFAULT "application/octet-stream" |
95 #define RFC822 "message/rfc822" | |
91 | 96 |
92 // output mode for contacts | 97 // output mode for contacts |
93 #define CMODE_VCARD 0 | 98 #define CMODE_VCARD 0 |
94 #define CMODE_LIST 1 | 99 #define CMODE_LIST 1 |
95 | 100 |
159 write_vcard(ff.output, item->contact, item->comment); | 164 write_vcard(ff.output, item->contact, item->comment); |
160 else | 165 else |
161 fprintf(ff.output, "%s <%s>\n", item->contact->fullname, item->contact->address1); | 166 fprintf(ff.output, "%s <%s>\n", item->contact->fullname, item->contact->address1); |
162 | 167 |
163 } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT || item->type == PST_TYPE_OTHER)) { | 168 } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT || item->type == PST_TYPE_OTHER)) { |
169 char *extra_mime_headers = NULL; | |
164 if (mode == MODE_SEPARATE) mk_separate_file(&ff); | 170 if (mode == MODE_SEPARATE) mk_separate_file(&ff); |
165 ff.email_count++; | 171 ff.email_count++; |
166 DEBUG_MAIN(("main: Processing Email\n")); | 172 DEBUG_MAIN(("main: Processing Email\n")); |
167 if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT) && (ff.type != PST_TYPE_OTHER)) { | 173 if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT) && (ff.type != PST_TYPE_OTHER)) { |
168 DEBUG_MAIN(("main: I have an email, but the folder isn't an email folder. Processing anyway\n")); | 174 DEBUG_MAIN(("main: I have an email, but the folder isn't an email folder. Processing anyway\n")); |
169 } | 175 } |
170 write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body); | 176 write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body, &extra_mime_headers); |
171 | 177 |
172 } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) { | 178 } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) { |
173 // deal with journal items | 179 // deal with journal items |
174 if (mode == MODE_SEPARATE) mk_separate_file(&ff); | 180 if (mode == MODE_SEPARATE) mk_separate_file(&ff); |
175 ff.email_count++; | 181 ff.email_count++; |
685 } | 691 } |
686 DEBUG_RET(); | 692 DEBUG_RET(); |
687 } | 693 } |
688 | 694 |
689 | 695 |
690 void write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst) | 696 void write_separate_attachment(char f_name[], pst_item_attach* attach, int attach_num, pst_file* pst) |
691 { | 697 { |
692 FILE *fp = NULL; | 698 FILE *fp = NULL; |
693 int x = 0; | 699 int x = 0; |
694 char *temp = NULL; | 700 char *temp = NULL; |
695 | 701 |
696 // If there is a long filename (filename2) use that, otherwise | 702 // If there is a long filename (filename2) use that, otherwise |
697 // use the 8.3 filename (filename1) | 703 // use the 8.3 filename (filename1) |
698 char *attach_filename = (current_attach->filename2) ? current_attach->filename2 | 704 char *attach_filename = (attach->filename2) ? attach->filename2 |
699 : current_attach->filename1; | 705 : attach->filename1; |
700 DEBUG_ENT("write_separate_attachment"); | 706 DEBUG_ENT("write_separate_attachment"); |
701 | 707 |
702 check_filename(f_name); | 708 check_filename(f_name); |
703 if (!attach_filename) { | 709 if (!attach_filename) { |
704 // generate our own (dummy) filename for the attachement | 710 // generate our own (dummy) filename for the attachement |
720 } | 726 } |
721 DEBUG_EMAIL(("Saving attachment to %s\n", temp)); | 727 DEBUG_EMAIL(("Saving attachment to %s\n", temp)); |
722 if (!(fp = fopen(temp, "w"))) { | 728 if (!(fp = fopen(temp, "w"))) { |
723 WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp)); | 729 WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp)); |
724 } else { | 730 } else { |
725 if (current_attach->data) | 731 if (attach->data) |
726 pst_fwrite(current_attach->data, 1, current_attach->size, fp); | 732 pst_fwrite(attach->data, 1, attach->size, fp); |
727 else { | 733 else { |
728 (void)pst_attach_to_file(pst, current_attach, fp); | 734 (void)pst_attach_to_file(pst, attach, fp); |
729 } | 735 } |
730 fclose(fp); | 736 fclose(fp); |
731 } | 737 } |
732 if (temp) free(temp); | 738 if (temp) free(temp); |
733 DEBUG_RET(); | 739 DEBUG_RET(); |
734 } | 740 } |
735 | 741 |
736 | 742 |
737 void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char *boundary, pst_file* pst) | 743 void write_embedded_message(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pf, char** extra_mime_headers) |
744 { | |
745 pst_index_ll *ptr; | |
746 DEBUG_ENT("write_embedded_message"); | |
747 fprintf(f_output, "\n--%s\n", boundary); | |
748 fprintf(f_output, "Content-Type: %s\n\n", attach->mimetype); | |
749 ptr = pst_getID(pf, attach->id_val); | |
750 pst_num_array *list = pst_parse_block(pf, ptr->id, NULL, NULL); | |
751 if (list) { | |
752 pst_item *item = (pst_item*) xmalloc(sizeof(pst_item)); | |
753 memset(item, 0, sizeof(pst_item)); | |
754 if (!pst_process(list, item, NULL)) { | |
755 write_normal_email(f_output, "", item, MODE_NORMAL, 0, pf, 0, extra_mime_headers); | |
756 } | |
757 pst_freeItem(item); | |
758 pst_free_list(list); | |
759 } | |
760 DEBUG_RET(); | |
761 } | |
762 | |
763 | |
764 void write_inline_attachment(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pst) | |
738 { | 765 { |
739 char *attach_filename; | 766 char *attach_filename; |
740 char *enc = NULL; // base64 encoded attachment | 767 char *enc = NULL; // base64 encoded attachment |
741 DEBUG_ENT("write_inline_attachment"); | 768 DEBUG_ENT("write_inline_attachment"); |
742 DEBUG_EMAIL(("Attachment Size is %i\n", current_attach->size)); | 769 DEBUG_EMAIL(("Attachment Size is %i\n", attach->size)); |
743 DEBUG_EMAIL(("Attachment Pointer is %p\n", current_attach->data)); | 770 DEBUG_EMAIL(("Attachment Pointer is %p\n", attach->data)); |
744 if (current_attach->data) { | 771 if (attach->data) { |
745 enc = base64_encode (current_attach->data, current_attach->size); | 772 enc = base64_encode (attach->data, attach->size); |
746 if (!enc) { | 773 if (!enc) { |
747 DEBUG_EMAIL(("ERROR base64_encode returned NULL. Must have failed\n")); | 774 DEBUG_EMAIL(("ERROR base64_encode returned NULL. Must have failed\n")); |
748 DEBUG_RET(); | 775 DEBUG_RET(); |
749 return; | 776 return; |
750 } | 777 } |
751 } | 778 } |
752 | 779 |
753 fprintf(f_output, "\n--%s\n", boundary); | 780 fprintf(f_output, "\n--%s\n", boundary); |
754 if (!current_attach->mimetype) { | 781 if (!attach->mimetype) { |
755 fprintf(f_output, "Content-Type: %s\n", MIME_TYPE_DEFAULT); | 782 fprintf(f_output, "Content-Type: %s\n", MIME_TYPE_DEFAULT); |
756 } else { | 783 } else { |
757 fprintf(f_output, "Content-Type: %s\n", current_attach->mimetype); | 784 fprintf(f_output, "Content-Type: %s\n", attach->mimetype); |
758 } | 785 } |
759 fprintf(f_output, "Content-Transfer-Encoding: base64\n"); | 786 fprintf(f_output, "Content-Transfer-Encoding: base64\n"); |
787 | |
760 // If there is a long filename (filename2) use that, otherwise | 788 // If there is a long filename (filename2) use that, otherwise |
761 // use the 8.3 filename (filename1) | 789 // use the 8.3 filename (filename1) |
762 if (current_attach->filename2) { | 790 attach_filename = (attach->filename2) ? attach->filename2 : attach->filename1; |
763 attach_filename = current_attach->filename2; | |
764 } else { | |
765 attach_filename = current_attach->filename1; | |
766 } | |
767 if (!attach_filename) { | 791 if (!attach_filename) { |
768 fprintf(f_output, "Content-Disposition: inline\n\n"); | 792 fprintf(f_output, "Content-Disposition: inline\n\n"); |
769 } else { | 793 } else { |
770 fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach_filename); | 794 fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach_filename); |
771 } | 795 } |
772 | 796 |
773 if (current_attach->data) { | 797 if (attach->data) { |
774 pst_fwrite(enc, 1, strlen(enc), f_output); | 798 pst_fwrite(enc, 1, strlen(enc), f_output); |
775 DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc))); | 799 DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc))); |
776 free(enc); // caught by valgrind | 800 free(enc); // caught by valgrind |
777 } else { | 801 } else { |
778 (void)pst_attach_to_file_base64(pst, current_attach, f_output); | 802 (void)pst_attach_to_file_base64(pst, attach, f_output); |
779 } | 803 } |
780 fprintf(f_output, "\n\n"); | 804 fprintf(f_output, "\n\n"); |
781 DEBUG_RET(); | 805 DEBUG_RET(); |
782 } | 806 } |
783 | 807 |
784 | 808 |
785 void header_has_field(char *header, char *field, int *flag) | 809 void header_has_field(char *header, char *field, int *flag) |
786 { | 810 { |
811 DEBUG_ENT("header_has_field"); | |
787 if (my_stristr(header, field) || (strncasecmp(header, field+1, strlen(field)-1) == 0)) { | 812 if (my_stristr(header, field) || (strncasecmp(header, field+1, strlen(field)-1) == 0)) { |
788 DEBUG_EMAIL(("header block has %s header\n", field+1)); | 813 DEBUG_EMAIL(("header block has %s header\n", field+1)); |
789 *flag = 1; | 814 *flag = 1; |
790 } | 815 } |
791 } | 816 DEBUG_RET(); |
792 | 817 } |
818 | |
819 | |
820 void header_get_subfield(char *field, const char *subfield, char *body_subfield, size_t size_subfield) | |
821 { | |
822 if (!field) return; | |
823 DEBUG_ENT("header_get_subfield"); | |
824 char search[60]; | |
825 snprintf(search, sizeof(search), " %s=", subfield); | |
826 field++; | |
827 char *n = header_end_field(field); | |
828 char *s = my_stristr(field, search); | |
829 if (n && s && (s < n)) { | |
830 char *e, *f, save; | |
831 s += strlen(search); // skip over subfield= | |
832 if (*s == '"') { | |
833 s++; | |
834 e = strchr(s, '"'); | |
835 } | |
836 else { | |
837 e = strchr(s, ';'); | |
838 f = strchr(s, '\n'); | |
839 if (e && f && (f < e)) e = f; | |
840 } | |
841 if (!e || (e > n)) e = n; // use the trailing lf as terminator if nothing better | |
842 save = *e; | |
843 *e = '\0'; | |
844 snprintf(body_subfield, size_subfield, "%s", s); // copy the subfield to our buffer | |
845 *e = save; | |
846 DEBUG_EMAIL(("body %s %s from headers\n", subfield, body_subfield)); | |
847 } | |
848 DEBUG_RET(); | |
849 } | |
793 | 850 |
794 char* header_get_field(char *header, char *field) | 851 char* header_get_field(char *header, char *field) |
795 { | 852 { |
796 char *t = my_stristr(header, field); | 853 char *t = my_stristr(header, field); |
797 if (!t && (strncasecmp(header, field+1, strlen(field)-1) == 0)) t = header; | 854 if (!t && (strncasecmp(header, field+1, strlen(field)-1) == 0)) t = header; |
798 return t; | 855 return t; |
799 } | 856 } |
800 | 857 |
801 | 858 |
859 // return pointer to \n at the end of this header field, | |
860 // or NULL if this field goes to the end of the string. | |
861 char *header_end_field(char *field) | |
862 { | |
863 char *e = strchr(field+1, '\n'); | |
864 while (e && ((e[1] == ' ') || (e[1] == '\t'))) { | |
865 e = strchr(e+1, '\n'); | |
866 } | |
867 return e; | |
868 } | |
869 | |
870 | |
802 void header_strip_field(char *header, char *field) | 871 void header_strip_field(char *header, char *field) |
803 { | 872 { |
804 char *e; | 873 char *e; |
805 char *t = header_get_field(header, field); | 874 char *t = header_get_field(header, field); |
806 if (t) { | 875 if (t) { |
807 e = strchr(t+1, '\n'); | 876 char *e = header_end_field(t); |
808 while (e && ((e[1] == ' ') || (e[1] == '\t'))) { | |
809 e = strchr(e+1, '\n'); | |
810 } | |
811 if (e) { | 877 if (e) { |
812 if (t == header) e++; // if *t is not \n, we don't want to keep the \n at *e either. | 878 if (t == header) e++; // if *t is not \n, we don't want to keep the \n at *e either. |
813 while (*e != '\0') { | 879 while (*e != '\0') { |
814 *t = *e; | 880 *t = *e; |
815 t++; | 881 t++; |
827 | 893 |
828 int test_base64(char *body) | 894 int test_base64(char *body) |
829 { | 895 { |
830 int b64 = 0; | 896 int b64 = 0; |
831 uint8_t *b = (uint8_t *)body; | 897 uint8_t *b = (uint8_t *)body; |
898 DEBUG_ENT("test_base64"); | |
832 while (*b != 0) { | 899 while (*b != 0) { |
833 if ((*b < 32) && (*b != 9) && (*b != 10)) { | 900 if ((*b < 32) && (*b != 9) && (*b != 10)) { |
834 DEBUG_EMAIL(("found base64 byte %d\n", (int)*b)); | 901 DEBUG_EMAIL(("found base64 byte %d\n", (int)*b)); |
835 DEBUG_HEXDUMPC(body, strlen(body), 0x10); | 902 DEBUG_HEXDUMPC(body, strlen(body), 0x10); |
836 b64 = 1; | 903 b64 = 1; |
837 break; | 904 break; |
838 } | 905 } |
839 b++; | 906 b++; |
840 } | 907 } |
908 DEBUG_RET(); | |
841 return b64; | 909 return b64; |
842 } | 910 } |
843 | 911 |
844 | 912 |
845 void find_html_charset(char *html, char *charset, size_t charsetlen) | 913 void find_html_charset(char *html, char *charset, size_t charsetlen) |
846 { | 914 { |
847 const int index = 1; | 915 const int index = 1; |
848 const int nmatch = index+1; | 916 const int nmatch = index+1; |
849 regmatch_t match[nmatch]; | 917 regmatch_t match[nmatch]; |
918 DEBUG_ENT("find_html_charset"); | |
850 int rc = regexec(&meta_charset_pattern, html, nmatch, match, 0); | 919 int rc = regexec(&meta_charset_pattern, html, nmatch, match, 0); |
851 if (rc == 0) { | 920 if (rc == 0) { |
852 int s = match[index].rm_so; | 921 int s = match[index].rm_so; |
853 int e = match[index].rm_eo; | 922 int e = match[index].rm_eo; |
854 if (s != -1) { | 923 if (s != -1) { |
864 } | 933 } |
865 } | 934 } |
866 else { | 935 else { |
867 DEBUG_EMAIL(("regexec returns %d\n", rc)); | 936 DEBUG_EMAIL(("regexec returns %d\n", rc)); |
868 } | 937 } |
938 DEBUG_RET(); | |
939 } | |
940 | |
941 | |
942 void find_rfc822_headers(char** extra_mime_headers) | |
943 { | |
944 DEBUG_ENT("find_rfc822_headers"); | |
945 char *headers = *extra_mime_headers; | |
946 if (headers) { | |
947 char *temp, *t; | |
948 while (temp = strstr(headers, "\n\n")) { | |
949 temp[1] = '\0'; | |
950 t = header_get_field(headers, "\nContent-Type: "); | |
951 if (t) { | |
952 t++; | |
953 DEBUG_EMAIL(("found content type header\n")); | |
954 char *n = strchr(t, '\n'); | |
955 char *s = strstr(t, ": "); | |
956 char *e = strchr(t, ';'); | |
957 if (!e || (e > n)) e = n; | |
958 if (s && (s < e)) { | |
959 s += 2; | |
960 if (!strncasecmp(s, RFC822, e-s)) { | |
961 headers = temp+2; // found rfc822 header | |
962 DEBUG_EMAIL(("found 822 headers\n%s\n", headers)); | |
963 break; | |
964 } | |
965 } | |
966 } | |
967 DEBUG_EMAIL(("skipping to next block after\n%s\n", headers)); | |
968 headers = temp+2; // skip to next chunk of headers | |
969 } | |
970 *extra_mime_headers = headers; | |
971 } | |
972 DEBUG_RET(); | |
869 } | 973 } |
870 | 974 |
871 | 975 |
872 void write_body_part(FILE* f_output, char *body, char *mime, char *charset, char *boundary) | 976 void write_body_part(FILE* f_output, char *body, char *mime, char *charset, char *boundary) |
873 { | 977 { |
874 char *needfree = NULL; | 978 char *needfree = NULL; |
979 DEBUG_ENT("write_body_part"); | |
875 if (strcasecmp("utf-8", charset)) { | 980 if (strcasecmp("utf-8", charset)) { |
876 // try to convert to the specified charset since it is not utf-8 | 981 // try to convert to the specified charset since it is not utf-8 |
877 size_t rc; | 982 size_t rc; |
878 DEBUG_EMAIL(("Convert %s utf-8 to %s\n", mime, charset)); | 983 DEBUG_EMAIL(("Convert %s utf-8 to %s\n", mime, charset)); |
879 vbuf *newer = vballoc(2); | 984 vbuf *newer = vballoc(2); |
904 } | 1009 } |
905 else { | 1010 else { |
906 write_email_body(f_output, body); | 1011 write_email_body(f_output, body); |
907 } | 1012 } |
908 if (needfree) free(needfree); | 1013 if (needfree) free(needfree); |
909 } | 1014 DEBUG_RET(); |
910 | 1015 } |
911 | 1016 |
912 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf) | 1017 |
1018 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf, char** extra_mime_headers) | |
913 { | 1019 { |
914 char boundary[60]; | 1020 char boundary[60]; |
915 char body_charset[60]; | 1021 char body_charset[60]; |
1022 char body_report[60]; | |
916 char sender[60]; | 1023 char sender[60]; |
917 int sender_known = 0; | 1024 int sender_known = 0; |
918 char *temp = NULL; | 1025 char *temp = NULL; |
919 int attach_num; | 1026 int attach_num; |
920 time_t em_time; | 1027 time_t em_time; |
921 char *c_time; | 1028 char *c_time; |
922 int has_from, has_subject, has_to, has_cc, has_date; | 1029 char *headers = (item->email->header) ? item->email->header : *extra_mime_headers; |
923 has_from = has_subject = has_to = has_cc = has_date = 0; | 1030 int has_from, has_subject, has_to, has_cc, has_date, has_msgid; |
1031 has_from = has_subject = has_to = has_cc = has_date = has_msgid = 0; | |
924 DEBUG_ENT("write_normal_email"); | 1032 DEBUG_ENT("write_normal_email"); |
925 | 1033 |
926 // setup default body character set | 1034 // setup default body character set and report type |
927 snprintf(body_charset, sizeof(body_charset), "%s", (item->email->body_charset) ? item->email->body_charset : "utf-8"); | 1035 snprintf(body_charset, sizeof(body_charset), "%s", (item->email->body_charset) ? item->email->body_charset : "utf-8"); |
1036 body_report[0] = '\0'; | |
928 | 1037 |
929 // setup default sender | 1038 // setup default sender |
930 if (item->email->sender_address && strchr(item->email->sender_address, '@')) { | 1039 if (item->email->sender_address && strchr(item->email->sender_address, '@')) { |
931 temp = item->email->sender_address; | 1040 temp = item->email->sender_address; |
932 sender_known = 1; | 1041 sender_known = 1; |
949 | 1058 |
950 // create our MIME boundary here. | 1059 // create our MIME boundary here. |
951 snprintf(boundary, sizeof(boundary), "--boundary-LibPST-iamunique-%i_-_-", rand()); | 1060 snprintf(boundary, sizeof(boundary), "--boundary-LibPST-iamunique-%i_-_-", rand()); |
952 | 1061 |
953 // we will always look at the headers to discover some stuff | 1062 // we will always look at the headers to discover some stuff |
954 if (item->email->header ) { | 1063 if (headers ) { |
955 char *t; | 1064 char *t; |
956 removeCR(item->email->header); | 1065 removeCR(headers); |
957 | 1066 |
958 // some of the headers we get from the file are not properly defined. | 1067 temp = strstr(headers, "\n\n"); |
959 // they can contain some email stuff too. We will cut off the header | |
960 // when we see a \n\n | |
961 temp = strstr(item->email->header, "\n\n"); | |
962 if (temp) { | 1068 if (temp) { |
963 temp[1] = '\0'; // stop after first \n | 1069 // cut off our real rfc822 headers here |
964 DEBUG_EMAIL(("Found body text in header %s\n", temp+2)); | 1070 temp[1] = '\0'; |
1071 // pointer to all the embedded MIME headers. | |
1072 // we use these to find the actual rfc822 headers for embedded message/rfc822 mime parts | |
1073 *extra_mime_headers = temp+2; | |
1074 DEBUG_EMAIL(("Found extra mime headers\n%s\n", temp+2)); | |
965 } | 1075 } |
966 | 1076 |
967 // Check if the headers have all the necessary fields | 1077 // Check if the headers have all the necessary fields |
968 header_has_field(item->email->header, "\nFrom: ", &has_from); | 1078 header_has_field(headers, "\nFrom: ", &has_from); |
969 header_has_field(item->email->header, "\nTo: ", &has_to); | 1079 header_has_field(headers, "\nTo: ", &has_to); |
970 header_has_field(item->email->header, "\nSubject: ", &has_subject); | 1080 header_has_field(headers, "\nSubject: ", &has_subject); |
971 header_has_field(item->email->header, "\nDate: ", &has_date); | 1081 header_has_field(headers, "\nDate: ", &has_date); |
972 header_has_field(item->email->header, "\nCC: ", &has_cc); | 1082 header_has_field(headers, "\nCC: ", &has_cc); |
973 | 1083 header_has_field(headers, "\nMessage-Id: ", &has_msgid); |
974 // look for charset in Content-Type header | 1084 |
975 t = header_get_field(item->email->header, "\nContent-Type: "); | 1085 // look for charset and report-type in Content-Type header |
976 if (t) { | 1086 t = header_get_field(headers, "\nContent-Type: "); |
977 // assume charset= will be on the first line, rather than on a continuation line | 1087 header_get_subfield(t, "charset", body_charset, sizeof(body_charset)); |
978 t++; | 1088 header_get_subfield(t, "report-type", body_report, sizeof(body_report)); |
979 char *n = strchr(t, '\n'); | |
980 char *s = my_stristr(t, "; charset="); | |
981 if (n && s && (s < n)) { | |
982 char *e; | |
983 char save; | |
984 s += 10; // skip over charset= | |
985 if (*s == '"') { | |
986 s++; | |
987 e = strchr(s, '"'); | |
988 } | |
989 else { | |
990 e = strchr(s, ';'); | |
991 } | |
992 if (!e || (e > n)) e = n; // use the trailing lf as terminator if nothing better | |
993 save = *e; | |
994 *e = '\0'; | |
995 snprintf(body_charset, sizeof(body_charset), "%s", s); // copy the charset to our buffer | |
996 *e = save; | |
997 DEBUG_EMAIL(("body charset %s from headers\n", body_charset)); | |
998 } | |
999 } | |
1000 | 1089 |
1001 // derive a proper sender email address | 1090 // derive a proper sender email address |
1002 if (!sender_known) { | 1091 if (!sender_known) { |
1003 t = header_get_field(item->email->header, "\nFrom: "); | 1092 t = header_get_field(headers, "\nFrom: "); |
1004 if (t) { | 1093 if (t) { |
1005 // assume address is on the first line, rather than on a continuation line | 1094 // assume address is on the first line, rather than on a continuation line |
1006 t++; | 1095 t++; |
1007 char *n = strchr(t, '\n'); | 1096 char *n = strchr(t, '\n'); |
1008 char *s = strchr(t, '<'); | 1097 char *s = strchr(t, '<'); |
1015 } | 1104 } |
1016 } | 1105 } |
1017 } | 1106 } |
1018 | 1107 |
1019 // Strip out the mime headers and some others that we don't want to emit | 1108 // Strip out the mime headers and some others that we don't want to emit |
1020 header_strip_field(item->email->header, "\nMicrosoft Mail Internet Headers"); | 1109 header_strip_field(headers, "\nMicrosoft Mail Internet Headers"); |
1021 header_strip_field(item->email->header, "\nMIME-Version: "); | 1110 header_strip_field(headers, "\nMIME-Version: "); |
1022 header_strip_field(item->email->header, "\nContent-Type: "); | 1111 header_strip_field(headers, "\nContent-Type: "); |
1023 header_strip_field(item->email->header, "\nContent-Transfer-Encoding: "); | 1112 header_strip_field(headers, "\nContent-Transfer-Encoding: "); |
1024 header_strip_field(item->email->header, "\nContent-class: "); | 1113 header_strip_field(headers, "\nContent-class: "); |
1025 header_strip_field(item->email->header, "\nX-MimeOLE: "); | 1114 header_strip_field(headers, "\nX-MimeOLE: "); |
1026 header_strip_field(item->email->header, "\nBcc:"); | 1115 header_strip_field(headers, "\nBcc:"); |
1027 header_strip_field(item->email->header, "\nX-From_: "); | 1116 header_strip_field(headers, "\nX-From_: "); |
1028 } | 1117 } |
1029 | 1118 |
1030 DEBUG_EMAIL(("About to print Header\n")); | 1119 DEBUG_EMAIL(("About to print Header\n")); |
1031 | 1120 |
1032 if (item && item->email && item->email->subject && item->email->subject->subj) { | 1121 if (item && item->email && item->email->subject && item->email->subject->subj) { |
1033 DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj)); | 1122 DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj)); |
1034 } | 1123 } |
1035 | 1124 |
1036 if (mode != MODE_SEPARATE) { | 1125 if (mode != MODE_SEPARATE) { |
1037 // most modes need this separator line | 1126 // most modes need this separator line |
1038 fprintf(f_output, "From \"%s\" %s\n", sender, c_time); | 1127 fprintf(f_output, "From %s %s\n", sender, c_time); |
1039 } | 1128 } |
1040 | 1129 |
1041 if (item->email->header) { | 1130 // print the supplied email headers |
1131 if (headers) { | |
1042 int len; | 1132 int len; |
1043 fprintf(f_output, "%s", item->email->header); | 1133 fprintf(f_output, "%s", headers); |
1044 // make sure the headers end with a \n | 1134 // make sure the headers end with a \n |
1045 len = strlen(item->email->header); | 1135 len = strlen(headers); |
1046 if (!len || (item->email->header[len-1] != '\n')) fprintf(f_output, "\n"); | 1136 if (!len || (headers[len-1] != '\n')) fprintf(f_output, "\n"); |
1047 } | 1137 } |
1048 | 1138 |
1049 // create required header fields that are not already written | 1139 // create required header fields that are not already written |
1140 | |
1050 if (!has_from) { | 1141 if (!has_from) { |
1051 fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, sender); | 1142 fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, sender); |
1052 } | 1143 } |
1053 | 1144 |
1054 if (!has_subject) { | 1145 if (!has_subject) { |
1071 char c_time[C_TIME_SIZE]; | 1162 char c_time[C_TIME_SIZE]; |
1072 strftime(c_time, C_TIME_SIZE, "%a, %d %b %Y %H:%M:%S %z", gmtime(&em_time)); | 1163 strftime(c_time, C_TIME_SIZE, "%a, %d %b %Y %H:%M:%S %z", gmtime(&em_time)); |
1073 fprintf(f_output, "Date: %s\n", c_time); | 1164 fprintf(f_output, "Date: %s\n", c_time); |
1074 } | 1165 } |
1075 | 1166 |
1167 if (!has_msgid && item->email->messageid) { | |
1168 fprintf(f_output, "Message-Id: %s\n", item->email->messageid); | |
1169 } | |
1170 | |
1076 // add forensic headers to capture some .pst stuff that is not really | 1171 // add forensic headers to capture some .pst stuff that is not really |
1077 // needed or used by mail clients | 1172 // needed or used by mail clients |
1078 if (item->email->sender_address && !strchr(item->email->sender_address, '@')) { | 1173 if (item->email->sender_address && !strchr(item->email->sender_address, '@') |
1174 && strcmp(item->email->sender_address, ".")) { | |
1079 fprintf(f_output, "X-libpst-forensic-sender: %s\n", item->email->sender_address); | 1175 fprintf(f_output, "X-libpst-forensic-sender: %s\n", item->email->sender_address); |
1080 } | 1176 } |
1081 | 1177 |
1082 if (item->email->bcc_address) { | 1178 if (item->email->bcc_address) { |
1083 fprintf(f_output, "X-libpst-forensic-bcc: %s\n", item->email->bcc_address); | 1179 fprintf(f_output, "X-libpst-forensic-bcc: %s\n", item->email->bcc_address); |
1084 } | 1180 } |
1085 | 1181 |
1086 // add our own mime headers | 1182 // add our own mime headers |
1087 fprintf(f_output, "MIME-Version: 1.0\n"); | 1183 fprintf(f_output, "MIME-Version: 1.0\n"); |
1088 if (item->attach || (item->email->rtf_compressed && save_rtf) | 1184 if (body_report[0] != '\0') { |
1089 || item->email->encrypted_body | 1185 // multipart/report for DSN/MDN reports |
1090 || item->email->encrypted_htmlbody) { | 1186 fprintf(f_output, "Content-Type: multipart/report; report-type=%s;\n\tboundary=\"%s\"\n", body_report, boundary); |
1187 } | |
1188 else if (item->attach || (item->email->rtf_compressed && save_rtf) | |
1189 || item->email->encrypted_body | |
1190 || item->email->encrypted_htmlbody) { | |
1091 // use multipart/mixed if we have attachments | 1191 // use multipart/mixed if we have attachments |
1092 fprintf(f_output, "Content-Type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary); | 1192 fprintf(f_output, "Content-Type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary); |
1093 } else { | 1193 } else { |
1094 // else use multipart/alternative | 1194 // else use multipart/alternative |
1095 fprintf(f_output, "Content-Type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary); | 1195 fprintf(f_output, "Content-Type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary); |
1149 { | 1249 { |
1150 pst_item_attach* attach; | 1250 pst_item_attach* attach; |
1151 attach_num = 0; | 1251 attach_num = 0; |
1152 for (attach = item->attach; attach; attach = attach->next) { | 1252 for (attach = item->attach; attach; attach = attach->next) { |
1153 DEBUG_EMAIL(("Attempting Attachment encoding\n")); | 1253 DEBUG_EMAIL(("Attempting Attachment encoding\n")); |
1154 if (!attach->data) { | 1254 if (!attach->data && attach->mimetype && !strcmp(attach->mimetype, RFC822)) { |
1155 DEBUG_EMAIL(("Data of attachment is NULL!. Size is supposed to be %i\n", attach->size)); | 1255 DEBUG_EMAIL(("seem to have special embedded message attachment\n")); |
1256 find_rfc822_headers(extra_mime_headers); | |
1257 write_embedded_message(f_output, attach, boundary, pst, extra_mime_headers); | |
1156 } | 1258 } |
1157 if (mode == MODE_SEPARATE && !mode_MH) | 1259 else if (mode == MODE_SEPARATE && !mode_MH) |
1158 write_separate_attachment(f_name, attach, ++attach_num, pst); | 1260 write_separate_attachment(f_name, attach, ++attach_num, pst); |
1159 else | 1261 else |
1160 write_inline_attachment(f_output, attach, boundary, pst); | 1262 write_inline_attachment(f_output, attach, boundary, pst); |
1161 } | 1263 } |
1162 } | 1264 } |