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 }