23 #include "mrmailbox_internal.h" 24 #include "mrmimeparser.h" 25 #include "mrmimefactory.h" 26 #include "mrsimplify.h" 34 #ifdef MR_USE_MIME_DEBUG 40 static void display_mime_content(
struct mailmime_content * content_type);
42 static void display_mime_data(
struct mailmime_data * data)
44 switch (data->dt_type) {
45 case MAILMIME_DATA_TEXT:
46 printf(
"data : %i bytes\n", (
int) data->dt_data.dt_text.dt_length);
48 case MAILMIME_DATA_FILE:
49 printf(
"data (file) : %s\n", data->dt_data.dt_filename);
54 static void display_mime_dsp_parm(
struct mailmime_disposition_parm * param)
56 switch (param->pa_type) {
57 case MAILMIME_DISPOSITION_PARM_FILENAME:
58 printf(
"filename: %s\n", param->pa_data.pa_filename);
63 static void display_mime_disposition(
struct mailmime_disposition * disposition)
67 for(cur = clist_begin(disposition->dsp_parms) ;
68 cur != NULL ; cur = clist_next(cur)) {
69 struct mailmime_disposition_parm * param;
71 param = (
struct mailmime_disposition_parm*)clist_content(cur);
72 display_mime_dsp_parm(param);
76 static void display_mime_field(
struct mailmime_field * field)
78 switch (field->fld_type) {
79 case MAILMIME_FIELD_TYPE:
80 printf(
"content-type: ");
81 display_mime_content(field->fld_data.fld_content);
84 case MAILMIME_FIELD_DISPOSITION:
85 display_mime_disposition(field->fld_data.fld_disposition);
90 static void display_mime_fields(
struct mailmime_fields * fields)
94 for(cur = clist_begin(fields->fld_list) ; cur != NULL ; cur = clist_next(cur)) {
95 struct mailmime_field * field;
97 field = (
struct mailmime_field*)clist_content(cur);
98 display_mime_field(field);
102 static void display_date_time(
struct mailimf_date_time * d)
104 printf(
"%02i/%02i/%i %02i:%02i:%02i %+04i",
105 d->dt_day, d->dt_month, d->dt_year,
106 d->dt_hour, d->dt_min, d->dt_sec, d->dt_zone);
109 static void display_orig_date(
struct mailimf_orig_date * orig_date)
111 display_date_time(orig_date->dt_date_time);
114 static void display_mailbox(
struct mailimf_mailbox * mb)
116 if (mb->mb_display_name != NULL)
117 printf(
"%s ", mb->mb_display_name);
118 printf(
"<%s>", mb->mb_addr_spec);
121 static void display_mailbox_list(
struct mailimf_mailbox_list * mb_list)
125 for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ;
126 cur = clist_next(cur)) {
127 struct mailimf_mailbox * mb;
129 mb = (
struct mailimf_mailbox*)clist_content(cur);
132 if (clist_next(cur) != NULL) {
138 static void display_group(
struct mailimf_group * group)
142 printf(
"%s: ", group->grp_display_name);
143 for(cur = clist_begin(group->grp_mb_list->mb_list) ; cur != NULL ; cur = clist_next(cur)) {
144 struct mailimf_mailbox * mb;
146 mb = (
struct mailimf_mailbox*)clist_content(cur);
152 static void display_address(
struct mailimf_address * a)
154 switch (a->ad_type) {
155 case MAILIMF_ADDRESS_GROUP:
156 display_group(a->ad_data.ad_group);
159 case MAILIMF_ADDRESS_MAILBOX:
160 display_mailbox(a->ad_data.ad_mailbox);
165 static void display_address_list(
struct mailimf_address_list * addr_list)
169 for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
170 cur = clist_next(cur)) {
171 struct mailimf_address * addr;
173 addr = (
struct mailimf_address*)clist_content(cur);
175 display_address(addr);
177 if (clist_next(cur) != NULL) {
183 static void display_from(
struct mailimf_from * from)
185 display_mailbox_list(from->frm_mb_list);
188 static void display_to(
struct mailimf_to * to)
190 display_address_list(to->to_addr_list);
193 static void display_cc(
struct mailimf_cc * cc)
195 display_address_list(cc->cc_addr_list);
198 static void display_subject(
struct mailimf_subject * subject)
200 printf(
"%s", subject->sbj_value);
203 static void display_field(
struct mailimf_field * field)
205 switch (field->fld_type) {
206 case MAILIMF_FIELD_ORIG_DATE:
208 display_orig_date(field->fld_data.fld_orig_date);
211 case MAILIMF_FIELD_FROM:
213 display_from(field->fld_data.fld_from);
216 case MAILIMF_FIELD_TO:
218 display_to(field->fld_data.fld_to);
221 case MAILIMF_FIELD_CC:
223 display_cc(field->fld_data.fld_cc);
226 case MAILIMF_FIELD_SUBJECT:
228 display_subject(field->fld_data.fld_subject);
231 case MAILIMF_FIELD_MESSAGE_ID:
232 printf(
"Message-ID: %s\n", field->fld_data.fld_message_id->mid_value);
237 static void display_fields(
struct mailimf_fields * fields)
241 for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
242 cur = clist_next(cur)) {
243 struct mailimf_field * f;
245 f = (
struct mailimf_field*)clist_content(cur);
251 static void display_mime_discrete_type(
struct mailmime_discrete_type * discrete_type)
253 switch (discrete_type->dt_type) {
254 case MAILMIME_DISCRETE_TYPE_TEXT:
257 case MAILMIME_DISCRETE_TYPE_IMAGE:
260 case MAILMIME_DISCRETE_TYPE_AUDIO:
263 case MAILMIME_DISCRETE_TYPE_VIDEO:
266 case MAILMIME_DISCRETE_TYPE_APPLICATION:
267 printf(
"application");
269 case MAILMIME_DISCRETE_TYPE_EXTENSION:
270 printf(
"%s", discrete_type->dt_extension);
275 static void display_mime_composite_type(
struct mailmime_composite_type * ct)
277 switch (ct->ct_type) {
278 case MAILMIME_COMPOSITE_TYPE_MESSAGE:
281 case MAILMIME_COMPOSITE_TYPE_MULTIPART:
284 case MAILMIME_COMPOSITE_TYPE_EXTENSION:
285 printf(
"%s", ct->ct_token);
290 static void display_mime_type(
struct mailmime_type * type)
292 switch (type->tp_type) {
293 case MAILMIME_TYPE_DISCRETE_TYPE:
294 display_mime_discrete_type(type->tp_data.tp_discrete_type);
296 case MAILMIME_TYPE_COMPOSITE_TYPE:
297 display_mime_composite_type(type->tp_data.tp_composite_type);
302 static void display_mime_content(
struct mailmime_content * content_type)
305 display_mime_type(content_type->ct_type);
306 printf(
"/%s\n", content_type->ct_subtype);
309 static void print_mime(
struct mailmime * mime)
314 printf(
"ERROR: NULL given to print_mime()\n");
318 switch (mime->mm_type) {
319 case MAILMIME_SINGLE:
320 printf(
"single part\n");
322 case MAILMIME_MULTIPLE:
323 printf(
"multipart\n");
325 case MAILMIME_MESSAGE:
330 if (mime->mm_mime_fields != NULL) {
331 if (clist_begin(mime->mm_mime_fields->fld_list) != NULL) {
332 printf(
"--------------------------------<mime-headers>--------------------------------\n");
333 display_mime_fields(mime->mm_mime_fields);
334 printf(
"--------------------------------</mime-headers>-------------------------------\n");
338 display_mime_content(mime->mm_content_type);
340 switch (mime->mm_type) {
341 case MAILMIME_SINGLE:
342 display_mime_data(mime->mm_data.mm_single);
345 case MAILMIME_MULTIPLE:
346 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ; cur != NULL ; cur = clist_next(cur)) {
347 printf(
"---------------------------<mime-part-of-multiple>----------------------------\n");
348 print_mime((
struct mailmime*)clist_content(cur));
349 printf(
"---------------------------</mime-part-of-multiple>---------------------------\n");
353 case MAILMIME_MESSAGE:
354 if (mime->mm_data.mm_message.mm_fields) {
355 if (clist_begin(mime->mm_data.mm_message.mm_fields->fld_list) != NULL) {
356 printf(
"-------------------------------<email-headers>--------------------------------\n");
357 display_fields(mime->mm_data.mm_message.mm_fields);
358 printf(
"-------------------------------</email-headers>-------------------------------\n");
361 if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
362 printf(
"----------------------------<mime-part-of-message>----------------------------\n");
363 print_mime(mime->mm_data.mm_message.mm_msg_mime);
364 printf(
"----------------------------</mime-part-of-message>---------------------------\n");
372 void mr_print_mime(
struct mailmime* mime)
374 printf(
"====================================<mime>====================================\n");
376 printf(
"====================================</mime>===================================\n\n");
388 struct mailimf_fields* mr_find_mailimf_fields(
struct mailmime* mime)
395 switch (mime->mm_type) {
396 case MAILMIME_MULTIPLE:
397 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ; cur != NULL ; cur = clist_next(cur)) {
398 struct mailimf_fields* header = mr_find_mailimf_fields(clist_content(cur));
405 case MAILMIME_MESSAGE:
406 return mime->mm_data.mm_message.mm_fields;
413 struct mailimf_field* mr_find_mailimf_field(
struct mailimf_fields* header,
int wanted_fld_type)
415 if( header == NULL || header->fld_list == NULL ) {
420 for( cur1 = clist_begin(header->fld_list); cur1!=NULL ; cur1=clist_next(cur1) )
422 struct mailimf_field* field = (
struct mailimf_field*)clist_content(cur1);
425 if( field->fld_type == wanted_fld_type ) {
435 struct mailimf_optional_field* mr_find_mailimf_field2(
struct mailimf_fields* header,
const char* wanted_fld_name)
438 if( header == NULL || header->fld_list == NULL ) {
443 for( cur1 = clist_begin(header->fld_list); cur1!=NULL ; cur1=clist_next(cur1) )
445 struct mailimf_field* field = (
struct mailimf_field*)clist_content(cur1);
446 if( field && field->fld_type == MAILIMF_FIELD_OPTIONAL_FIELD )
448 struct mailimf_optional_field* optional_field = field->fld_data.fld_optional_field;
449 if( optional_field && optional_field->fld_name && optional_field->fld_value && strcasecmp(optional_field->fld_name, wanted_fld_name)==0 ) {
450 return optional_field;
459 struct mailmime_parameter* mr_find_ct_parameter(
struct mailmime* mime,
const char* name)
462 if( mime==NULL || name==NULL
463 || mime->mm_content_type==NULL || mime->mm_content_type->ct_parameters==NULL )
469 for( cur = clist_begin(mime->mm_content_type->ct_parameters); cur != NULL; cur = clist_next(cur) ) {
470 struct mailmime_parameter* param = (
struct mailmime_parameter*)clist_content(cur);
471 if( param && param->pa_name ) {
472 if( strcmp(param->pa_name, name)==0 ) {
482 char* mr_normalize_addr(
const char* addr__)
486 char* addr = safe_strdup(addr__);
488 if( strncmp(addr,
"mailto:", 7)==0 ) {
490 addr = safe_strdup(&old[7]);
498 char* mr_find_first_addr(
const struct mailimf_mailbox_list* mb_list)
502 if( mb_list == NULL ) {
506 for( cur = clist_begin(mb_list->mb_list); cur!=NULL ; cur=clist_next(cur) ) {
507 struct mailimf_mailbox* mb = (
struct mailimf_mailbox*)clist_content(cur);
508 if( mb && mb->mb_addr_spec ) {
509 return mr_normalize_addr(mb->mb_addr_spec);
521 static mrmimepart_t* mrmimepart_new(
void)
523 mrmimepart_t* ths = NULL;
525 if( (ths=calloc(1,
sizeof(mrmimepart_t)))==NULL ) {
529 ths->m_type = MR_MSG_UNDEFINED;
536 static void mrmimepart_unref(mrmimepart_t* ths)
547 if( ths->m_msg_raw ) {
548 free(ths->m_msg_raw);
549 ths->m_msg_raw = NULL;
562 mrmimeparser_t* mrmimeparser_new(
const char* blobdir,
mrmailbox_t* mailbox)
564 mrmimeparser_t* ths = NULL;
566 if( (ths=calloc(1,
sizeof(mrmimeparser_t)))==NULL ) {
570 ths->m_mailbox = mailbox;
571 ths->m_parts = carray_new(16);
572 ths->m_blobdir = blobdir;
573 ths->m_reports = carray_new(16);
579 void mrmimeparser_unref(mrmimeparser_t* ths)
585 mrmimeparser_empty(ths);
586 if( ths->m_parts ) { carray_free(ths->m_parts); }
587 if( ths->m_reports ) { carray_free(ths->m_reports); }
592 void mrmimeparser_empty(mrmimeparser_t* ths)
600 int i, cnt = carray_count(ths->m_parts);
601 for( i = 0; i < cnt; i++ ) {
602 mrmimepart_t* part = (mrmimepart_t*)carray_get(ths->m_parts, i);
604 mrmimepart_unref(part);
607 carray_set_size(ths->m_parts, 0);
610 ths->m_header = NULL;
611 ths->m_is_send_by_messenger = 0;
612 ths->m_is_system_message = 0;
614 free(ths->m_subject);
615 ths->m_subject = NULL;
617 if( ths->m_mimeroot )
619 mailmime_free(ths->m_mimeroot);
620 ths->m_mimeroot = NULL;
623 ths->m_is_forwarded = 0;
625 if( ths->m_reports ) {
626 carray_set_size(ths->m_reports, 0);
629 ths->m_decrypted_and_validated = 0;
630 ths->m_decrypted_with_validation_errors = 0;
631 ths->m_decrypting_failed = 0;
635 static int is_attachment_disposition(
struct mailmime* mime)
637 if( mime->mm_mime_fields != NULL ) {
639 for( cur = clist_begin(mime->mm_mime_fields->fld_list); cur != NULL; cur = clist_next(cur) ) {
640 struct mailmime_field* field = (
struct mailmime_field*)clist_content(cur);
641 if( field && field->fld_type == MAILMIME_FIELD_DISPOSITION && field->fld_data.fld_disposition ) {
642 if( field->fld_data.fld_disposition->dsp_type
643 && field->fld_data.fld_disposition->dsp_type->dsp_type==MAILMIME_DISPOSITION_TYPE_ATTACHMENT )
654 static int mrmimeparser_get_mime_type(
struct mailmime* mime,
int* msg_type)
656 #define MR_MIMETYPE_MP_ALTERNATIVE 10 657 #define MR_MIMETYPE_MP_RELATED 20 658 #define MR_MIMETYPE_MP_MIXED 30 659 #define MR_MIMETYPE_MP_NOT_DECRYPTABLE 40 660 #define MR_MIMETYPE_MP_REPORT 45 661 #define MR_MIMETYPE_MP_SIGNED 46 662 #define MR_MIMETYPE_MP_OTHER 50 663 #define MR_MIMETYPE_TEXT_PLAIN 60 664 #define MR_MIMETYPE_TEXT_HTML 70 665 #define MR_MIMETYPE_IMAGE 80 666 #define MR_MIMETYPE_AUDIO 90 667 #define MR_MIMETYPE_VIDEO 100 668 #define MR_MIMETYPE_FILE 110 670 struct mailmime_content* c = mime->mm_content_type;
671 int dummy;
if( msg_type == NULL ) { msg_type = &dummy; }
672 *msg_type = MR_MSG_UNDEFINED;
674 if( c == NULL || c->ct_type == NULL ) {
678 switch( c->ct_type->tp_type )
680 case MAILMIME_TYPE_DISCRETE_TYPE:
681 switch( c->ct_type->tp_data.tp_discrete_type->dt_type )
683 case MAILMIME_DISCRETE_TYPE_TEXT:
684 if( is_attachment_disposition(mime) ) {
687 else if( strcmp(c->ct_subtype,
"plain")==0 ) {
688 *msg_type = MR_MSG_TEXT;
689 return MR_MIMETYPE_TEXT_PLAIN;
691 else if( strcmp(c->ct_subtype,
"html")==0 ) {
692 *msg_type = MR_MSG_TEXT;
693 return MR_MIMETYPE_TEXT_HTML;
695 *msg_type = MR_MSG_FILE;
696 return MR_MIMETYPE_FILE;
698 case MAILMIME_DISCRETE_TYPE_IMAGE:
699 if( strcmp(c->ct_subtype,
"gif")==0 ) {
700 *msg_type = MR_MSG_GIF;
703 *msg_type = MR_MSG_IMAGE;
705 return MR_MIMETYPE_IMAGE;
707 case MAILMIME_DISCRETE_TYPE_AUDIO:
708 *msg_type = MR_MSG_AUDIO;
709 return MR_MIMETYPE_AUDIO;
711 case MAILMIME_DISCRETE_TYPE_VIDEO:
712 *msg_type = MR_MSG_VIDEO;
713 return MR_MIMETYPE_VIDEO;
716 *msg_type = MR_MSG_FILE;
717 return MR_MIMETYPE_FILE;
721 case MAILMIME_TYPE_COMPOSITE_TYPE:
722 if( c->ct_type->tp_data.tp_composite_type->ct_type == MAILMIME_COMPOSITE_TYPE_MULTIPART )
724 if( strcmp(c->ct_subtype,
"alternative")==0 ) {
725 return MR_MIMETYPE_MP_ALTERNATIVE;
727 else if( strcmp(c->ct_subtype,
"related")==0 ) {
728 return MR_MIMETYPE_MP_RELATED;
730 else if( strcmp(c->ct_subtype,
"encrypted")==0 ) {
731 return MR_MIMETYPE_MP_NOT_DECRYPTABLE;
733 else if( strcmp(c->ct_subtype,
"signed")==0 ) {
734 return MR_MIMETYPE_MP_SIGNED;
736 else if( strcmp(c->ct_subtype,
"mixed")==0 ) {
737 return MR_MIMETYPE_MP_MIXED;
739 else if( strcmp(c->ct_subtype,
"report")==0 ) {
740 return MR_MIMETYPE_MP_REPORT;
743 return MR_MIMETYPE_MP_OTHER;
746 else if( c->ct_type->tp_data.tp_composite_type->ct_type == MAILMIME_COMPOSITE_TYPE_MESSAGE )
766 static char* get_file_disposition_suffix_(
struct mailmime_disposition* file_disposition)
768 if( file_disposition ) {
770 for( cur = clist_begin(file_disposition->dsp_parms); cur != NULL; cur = clist_next(cur) ) {
771 struct mailmime_disposition_parm* dsp_param = (
struct mailmime_disposition_parm*)clist_content(cur);
773 if( dsp_param->pa_type==MAILMIME_DISPOSITION_PARM_FILENAME ) {
774 return mr_get_filesuffix_lc(dsp_param->pa_data.pa_filename);
784 int mr_mime_transfer_decode(
struct mailmime* mime,
const char** ret_decoded_data,
size_t* ret_decoded_data_bytes,
char** ret_to_mmap_string_unref)
786 int mime_transfer_encoding = MAILMIME_MECHANISM_BINARY;
787 struct mailmime_data* mime_data = mime->mm_data.mm_single;
788 const char* decoded_data = NULL;
789 size_t decoded_data_bytes = 0;
790 char* transfer_decoding_buffer = NULL;
792 if( mime == NULL || ret_decoded_data == NULL || ret_decoded_data_bytes == NULL || ret_to_mmap_string_unref == NULL
793 || *ret_decoded_data != NULL || *ret_decoded_data_bytes != 0 || *ret_to_mmap_string_unref != NULL ) {
797 if( mime->mm_mime_fields != NULL ) {
799 for( cur = clist_begin(mime->mm_mime_fields->fld_list); cur != NULL; cur = clist_next(cur) ) {
800 struct mailmime_field* field = (
struct mailmime_field*)clist_content(cur);
801 if( field && field->fld_type == MAILMIME_FIELD_TRANSFER_ENCODING && field->fld_data.fld_encoding ) {
802 mime_transfer_encoding = field->fld_data.fld_encoding->enc_type;
809 if( mime_transfer_encoding == MAILMIME_MECHANISM_7BIT
810 || mime_transfer_encoding == MAILMIME_MECHANISM_8BIT
811 || mime_transfer_encoding == MAILMIME_MECHANISM_BINARY )
813 decoded_data = mime_data->dt_data.dt_text.dt_data;
814 decoded_data_bytes = mime_data->dt_data.dt_text.dt_length;
815 if( decoded_data == NULL || decoded_data_bytes <= 0 ) {
822 size_t current_index = 0;
823 r = mailmime_part_parse(mime_data->dt_data.dt_text.dt_data, mime_data->dt_data.dt_text.dt_length,
824 ¤t_index, mime_transfer_encoding,
825 &transfer_decoding_buffer, &decoded_data_bytes);
826 if( r != MAILIMF_NO_ERROR || transfer_decoding_buffer == NULL || decoded_data_bytes <= 0 ) {
829 decoded_data = transfer_decoding_buffer;
832 *ret_decoded_data = decoded_data;
833 *ret_decoded_data_bytes = decoded_data_bytes;
834 *ret_to_mmap_string_unref = transfer_decoding_buffer;
839 static int mrmimeparser_add_single_part_if_known(mrmimeparser_t* ths,
struct mailmime* mime)
841 mrmimepart_t* part = mrmimepart_new();
845 struct mailmime_data* mime_data;
846 char* pathNfilename = NULL;
847 char* file_suffix = NULL, *desired_filename = NULL;
850 char* transfer_decoding_buffer = NULL;
851 char* charset_buffer = NULL;
852 const char* decoded_data = NULL;
853 size_t decoded_data_bytes = 0;
854 mrsimplify_t* simplifier = NULL;
856 if( mime == NULL || mime->mm_data.mm_single == NULL || part == NULL ) {
861 mime_type = mrmimeparser_get_mime_type(mime, &msg_type);
864 mime_data = mime->mm_data.mm_single;
865 if( mime_data->dt_type != MAILMIME_DATA_TEXT
866 || mime_data->dt_data.dt_text.dt_data == NULL
867 || mime_data->dt_data.dt_text.dt_length <= 0 ) {
873 if( !mr_mime_transfer_decode(mime, &decoded_data, &decoded_data_bytes, &transfer_decoding_buffer) ) {
879 case MR_MIMETYPE_TEXT_PLAIN:
880 case MR_MIMETYPE_TEXT_HTML:
882 if( simplifier==NULL ) {
883 simplifier = mrsimplify_new();
884 if( simplifier==NULL ) {
889 const char* charset = mailmime_content_charset_get(mime->mm_content_type);
890 if( charset!=NULL && strcmp(charset,
"utf-8")!=0 && strcmp(charset,
"UTF-8")!=0 ) {
891 size_t ret_bytes = 0;
892 int r = charconv_buffer(
"utf-8", charset, decoded_data, decoded_data_bytes, &charset_buffer, &ret_bytes);
893 if( r != MAIL_CHARCONV_NO_ERROR ) {
894 mrmailbox_log_warning(ths->m_mailbox, 0,
"Cannot convert %i bytes from \"%s\" to \"utf-8\"; errorcode is %i.",
895 (
int)decoded_data_bytes, charset, (
int)r);
897 else if( charset_buffer==NULL || ret_bytes <= 0 ) {
901 decoded_data = charset_buffer;
902 decoded_data_bytes = ret_bytes;
906 part->m_type = MR_MSG_TEXT;
907 part->m_msg_raw = strndup(decoded_data, decoded_data_bytes);
908 part->m_msg = mrsimplify_simplify(simplifier, decoded_data, decoded_data_bytes, mime_type==MR_MIMETYPE_TEXT_HTML? 1 : 0);
910 if( part->m_msg && part->m_msg[0] ) {
914 if( simplifier->m_is_forwarded ) {
915 ths->m_is_forwarded = 1;
920 case MR_MIMETYPE_IMAGE:
921 case MR_MIMETYPE_AUDIO:
922 case MR_MIMETYPE_VIDEO:
923 case MR_MIMETYPE_FILE:
926 struct mailmime_disposition* file_disposition = NULL;
928 for( cur = clist_begin(mime->mm_mime_fields->fld_list); cur != NULL; cur = clist_next(cur) ) {
929 struct mailmime_field* field = (
struct mailmime_field*)clist_content(cur);
930 if( field && field->fld_type == MAILMIME_FIELD_DISPOSITION && field->fld_data.fld_disposition ) {
931 file_disposition = field->fld_data.fld_disposition;
936 if( file_disposition ) {
937 for( cur = clist_begin(file_disposition->dsp_parms); cur != NULL; cur = clist_next(cur) ) {
938 struct mailmime_disposition_parm* dsp_param = (
struct mailmime_disposition_parm*)clist_content(cur);
940 if( dsp_param->pa_type==MAILMIME_DISPOSITION_PARM_FILENAME ) {
941 desired_filename = safe_strdup(dsp_param->pa_data.pa_filename);
947 if( desired_filename==NULL ) {
948 struct mailmime_parameter* param = mr_find_ct_parameter(mime,
"name");
949 if( param && param->pa_value && param->pa_value[0] ) {
950 desired_filename = safe_strdup(param->pa_value);
954 if( desired_filename==NULL ) {
955 if( mime->mm_content_type && mime->mm_content_type->ct_subtype ) {
956 desired_filename = mr_mprintf(
"file.%s", mime->mm_content_type->ct_subtype);
963 mr_replace_bad_utf8_chars(desired_filename);
966 if( (pathNfilename=mr_get_fine_pathNfilename(ths->m_blobdir, desired_filename)) == NULL ) {
971 if( mr_write_file(pathNfilename, decoded_data, decoded_data_bytes, ths->m_mailbox)==0 ) {
975 part->m_type = msg_type;
976 part->m_bytes = decoded_data_bytes;
977 mrparam_set(part->m_param, MRP_FILE, pathNfilename);
978 if( MR_MSG_MAKE_FILENAME_SEARCHABLE(msg_type) ) {
979 part->m_msg = mr_get_filename(pathNfilename);
981 else if( MR_MSG_MAKE_SUFFIX_SEARCHABLE(msg_type) ) {
982 part->m_msg = mr_get_filesuffix_lc(pathNfilename);
985 if( mime_type == MR_MIMETYPE_IMAGE ) {
986 uint32_t w = 0, h = 0;
987 if( mr_get_filemeta(decoded_data, decoded_data_bytes, &w, &h) ) {
994 if( msg_type == MR_MSG_AUDIO ) {
995 char* author = NULL, *title = NULL;
996 mrmsg_get_authorNtitle_from_filename(desired_filename, &author, &title);
997 mrparam_set(part->m_param, MRP_AUTHORNAME, author);
1014 mrsimplify_unref(simplifier);
1017 if( charset_buffer ) {
1018 charconv_buffer_free(charset_buffer);
1021 if( transfer_decoding_buffer ) {
1022 mmap_string_unref(transfer_decoding_buffer);
1025 free(pathNfilename);
1027 free(desired_filename);
1030 if( ths->m_decrypted_and_validated ) {
1033 else if( ths->m_decrypted_with_validation_errors ) {
1034 mrparam_set_int(part->m_param, MRP_ERRONEOUS_E2EE, ths->m_decrypted_with_validation_errors);
1036 carray_add(ths->m_parts, (
void*)part, NULL);
1040 mrmimepart_unref(part);
1046 static int mrmimeparser_parse_mime_recursive(mrmimeparser_t* ths,
struct mailmime* mime)
1048 int any_part_added = 0;
1051 if( ths == NULL || mime == NULL ) {
1055 switch( mime->mm_type )
1057 case MAILMIME_SINGLE:
1058 any_part_added = mrmimeparser_add_single_part_if_known(ths, mime);
1061 case MAILMIME_MULTIPLE:
1062 switch( mrmimeparser_get_mime_type(mime, NULL) )
1064 case MR_MIMETYPE_MP_ALTERNATIVE:
1067 for( cur=clist_begin(mime->mm_data.mm_multipart.mm_mp_list); cur!=NULL; cur=clist_next(cur)) {
1068 struct mailmime* childmime = (
struct mailmime*)clist_content(cur);
1069 if( mrmimeparser_get_mime_type(childmime, NULL) == MR_MIMETYPE_MP_MIXED ) {
1070 any_part_added = mrmimeparser_parse_mime_recursive(ths, childmime);
1076 if( !any_part_added ) {
1078 for( cur=clist_begin(mime->mm_data.mm_multipart.mm_mp_list); cur!=NULL; cur=clist_next(cur)) {
1079 struct mailmime* childmime = (
struct mailmime*)clist_content(cur);
1080 if( mrmimeparser_get_mime_type(childmime, NULL) == MR_MIMETYPE_TEXT_PLAIN ) {
1081 any_part_added = mrmimeparser_parse_mime_recursive(ths, childmime);
1087 if( !any_part_added ) {
1088 for( cur=clist_begin(mime->mm_data.mm_multipart.mm_mp_list); cur!=NULL; cur=clist_next(cur)) {
1089 if( mrmimeparser_parse_mime_recursive(ths, (
struct mailmime*)clist_content(cur)) ) {
1097 case MR_MIMETYPE_MP_RELATED:
1099 cur=clist_begin(mime->mm_data.mm_multipart.mm_mp_list);
1101 any_part_added = mrmimeparser_parse_mime_recursive(ths, (
struct mailmime*)clist_content(cur));
1105 case MR_MIMETYPE_MP_NOT_DECRYPTABLE:
1107 mrmimepart_t* part = mrmimepart_new();
1108 part->m_type = MR_MSG_TEXT;
1109 part->m_msg = mrstock_str(MR_STR_ENCRYPTEDMSG);
1110 carray_add(ths->m_parts, (
void*)part, NULL);
1112 ths->m_decrypting_failed = 1;
1116 case MR_MIMETYPE_MP_SIGNED:
1122 if( (cur=clist_begin(mime->mm_data.mm_multipart.mm_mp_list)) != NULL )
1124 any_part_added = mrmimeparser_parse_mime_recursive(ths, (
struct mailmime*)clist_content(cur));
1128 case MR_MIMETYPE_MP_REPORT:
1129 if( clist_count(mime->mm_data.mm_multipart.mm_mp_list) >= 2 )
1131 struct mailmime_parameter* report_type = mr_find_ct_parameter(mime,
"report-type");
1132 if( report_type && report_type->pa_value
1133 && strcmp(report_type->pa_value,
"disposition-notification") == 0 )
1135 carray_add(ths->m_reports, (
void*)mime, NULL);
1140 any_part_added = mrmimeparser_parse_mime_recursive(ths, (
struct mailmime*)clist_content(clist_begin(mime->mm_data.mm_multipart.mm_mp_list)));
1150 struct mailmime* skip_part = NULL;
1152 struct mailmime* html_part = NULL;
1153 int plain_cnt = 0, html_cnt = 0;
1154 for( cur=clist_begin(mime->mm_data.mm_multipart.mm_mp_list); cur!=NULL; cur=clist_next(cur)) {
1155 struct mailmime* childmime = (
struct mailmime*)clist_content(cur);
1156 if( mrmimeparser_get_mime_type(childmime, NULL) == MR_MIMETYPE_TEXT_PLAIN ) {
1159 else if( mrmimeparser_get_mime_type(childmime, NULL) == MR_MIMETYPE_TEXT_HTML ) {
1160 html_part = childmime;
1164 if( plain_cnt==1 && html_cnt==1 ) {
1165 mrmailbox_log_warning(ths->m_mailbox, 0,
"HACK: multipart/mixed message found with PLAIN and HTML, we'll skip the HTML part as this seems to be unwanted.");
1166 skip_part = html_part;
1171 for( cur=clist_begin(mime->mm_data.mm_multipart.mm_mp_list); cur!=NULL; cur=clist_next(cur)) {
1172 struct mailmime* childmime = (
struct mailmime*)clist_content(cur);
1173 if( childmime != skip_part ) {
1174 if( mrmimeparser_parse_mime_recursive(ths, childmime) ) {
1184 case MAILMIME_MESSAGE:
1185 if( ths->m_header == NULL && mime->mm_data.mm_message.mm_fields )
1187 ths->m_header = mime->mm_data.mm_message.mm_fields;
1188 for( cur = clist_begin(ths->m_header->fld_list); cur!=NULL ; cur=clist_next(cur) ) {
1189 struct mailimf_field* field = (
struct mailimf_field*)clist_content(cur);
1190 if( field->fld_type == MAILIMF_FIELD_SUBJECT ) {
1191 if( ths->m_subject == NULL && field->fld_data.fld_subject ) {
1192 ths->m_subject = mr_decode_header_string(field->fld_data.fld_subject->sbj_value);
1195 else if( field->fld_type == MAILIMF_FIELD_OPTIONAL_FIELD ) {
1196 struct mailimf_optional_field* optional_field = field->fld_data.fld_optional_field;
1197 if( optional_field ) {
1198 if( strcasecmp(optional_field->fld_name,
"X-MrMsg")==0 || strcasecmp(optional_field->fld_name,
"Chat-Version")==0 ) {
1199 ths->m_is_send_by_messenger = 1;
1206 if( mime->mm_data.mm_message.mm_msg_mime )
1208 any_part_added = mrmimeparser_parse_mime_recursive(ths, mime->mm_data.mm_message.mm_msg_mime);
1213 return any_part_added;
1217 static struct mailimf_optional_field* mrmimeparser_find_xtra_field(mrmimeparser_t* ths,
const char* wanted_fld_name)
1219 return mr_find_mailimf_field2(ths->m_header, wanted_fld_name);
1223 void mrmimeparser_parse(mrmimeparser_t* ths,
const char* body_not_terminated,
size_t body_bytes)
1228 mrmimeparser_empty(ths);
1231 r = mailmime_parse(body_not_terminated, body_bytes, &index, &ths->m_mimeroot);
1232 if(r != MAILIMF_NO_ERROR || ths->m_mimeroot == NULL ) {
1237 printf(
"-----------------------------------------------------------------------\n");
1238 mr_print_mime(m_mimeroot);
1239 printf(
"-----------------------------------------------------------------------\n");
1244 int validation_errors = 0;
1245 if( mrmailbox_e2ee_decrypt(ths->m_mailbox, ths->m_mimeroot, &validation_errors) ) {
1246 if( validation_errors == 0 ) {
1247 ths->m_decrypted_and_validated = 1;
1250 ths->m_decrypted_with_validation_errors = validation_errors;
1255 mrmimeparser_parse_mime_recursive(ths, ths->m_mimeroot);
1258 if( ths->m_subject )
1260 int prepend_subject = 1;
1261 if( !ths->m_decrypting_failed )
1263 char* p = strchr(ths->m_subject,
':');
1264 if( (p-ths->m_subject) == 2
1265 || (p-ths->m_subject) == 3
1266 || ths->m_is_send_by_messenger
1267 || strstr(ths->m_subject, MR_CHAT_PREFIX)!=NULL ) {
1268 prepend_subject = 0;
1272 if( prepend_subject )
1274 char* subj = safe_strdup(ths->m_subject);
1275 char* p = strchr(subj,
'[');
1281 int i, icnt = carray_count(ths->m_parts);
1282 for( i = 0; i < icnt; i++ ) {
1283 mrmimepart_t* part = (mrmimepart_t*)carray_get(ths->m_parts, i);
1284 if( part->m_type == MR_MSG_TEXT ) {
1285 #define MR_NDASH "\xE2\x80\x93" 1286 char* new_txt = mr_mprintf(
"%s " MR_NDASH
" %s", subj, part->m_msg);
1288 part->m_msg = new_txt;
1298 if( ths->m_is_forwarded ) {
1299 int i, icnt = carray_count(ths->m_parts);
1300 for( i = 0; i < icnt; i++ ) {
1301 mrmimepart_t* part = (mrmimepart_t*)carray_get(ths->m_parts, i);
1306 if( carray_count(ths->m_parts)==1 )
1310 mrmimepart_t* part = (mrmimepart_t*)carray_get(ths->m_parts, 0);
1311 if( part->m_type == MR_MSG_AUDIO ) {
1312 if( mrmimeparser_find_xtra_field(ths,
"X-MrVoiceMessage") || mrmimeparser_find_xtra_field(ths,
"Chat-Voice-Message") ) {
1314 part->m_msg = strdup(
"ogg");
1315 part->m_type = MR_MSG_VOICE;
1321 if( part->m_type == MR_MSG_AUDIO || part->m_type == MR_MSG_VOICE || part->m_type == MR_MSG_VIDEO ) {
1322 const struct mailimf_optional_field* field = mrmimeparser_find_xtra_field(ths,
"X-MrDurationMs");
1323 if( field==NULL ) { field = mrmimeparser_find_xtra_field(ths,
"Chat-Duration"); }
1325 int duration_ms = atoi(field->fld_value);
1326 if( duration_ms > 0 && duration_ms < 24*60*60*1000 ) {
1334 if( mrmimeparser_find_xtra_field(ths,
"Chat-Group-Image")
1335 && carray_count(ths->m_parts)>=1 ) {
1336 mrmimepart_t* textpart = (mrmimepart_t*)carray_get(ths->m_parts, 0);
1337 if( textpart->m_type == MR_MSG_TEXT ) {
1338 mrparam_set_int(textpart->m_param, MRP_SYSTEM_CMD, MR_SYSTEM_GROUPIMAGE_CHANGED);
1339 if( carray_count(ths->m_parts)>=2 ) {
1340 mrmimepart_t* imgpart = (mrmimepart_t*)carray_get(ths->m_parts, 1);
1341 if( imgpart->m_type == MR_MSG_IMAGE ) {
1342 imgpart->m_is_meta = 1;
1349 if( !ths->m_decrypting_failed )
1351 const struct mailimf_optional_field* dn_field = mrmimeparser_find_xtra_field(ths,
"Chat-Disposition-Notification-To");
1352 if( dn_field && mrmimeparser_get_last_nonmeta(ths) )
1354 struct mailimf_mailbox_list* mb_list = NULL;
1356 if( mailimf_mailbox_list_parse(dn_field->fld_value, strlen(dn_field->fld_value), &index, &mb_list)==MAILIMF_NO_ERROR && mb_list )
1358 char* dn_to_addr = mr_find_first_addr(mb_list);
1361 struct mailimf_field* from_field = mr_find_mailimf_field(ths->m_header, MAILIMF_FIELD_FROM);
1362 if( from_field && from_field->fld_data.fld_from )
1364 char* from_addr = mr_find_first_addr(from_field->fld_data.fld_from->frm_mb_list);
1367 if( strcmp(from_addr, dn_to_addr)==0 )
1372 mrmimepart_t* part = mrmimeparser_get_last_nonmeta(ths);
1382 mailimf_mailbox_list_free(mb_list);
1389 if( !mrmimeparser_has_nonmeta(ths) && carray_count(ths->m_reports)==0 ) {
1390 mrmimepart_t* part = mrmimepart_new();
1391 part->m_type = MR_MSG_TEXT;
1392 part->m_msg = safe_strdup(ths->m_subject? ths->m_subject :
"Empty message");
1393 carray_add(ths->m_parts, (
void*)part, NULL);
1398 mrmimepart_t* mrmimeparser_get_last_nonmeta(mrmimeparser_t* ths)
1400 if( ths && ths->m_parts ) {
1401 int i, icnt = carray_count(ths->m_parts);
1402 for( i = icnt-1; i >= 0; i-- ) {
1403 mrmimepart_t* part = (mrmimepart_t*)carray_get(ths->m_parts, i);
1404 if( part && !part->m_is_meta ) {
1413 int mrmimeparser_is_mailinglist_message(mrmimeparser_t* ths)
1438 if( mr_find_mailimf_field2(ths->m_header,
"List-Id") != NULL ) {
1442 struct mailimf_optional_field* precedence = mr_find_mailimf_field2(ths->m_header,
"Precedence");
1443 if( precedence != NULL ) {
1444 if( strcasecmp(precedence->fld_value,
"list")==0
1445 || strcasecmp(precedence->fld_value,
"bulk")==0 ) {
An object representing a single mailbox.
void mrparam_unref(mrparam_t *param)
Free an parameter list object created eg.
void mrparam_set(mrparam_t *param, int key, const char *value)
Set parameter to a string.
mrparam_t * mrparam_new()
Create new parameter list object.
void mrparam_set_int(mrparam_t *param, int key, int32_t value)
Set parameter to an integer.