1 // This file is under GNU General Public License 3.0
4 #include "etpan_mime.h"
5 #ifndef mailmime_param_new_with_data
6 #include <libetpan/mailprivacy_tools.h>
9 #include "pEp_internal.h"
13 #include "resource_id.h"
20 #define MAX_MESSAGE_ID 128
22 static char * generate_boundary(void)
24 char id[MAX_MESSAGE_ID];
26 // no cryptographically strong random needed here
27 const long value1 = random();
28 const long value2 = random();
29 const long value3 = random();
30 const long value4 = random();
32 snprintf(id, MAX_MESSAGE_ID, "%.4lx%.4lx%.4lx%.4lx", value1, value2,
38 struct mailmime * part_new_empty(
39 struct mailmime_content * content,
40 struct mailmime_fields * mime_fields,
41 stringpair_list_t* param_keyvals,
45 struct mailmime * build_info;
49 char * attr_name = NULL;
50 char * attr_value = NULL;
51 struct mailmime_parameter * param = NULL;
52 clist * parameters = NULL;
53 char *boundary = NULL;
58 mime_type = MAILMIME_SINGLE;
61 switch (content->ct_type->tp_type) {
62 case MAILMIME_TYPE_DISCRETE_TYPE:
63 mime_type = MAILMIME_SINGLE;
66 case MAILMIME_TYPE_COMPOSITE_TYPE:
67 switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
68 case MAILMIME_COMPOSITE_TYPE_MULTIPART:
69 mime_type = MAILMIME_MULTIPLE;
72 case MAILMIME_COMPOSITE_TYPE_MESSAGE:
73 if (strcasecmp(content->ct_subtype, "rfc822") == 0)
74 mime_type = MAILMIME_MESSAGE;
76 mime_type = MAILMIME_SINGLE;
89 if (mime_type == MAILMIME_MULTIPLE) {
95 attr_name = strdup("boundary");
97 if (attr_name == NULL)
100 boundary = generate_boundary();
102 attr_value = boundary;
103 if (attr_value == NULL)
106 param = mailmime_parameter_new(attr_name, attr_value);
113 if (content->ct_parameters == NULL) {
114 parameters = clist_new();
116 if (parameters == NULL)
120 parameters = content->ct_parameters;
123 r = clist_append(parameters, param);
128 if (content->ct_parameters == NULL)
129 content->ct_parameters = parameters;
133 stringpair_list_t* cur;
134 for (cur = param_keyvals; cur; cur = cur->next) {
135 attr_name = strdup(cur->value->key);
136 attr_value = strdup(cur->value->value);
138 param = mailmime_parameter_new(attr_name, attr_value);
146 if (content->ct_parameters == NULL) {
147 parameters = clist_new();
149 if (parameters == NULL)
153 parameters = content->ct_parameters;
156 r = clist_append(parameters, param);
161 if (content->ct_parameters == NULL)
162 content->ct_parameters = parameters;
166 build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
167 NULL, NULL, list, NULL, NULL);
168 if (build_info == NULL)
178 if (content->ct_parameters == NULL)
180 clist_free(parameters);
182 mailmime_parameter_free(param);
186 struct mailmime * get_pgp_encrypted_part(void)
188 struct mailmime * mime = NULL;
189 struct mailmime_fields * mime_fields = NULL;
190 struct mailmime_content * content = NULL;
193 content = mailmime_content_new_with_str("application/pgp-encrypted");
197 mime_fields = mailmime_fields_new_empty();
198 if (mime_fields == NULL)
201 mime = part_new_empty(content, mime_fields, NULL, 1);
207 r = mailmime_set_body_text(mime, "Version: 1\n", 10);
215 mailmime_content_free(content);
217 mailmime_fields_free(mime_fields);
224 struct mailmime * get_text_part(
225 pEp_rid_list_t* resource,
226 const char * mime_type,
232 char * disposition_name = NULL;
233 struct mailmime_fields * mime_fields = NULL;
234 struct mailmime * mime = NULL;
235 struct mailmime_content * content = NULL;
236 struct mailmime_parameter * param = NULL;
237 struct mailmime_disposition * disposition = NULL;
238 struct mailmime_mechanism * encoding = NULL;
239 char* content_id = NULL;
242 if (resource != NULL && resource->rid != NULL) {
243 switch (resource->rid_type) {
245 content_id = strdup(resource->rid);
247 case PEP_RID_FILENAME:
249 disposition_name = strdup(resource->rid);
250 if (disposition_name == NULL)
254 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
255 disposition_name, NULL, NULL, NULL, (size_t) -1);
257 if (disposition == NULL)
260 disposition_name = NULL;
266 encoding = mailmime_mechanism_new(encoding_type, NULL);
267 if (encoding == NULL)
271 mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
273 if (mime_fields == NULL)
279 content = mailmime_content_new_with_str(mime_type);
283 if (encoding_type != MAILMIME_MECHANISM_7BIT) {
284 param = mailmime_param_new_with_data("charset", "utf-8");
285 r = clist_append(content->ct_parameters, param);
290 mime = part_new_empty(content, mime_fields, NULL, 1);
297 r = mailmime_set_body_text(mime, (char *) text, length);
305 free(disposition_name);
307 mailmime_fields_free(mime_fields);
311 mailmime_content_free(content);
313 mailmime_parameter_free(param);
315 mailmime_disposition_free(disposition);
317 mailmime_mechanism_free(encoding);
322 struct mailmime * get_file_part(
323 pEp_rid_list_t* resource,
324 const char * mime_type,
327 bool transport_encode,
328 bool set_attachment_forward_comment
331 char * disposition_name = NULL;
333 struct mailmime_disposition * disposition = NULL;
334 struct mailmime_mechanism * encoding = NULL;
335 struct mailmime_content * content = NULL;
336 struct mailmime * mime = NULL;
337 struct mailmime_fields * mime_fields = NULL;
338 char* content_id = NULL;
341 if (resource != NULL && resource->rid != NULL) {
342 switch (resource->rid_type) {
344 content_id = strdup(resource->rid);
346 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
347 NULL, NULL, NULL, NULL, (size_t) -1);
348 if (disposition == NULL)
351 case PEP_RID_FILENAME:
353 disposition_name = strdup(resource->rid);
354 if (disposition_name == NULL)
358 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
359 disposition_name, NULL, NULL, NULL, (size_t) -1);
361 if (disposition == NULL)
363 disposition_name = NULL;
370 content = mailmime_content_new_with_str(mime_type);
376 if (transport_encode) {
377 encoding_type = MAILMIME_MECHANISM_BASE64;
378 encoding = mailmime_mechanism_new(encoding_type, NULL);
379 if (encoding == NULL)
383 mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
385 if (mime_fields == NULL)
390 stringpair_list_t* extra_params = NULL;
392 if (set_attachment_forward_comment)
393 extra_params = new_stringpair_list(new_stringpair("forwarded", "no"));
395 mime = part_new_empty(content, mime_fields, extra_params, 1);
396 free_stringpair_list(extra_params);
404 r = mailmime_set_body_text(mime, data, length);
412 free(disposition_name);
414 mailmime_disposition_free(disposition);
416 mailmime_mechanism_free(encoding);
418 mailmime_content_free(content);
420 mailmime_fields_free(mime_fields);
427 struct mailmime * part_multiple_new(const char *type)
429 struct mailmime_fields *mime_fields = NULL;
430 struct mailmime_content *content = NULL;
431 struct mailmime *mp = NULL;
433 mime_fields = mailmime_fields_new_empty();
434 if (mime_fields == NULL)
437 content = mailmime_content_new_with_str(type);
441 mp = part_new_empty(content, mime_fields, NULL, 0);
449 mailmime_content_free(content);
451 mailmime_fields_free(mime_fields);
456 struct mailimf_field * _new_field(
458 _new_func_t new_func,
462 void *data = new_func(value);
467 struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
469 if (result == NULL) {
474 result->fld_type = type;
475 result->fld_data.fld_return_path = data;
480 void _free_field(struct mailimf_field *field)
483 free(field->fld_data.fld_return_path);
490 _new_func_t new_func,
495 struct mailimf_field * field;
501 field = _new_field(type, new_func, value);
505 r = clist_append(list, field);
512 // http://media2.giga.de/2014/02/Image-28.jpg
514 struct mailimf_date_time * timestamp_to_etpantime(const timestamp *ts)
516 struct mailimf_date_time * result = calloc(1,
517 sizeof(struct mailimf_date_time));
524 result->dt_sec = ts->tm_sec;
525 result->dt_min = ts->tm_min;
526 result->dt_hour = ts->tm_hour;
527 result->dt_day = ts->tm_mday;
528 result->dt_month = ts->tm_mon + 1;
529 result->dt_year = ts->tm_year + 1900;
530 result->dt_zone = (int) (ts->tm_gmtoff / 36L);
534 timestamp * etpantime_to_timestamp(const struct mailimf_date_time *et)
536 timestamp * result = calloc(1, sizeof(timestamp));
543 result->tm_sec = et->dt_sec;
544 result->tm_min = et->dt_min;
545 result->tm_hour = et->dt_hour;
546 result->tm_mday = et->dt_day;
547 result->tm_mon = et->dt_month - 1;
548 result->tm_year = et->dt_year - 1900;
549 result->tm_gmtoff = 36L * (long) et->dt_zone;
553 struct mailimf_mailbox * mailbox_from_string(
558 struct mailimf_mailbox *mb = NULL;
560 char *_address = NULL;
564 _name = name ? strdup(name) : strdup("");
568 _address = strdup(address);
569 if (_address == NULL)
572 mb = mailimf_mailbox_new(_name, _address);
587 struct mailimf_field * create_optional_field(
594 struct mailimf_optional_field *optional_field = NULL;
596 _field = strdup(field);
600 if (!must_field_value_be_encoded(value))
601 _value = strdup(value);
603 _value = mailmime_encode_subject_header("utf-8", value, 0);
607 optional_field = mailimf_optional_field_new(_field, _value);
608 if (optional_field == NULL)
611 struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
616 result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
617 result->fld_data.fld_optional_field = optional_field;
622 if (optional_field) {
623 mailimf_optional_field_free(optional_field);
633 int _append_optional_field(
640 struct mailimf_field * optional_field =
641 create_optional_field(field, value);
643 if (optional_field == NULL)
646 r = clist_append(list, optional_field);
648 mailimf_field_free(optional_field);
653 clist * _get_fields(struct mailmime * mime)
655 clist * _fieldlist = NULL;
659 if (mime->mm_data.mm_message.mm_fields &&
660 mime->mm_data.mm_message.mm_fields->fld_list) {
661 _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
667 struct mailmime_content * _get_content(struct mailmime * mime)
669 struct mailmime_content * content = NULL;
673 if (mime->mm_data.mm_message.mm_msg_mime)
674 content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
680 /* Return a list of identifier_type and resource id (filename, cid, etc) */
681 pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
683 clist * _fieldlist = NULL;
687 if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
688 _fieldlist = mime->mm_mime_fields->fld_list;
694 pEp_rid_list_t* rid_list = NULL;
695 pEp_rid_list_t** rid_list_curr_p = &rid_list;
697 for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
698 struct mailmime_field * _field = clist_content(cur);
700 if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
701 pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
702 new_rid->rid_type = PEP_RID_CID;
703 new_rid->rid = strdup(_field->fld_data.fld_id);
704 *rid_list_curr_p = new_rid;
705 rid_list_curr_p = &new_rid->next;
707 else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
709 if (_field->fld_data.fld_disposition &&
710 _field->fld_data.fld_disposition->dsp_parms) {
712 _field->fld_data.fld_disposition->dsp_parms;
714 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
716 struct mailmime_disposition_parm * param =
718 if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
719 pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
720 new_rid->rid_type = PEP_RID_FILENAME;
721 new_rid->rid = strdup(param->pa_data.pa_filename);
722 *rid_list_curr_p = new_rid;
723 rid_list_curr_p = &new_rid->next;
729 /* Will almost certainly usually be a singleton, but we need to be able to decide */
734 /* FIXME: about to be obsoleted? */
735 char * _get_filename_or_cid(struct mailmime *mime)
737 clist * _fieldlist = NULL;
741 if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
742 _fieldlist = mime->mm_mime_fields->fld_list;
748 char* _temp_filename_ptr = NULL;
750 for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
751 struct mailmime_field * _field = clist_content(cur);
752 if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
753 /* We prefer CIDs to filenames when both are present */
754 free(_temp_filename_ptr); /* can be null, it's ok */
755 return build_uri("cid", _field->fld_data.fld_id);
757 else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
758 if (_field->fld_data.fld_disposition &&
759 _field->fld_data.fld_disposition->dsp_parms &&
760 !_temp_filename_ptr) {
762 _field->fld_data.fld_disposition->dsp_parms;
764 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
766 struct mailmime_disposition_parm * param =
768 if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
769 _temp_filename_ptr = build_uri("file", param->pa_data.pa_filename);
776 /* Ok, it wasn't a CID */
777 return _temp_filename_ptr;
780 static bool parameter_has_value(
781 struct mailmime_content *content,
791 clist * list = content->ct_parameters;
795 for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
796 struct mailmime_parameter * param = clist_content(cur);
798 param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
799 param->pa_value && strcasecmp(value, param->pa_value) == 0)
806 bool _is_multipart(struct mailmime_content *content, const char *subtype)
810 if (content->ct_type && content->ct_type->tp_type ==
811 MAILMIME_TYPE_COMPOSITE_TYPE &&
812 content->ct_type->tp_data.tp_composite_type &&
813 content->ct_type->tp_data.tp_composite_type->ct_type ==
814 MAILMIME_COMPOSITE_TYPE_MULTIPART) {
816 return content->ct_subtype &&
817 strcasecmp(content->ct_subtype, subtype) == 0;
825 bool _is_PGP_MIME(struct mailmime_content *content)
829 if (_is_multipart(content, "encrypted") &&
830 parameter_has_value(content, "protocol",
831 "application/pgp-encrypted"))
837 bool _is_text_part(struct mailmime_content *content, const char *subtype)
841 if (content->ct_type && content->ct_type->tp_type ==
842 MAILMIME_TYPE_DISCRETE_TYPE &&
843 content->ct_type->tp_data.tp_discrete_type &&
844 content->ct_type->tp_data.tp_discrete_type->dt_type ==
845 MAILMIME_DISCRETE_TYPE_TEXT) {
847 return content->ct_subtype &&
848 strcasecmp(content->ct_subtype, subtype) == 0;
856 bool _is_message_part(struct mailmime_content *content, const char* subtype) {
858 if (content->ct_type && content->ct_type->tp_type == MAILMIME_TYPE_COMPOSITE_TYPE &&
859 content->ct_type->tp_data.tp_composite_type &&
860 content->ct_type->tp_data.tp_composite_type->ct_type ==
861 MAILMIME_COMPOSITE_TYPE_MESSAGE) {
863 return content->ct_subtype &&
864 strcasecmp(content->ct_subtype, subtype) == 0;
872 int _get_content_type(
873 const struct mailmime_content *content,
879 char *_charset = NULL;
888 if (content->ct_subtype == NULL)
891 if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
893 const char *_main_type;
895 switch (content->ct_type->tp_data.tp_discrete_type->dt_type) {
896 case MAILMIME_DISCRETE_TYPE_TEXT:
897 _main_type = (content->ct_subtype &&
898 strcasecmp(content->ct_subtype, "rfc822") == 0 ?
901 case MAILMIME_DISCRETE_TYPE_IMAGE:
902 _main_type = "image";
904 case MAILMIME_DISCRETE_TYPE_AUDIO:
905 _main_type = "audio";
907 case MAILMIME_DISCRETE_TYPE_VIDEO:
908 _main_type = "video";
910 case MAILMIME_DISCRETE_TYPE_APPLICATION:
911 _main_type = "application";
913 case MAILMIME_DISCRETE_TYPE_EXTENSION:
914 _main_type = "extension";
920 len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
921 _type = calloc(1, len);
926 strncpy(_type, _main_type, len);
927 len -= strlen(_main_type);
928 strncat(_type, "/", len--);
929 strncat(_type, content->ct_subtype, len);
931 if (content->ct_parameters) {
933 for (cur = clist_begin(content->ct_parameters); cur; cur =
935 struct mailmime_parameter * param = clist_content(cur);
936 if (param && param->pa_name && strcasecmp(param->pa_name,
938 _charset = param->pa_value;
943 *charset = strdup(_charset);
953 // Only for null-terminated field strings.
954 // can this field be transported as is without modification?)
955 // (See rfc2822, section 2.2.3 - libetpan's handling isn't quite what
957 bool must_field_value_be_encoded(const char* field_value) {
961 return must_chunk_be_encoded((const void*)field_value, strlen(field_value), false);
964 bool must_chunk_be_encoded(const void* value, size_t size, bool ignore_fws) {
966 const char* begin_ptr = (const char*)value;
968 const char* end_ptr = begin_ptr + size;
970 const char* cur_char_ptr = begin_ptr;
971 while (cur_char_ptr < end_ptr) {
972 char cur_char = *cur_char_ptr;
973 if (cur_char > 127 || cur_char < 0)
975 // FIXME - do we need to deal with CRCRLF here?
976 // I guess in the worst case, it gets encoded, which
977 // is *supposed* to be harmless...
979 if (cur_char == '\r') {
980 const char* next = cur_char_ptr + 1;
981 const char* nextnext = next + 1;
982 if (next >= end_ptr || nextnext >= end_ptr
984 || (*nextnext != ' ' && *nextnext != '\t')) {
988 else if (cur_char == '\n') {
989 const char* prev = cur_char_ptr - 1;
990 if (prev == begin_ptr || *prev != '\r')
999 #define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
1001 #define PATH_SEP '\\'
1003 #define PATH_SEP '/'
1006 static PEP_STATUS interpret_MIME(struct mailmime *mime,
1008 bool* raise_msg_attachment);
1010 // This function was rewritten to use in-memory buffers instead of
1011 // temporary files when the pgp/mime support was implemented for
1012 // outlook, as the existing code did not work well on windows.
1014 static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
1016 PEP_STATUS status = PEP_STATUS_OK;
1024 buffer = mmap_string_new(NULL);
1029 r = mailmime_write_mem(buffer, &col, mime);
1030 assert(r == MAILIMF_NO_ERROR);
1031 if (r == MAILIMF_ERROR_MEMORY)
1033 else if (r != MAILIMF_NO_ERROR)
1036 // we overallocate by 1 byte, so we have a terminating 0.
1038 buf = calloc(len + 1, 1);
1042 memcpy(buf, buffer->str, len);
1043 mmap_string_free(buffer);
1046 return PEP_STATUS_OK;
1049 status = PEP_CANNOT_CREATE_TEMP_FILE;
1053 status = PEP_OUT_OF_MEMORY;
1057 mmap_string_free(buffer);
1063 static PEP_STATUS mime_attachment(
1065 struct mailmime **result,
1066 bool transport_encode,
1067 bool set_attachment_forward_comment
1070 PEP_STATUS status = PEP_STATUS_OK;
1071 struct mailmime * mime = NULL;
1078 // TODO: It seems the pEp COM server adapter sends an empty string here,
1079 // which leads to a crash later. Thus, we workaround here by treating an
1080 // empty string as NULL. We need to check whether the bug really is here,
1081 // or the pEp COM server adapter needs to be changed.
1082 if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
1083 mime_type = "application/octet-stream";
1085 mime_type = blob->mime_type;
1087 pEp_rid_list_t* resource = parse_uri(blob->filename);
1089 bool already_ascii = !(must_chunk_be_encoded(blob->value, blob->size, true));
1091 mime = get_file_part(resource, mime_type, blob->value, blob->size,
1092 (already_ascii ? false : transport_encode),
1093 set_attachment_forward_comment);
1094 free_rid_list(resource);
1101 return PEP_STATUS_OK;
1104 status = PEP_OUT_OF_MEMORY;
1107 mailmime_free(mime);
1112 static PEP_STATUS mime_html_text(
1113 const char *plaintext,
1114 const char *htmltext,
1115 bloblist_t *attachments,
1116 struct mailmime **result,
1117 bool transport_encode
1120 PEP_STATUS status = PEP_STATUS_OK;
1121 struct mailmime * top_level_html_mime = NULL;
1122 struct mailmime * mime = NULL;
1123 struct mailmime * submime = NULL;
1132 mime = part_multiple_new("multipart/alternative");
1137 pEp_rid_list_t* resource = NULL;
1139 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
1140 submime = get_text_part(NULL, "text/plain", plaintext, strlen(plaintext),
1142 free_rid_list(resource);
1146 if (submime == NULL)
1149 r = mailmime_smart_add_part(mime, submime);
1150 assert(r == MAILIMF_NO_ERROR);
1151 if (r == MAILIMF_ERROR_MEMORY) {
1155 // mailmime_smart_add_part() takes ownership of submime
1159 bool inlined_attachments = false;
1161 bloblist_t* traversal_ptr = attachments;
1163 while (traversal_ptr) {
1164 if (traversal_ptr->disposition == PEP_CONTENT_DISP_INLINE) {
1165 inlined_attachments = true;
1168 traversal_ptr = traversal_ptr->next;
1171 if (inlined_attachments) {
1172 /* Noooooo... dirk, why do you do this to me? */
1173 submime = part_multiple_new("multipart/related");
1175 if (submime == NULL)
1178 top_level_html_mime = submime;
1180 r = mailmime_smart_add_part(mime, top_level_html_mime);
1181 assert(r == MAILIMF_NO_ERROR);
1182 if (r == MAILIMF_ERROR_MEMORY) {
1186 // mailmime_smart_add_part() takes ownership of submime
1191 top_level_html_mime = mime;
1194 // resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
1195 submime = get_text_part(NULL, "text/html", htmltext, strlen(htmltext),
1197 free_rid_list(resource);
1201 if (submime == NULL)
1204 r = mailmime_smart_add_part(top_level_html_mime, submime);
1205 assert(r == MAILIMF_NO_ERROR);
1206 if (r == MAILIMF_ERROR_MEMORY)
1209 // mailmime_smart_add_part() takes ownership of submime
1214 for (_a = attachments; _a != NULL; _a = _a->next) {
1215 if (_a->disposition != PEP_CONTENT_DISP_INLINE)
1217 status = mime_attachment(_a, &submime, transport_encode, false);
1218 if (status != PEP_STATUS_OK)
1219 return PEP_UNKNOWN_ERROR; // FIXME
1221 r = mailmime_smart_add_part(top_level_html_mime, submime);
1222 assert(r == MAILIMF_NO_ERROR);
1223 if (r == MAILIMF_ERROR_MEMORY) {
1227 // mailmime_smart_add_part() takes ownership of submime
1233 return PEP_STATUS_OK;
1236 status = PEP_OUT_OF_MEMORY;
1239 mailmime_free(mime);
1242 mailmime_free(submime);
1248 // FIXME: maybe need to add transport_encode field here
1249 static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
1251 char *_username = NULL;
1252 struct mailimf_mailbox *mb;
1254 if (!ident->username)
1255 _username = strdup("");
1257 _username = must_field_value_be_encoded(ident->username) ?
1258 mailmime_encode_subject_header("utf-8", ident->username, 0) :
1259 strdup(ident->username);
1262 if (_username == NULL)
1265 mb = mailbox_from_string(_username, ident->address);
1279 static struct mailimf_mailbox_list * identity_to_mbl(
1280 const pEp_identity *ident)
1282 struct mailimf_mailbox_list *mbl = NULL;
1283 struct mailimf_mailbox *mb = NULL;
1293 mb = identity_to_mailbox(ident);
1297 r = clist_append(list, mb);
1301 mbl = mailimf_mailbox_list_new(list);
1309 mailimf_mailbox_free(mb);
1317 static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
1319 struct mailimf_address_list *mal = NULL;
1320 struct mailimf_mailbox *mb = NULL;
1321 struct mailimf_address * addr = NULL;
1332 for (_il = il; _il && _il->ident; _il = _il->next) {
1333 mb = identity_to_mailbox(_il->ident);
1337 addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
1342 r = clist_append(list, addr);
1347 mal = mailimf_address_list_new(list);
1355 mailimf_mailbox_free(mb);
1358 mailimf_address_free(addr);
1366 static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
1368 clist * cl = clist_new();
1373 if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
1377 for (_sl = sl; _sl; _sl = _sl->next) {
1379 char * value = ((transport_encode && must_field_value_be_encoded(_sl->value)) ?
1380 mailmime_encode_subject_header("utf-8", _sl->value, 0) :
1381 strdup(_sl->value));
1383 if (value == NULL) {
1387 r = clist_append(cl, value);
1399 static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
1401 PEP_STATUS status = PEP_STATUS_OK;
1402 struct mailimf_fields * fields = NULL;
1404 clist * fields_list = NULL;
1405 unsigned char pEpstr[] = PEP_SUBJ_STRING; // unsigned due to UTF-8 byte fun
1407 char* altstr = "pEp";
1409 char* altstr = (char*)pEpstr;
1411 char *subject = msg->shortmsg && msg->shortmsg[0] ? msg->shortmsg : altstr;
1418 fields_list = clist_new();
1419 assert(fields_list);
1420 if (fields_list == NULL)
1423 if (msg->id && msg->id[0]) {
1424 char *_msgid = strdup(msg->id);
1429 r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
1430 (_new_func_t) mailimf_message_id_new, _msgid);
1438 struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
1442 r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
1443 (_new_func_t) mailimf_orig_date_new, dt);
1445 mailimf_date_time_free(dt);
1452 struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
1456 r = _append_field(fields_list, MAILIMF_FIELD_FROM,
1457 (_new_func_t) mailimf_from_new, from);
1459 mailimf_mailbox_list_free(from);
1464 if (msg->to && msg->to->ident) {
1465 struct mailimf_address_list *to = identity_list_to_mal(msg->to);
1469 r = _append_field(fields_list, MAILIMF_FIELD_TO,
1470 (_new_func_t) mailimf_to_new, to);
1472 mailimf_address_list_free(to);
1477 char* _subject = NULL;
1478 if (!must_field_value_be_encoded(subject)) {
1479 _subject = strdup(subject);
1483 _subject = mailmime_encode_subject_header("utf-8", subject, 1);
1485 if (_subject == NULL)
1488 r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
1489 (_new_func_t) mailimf_subject_new, _subject);
1495 if (msg->cc && msg->cc->ident) {
1496 struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
1500 r = _append_field(fields_list, MAILIMF_FIELD_CC,
1501 (_new_func_t) mailimf_cc_new, cc);
1503 mailimf_address_list_free(cc);
1508 if (msg->bcc && msg->bcc->ident) {
1509 struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
1513 r = _append_field(fields_list, MAILIMF_FIELD_BCC,
1514 (_new_func_t) mailimf_bcc_new, bcc);
1516 mailimf_address_list_free(bcc);
1521 if (msg->reply_to && msg->reply_to->ident) {
1522 struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
1523 if (reply_to == NULL)
1526 r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
1527 (_new_func_t) mailimf_reply_to_new, reply_to);
1529 mailimf_address_list_free(reply_to);
1534 if (msg->in_reply_to && msg->in_reply_to->value) {
1535 clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
1536 if (in_reply_to == NULL)
1539 r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
1540 (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
1542 clist_free(in_reply_to);
1547 if (msg->references && msg->references->value) {
1548 clist *references = stringlist_to_clist(msg->references, true);
1549 if (references == NULL)
1552 r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
1553 (_new_func_t) mailimf_references_new, references);
1555 clist_free(references);
1560 if (msg->keywords && msg->keywords->value) {
1561 clist *keywords = stringlist_to_clist(msg->keywords, true);
1562 if (keywords == NULL)
1565 r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
1566 (_new_func_t) mailimf_keywords_new, keywords);
1568 clist_free(keywords);
1573 if (msg->comments && msg->comments[0]) {
1574 char *comments = NULL;
1575 if (!must_field_value_be_encoded(msg->comments)) {
1576 comments = strdup(msg->comments);
1580 comments = mailmime_encode_subject_header("utf-8", msg->comments, 0);
1582 if (comments == NULL)
1585 r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
1586 (_new_func_t) mailimf_comments_new, comments);
1593 if (msg->opt_fields && msg->opt_fields->value) {
1594 stringpair_list_t *_l;
1595 for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
1596 char *key = _l->value->key;
1597 char *value = _l->value->value;
1599 r = _append_optional_field(fields_list, key, value);
1607 fields = mailimf_fields_new(fields_list);
1614 return PEP_STATUS_OK;
1617 status = PEP_OUT_OF_MEMORY;
1620 clist_free(fields_list);
1623 mailimf_fields_free(fields);
1628 static bool has_exceptional_extension(char* filename) {
1631 int len = strlen(filename);
1634 char* ext_start = filename + (len - 4);
1635 if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
1636 strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
1641 static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
1642 pEp_rid_list_t* retval = rid_list;
1644 /* multiple elements - least common case */
1645 if (rid_list && rid_list->next) {
1646 pEp_rid_list_t* rid_list_curr = rid_list;
1649 while (rid_list_curr) {
1650 pEp_resource_id_type rid_type = rid_list_curr->rid_type;
1651 if (rid_type == PEP_RID_CID)
1652 retval = rid_list_curr;
1653 else if (rid_type == PEP_RID_FILENAME && has_exceptional_extension(rid_list_curr->rid))
1654 return rid_list_curr;
1655 rid_list_curr = rid_list_curr->next;
1661 // static void split_inlined_and_attached(bloblist_t** inlined, bloblist_t** attached) {
1662 // bloblist_t** curr_pp = attached;
1663 // bloblist_t* curr = *curr_pp;
1665 // bloblist_t* inline_ret = NULL;
1666 // bloblist_t** inline_curr_pp = &inline_ret;
1668 // bloblist_t* att_ret = NULL;
1669 // bloblist_t** att_curr_pp = &att_ret;
1672 // if (curr->disposition == PEP_CONTENT_DISP_INLINE) {
1673 // *inline_curr_pp = curr;
1674 // inline_curr_pp = &(curr->next);
1677 // *att_curr_pp = curr;
1678 // att_curr_pp = &(curr->next);
1680 // *curr_pp = curr->next;
1681 // curr->next = NULL;
1685 // *inlined = inline_ret;
1686 // *attached = att_ret;
1690 static PEP_STATUS mime_encode_message_plain(
1693 struct mailmime **result,
1694 bool transport_encode,
1695 bool set_attachment_forward_comment
1698 struct mailmime * mime = NULL;
1699 struct mailmime * submime = NULL;
1709 //subject = (msg->shortmsg) ? msg->shortmsg : "pEp"; // not used, yet.
1710 plaintext = (msg->longmsg) ? msg->longmsg : "";
1711 htmltext = msg->longmsg_formatted;
1713 if (htmltext && (htmltext[0] != '\0')) {
1714 /* first, we need to strip out the inlined attachments to ensure this
1715 gets set up correctly */
1717 status = mime_html_text(plaintext, htmltext, msg->attachments, &mime,
1720 if (status != PEP_STATUS_OK)
1724 pEp_rid_list_t* resource = NULL;
1725 if (is_PGP_message_text(plaintext)) {
1727 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
1728 mime = get_text_part(resource, "application/octet-stream", plaintext,
1729 strlen(plaintext), encoding_type);
1733 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
1734 mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
1737 free_rid_list(resource);
1744 bool normal_attachments = false;
1746 bloblist_t* traversal_ptr = msg->attachments;
1748 while (traversal_ptr) {
1749 if (traversal_ptr->disposition != PEP_CONTENT_DISP_INLINE) {
1750 normal_attachments = true;
1753 traversal_ptr = traversal_ptr->next;
1756 if (normal_attachments) {
1758 mime = part_multiple_new("multipart/mixed");
1763 r = mailmime_smart_add_part(mime, submime);
1764 assert(r == MAILIMF_NO_ERROR);
1765 if (r == MAILIMF_ERROR_MEMORY) {
1769 // mailmime_smart_add_part() takes ownership of submime
1774 bool first_one = true;
1776 for (_a = msg->attachments; _a != NULL; _a = _a->next) {
1778 if (_a->disposition == PEP_CONTENT_DISP_INLINE)
1781 status = mime_attachment(_a, &submime, transport_encode,
1782 (first_one && set_attachment_forward_comment));
1783 if (status != PEP_STATUS_OK)
1788 r = mailmime_smart_add_part(mime, submime);
1789 assert(r == MAILIMF_NO_ERROR);
1790 if (r == MAILIMF_ERROR_MEMORY) {
1794 // mailmime_smart_add_part() takes ownership of submime
1801 return PEP_STATUS_OK;
1804 status = PEP_OUT_OF_MEMORY;
1808 mailmime_free(mime);
1811 mailmime_free(submime);
1816 static PEP_STATUS mime_encode_message_PGP_MIME(
1817 const message * msg,
1819 struct mailmime **result
1822 struct mailmime * mime = NULL;
1823 struct mailmime * submime = NULL;
1824 struct mailmime_parameter * param;
1828 size_t plaintext_size;
1830 assert(msg->attachments && msg->attachments->next &&
1831 msg->attachments->next->value);
1833 plaintext = msg->attachments->next->value;
1834 plaintext_size = msg->attachments->next->size;
1836 mime = part_multiple_new("multipart/encrypted");
1841 param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
1842 clist_append(mime->mm_content_type->ct_parameters, param);
1844 submime = get_pgp_encrypted_part();
1846 if (submime == NULL)
1849 r = mailmime_smart_add_part(mime, submime);
1850 assert(r == MAILIMF_NO_ERROR);
1851 if (r == MAILIMF_ERROR_MEMORY) {
1855 // mailmime_smart_add_part() takes ownership of submime
1859 pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
1860 submime = get_text_part(resource, "application/octet-stream", plaintext,
1861 plaintext_size, MAILMIME_MECHANISM_7BIT);
1863 free_rid_list(resource);
1866 if (submime == NULL)
1869 r = mailmime_smart_add_part(mime, submime);
1870 assert(r == MAILIMF_NO_ERROR);
1871 if (r == MAILIMF_ERROR_MEMORY) {
1875 // mailmime_smart_add_part() takes ownership of submime
1880 return PEP_STATUS_OK;
1883 status = PEP_OUT_OF_MEMORY;
1886 mailmime_free(mime);
1889 mailmime_free(submime);
1894 PEP_STATUS _mime_encode_message_internal(
1895 const message * msg,
1898 bool transport_encode,
1899 bool set_attachment_forward_comment
1902 PEP_STATUS status = PEP_STATUS_OK;
1903 struct mailmime * msg_mime = NULL;
1904 struct mailmime * mime = NULL;
1905 struct mailimf_fields * fields = NULL;
1912 if (!(msg && mimetext))
1913 return PEP_ILLEGAL_VALUE;
1917 switch (msg->enc_format) {
1919 status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode, set_attachment_forward_comment);
1922 // I'm presuming we should hardcore ignoring set_attachment_forward_comment here...
1923 case PEP_enc_inline:
1924 status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode, false);
1927 case PEP_enc_S_MIME:
1930 case PEP_enc_PGP_MIME:
1931 status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
1935 // today's pEp message format is PGP/MIME from the outside
1936 status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
1943 if (status != PEP_STATUS_OK)
1946 msg_mime = mailmime_new_message_data(NULL);
1948 if (msg_mime == NULL)
1951 r = mailmime_add_part(msg_mime, mime);
1953 mailmime_free(mime);
1959 status = build_fields(msg, &fields);
1960 if (status != PEP_STATUS_OK)
1963 mailmime_set_imf_fields(msg_mime, fields);
1966 status = render_mime(msg_mime, &buf);
1967 if (status != PEP_STATUS_OK)
1970 mailmime_free(msg_mime);
1973 return PEP_STATUS_OK;
1976 status = PEP_OUT_OF_MEMORY;
1980 mailmime_free(msg_mime);
1983 mailmime_free(mime);
1988 static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
1990 char *username = NULL;
1993 assert(mb->mb_addr_spec);
1995 if (mb->mb_addr_spec == NULL)
1998 if (mb->mb_display_name) {
2000 const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
2001 strlen(mb->mb_display_name), &index, "utf-8", &username);
2006 pEp_identity *ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
2018 static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
2020 struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
2021 return mailbox_to_identity(mb);
2024 static identity_list * mal_to_identity_list(
2025 const struct mailimf_address_list *mal
2028 identity_list *il = new_identity_list(NULL);
2032 // if we have nothing to translate then return an empty list
2036 clist *list = mal->ad_list;
2038 identity_list *_il = il;
2039 for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
2040 pEp_identity *ident;
2042 struct mailimf_address *addr = clist_content(cur);
2043 switch(addr->ad_type) {
2044 case MAILIMF_ADDRESS_MAILBOX:
2045 ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
2048 _il = identity_list_add(_il, ident);
2053 case MAILIMF_ADDRESS_GROUP:
2055 struct mailimf_mailbox_list * mbl =
2056 addr->ad_data.ad_group->grp_mb_list;
2057 for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
2058 cur2 = clist_next(cur2)) {
2059 ident = mailbox_to_identity(clist_content(cur));
2062 _il = identity_list_add(_il, ident);
2078 free_identity_list(il);
2082 static stringlist_t * clist_to_stringlist(const clist *list)
2085 stringlist_t * sl = new_stringlist(NULL);
2089 stringlist_t *_sl = sl;
2090 for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
2091 char *phrase = clist_content(cur);
2094 const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
2095 &index, "utf-8", &text);
2099 _sl = stringlist_add(_sl, text);
2110 free_stringlist(sl);
2116 static PEP_STATUS read_fields(message *msg, clist *fieldlist)
2118 PEP_STATUS status = PEP_STATUS_OK;
2119 struct mailimf_field * _field;
2124 stringpair_list_t *opt = msg->opt_fields;
2127 return PEP_STATUS_OK;
2129 for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
2130 _field = clist_content(cur);
2132 switch (_field->fld_type) {
2133 case MAILIMF_FIELD_MESSAGE_ID:
2135 char * text = _field->fld_data.fld_message_id->mid_value;
2139 r = mailmime_encoded_phrase_parse("utf-8", text,
2140 strlen(text), &index, "utf-8", &msg->id);
2146 case MAILIMF_FIELD_SUBJECT:
2148 char * text = _field->fld_data.fld_subject->sbj_value;
2150 free(msg->shortmsg);
2152 r = mailmime_encoded_phrase_parse("utf-8", text,
2153 strlen(text), &index, "utf-8", &msg->shortmsg);
2159 case MAILIMF_FIELD_ORIG_DATE:
2161 struct mailimf_date_time *date =
2162 _field->fld_data.fld_orig_date->dt_date_time;
2164 free_timestamp(msg->sent);
2165 msg->sent = etpantime_to_timestamp(date);
2166 if (msg->sent == NULL)
2171 case MAILIMF_FIELD_FROM:
2173 struct mailimf_mailbox_list *mbl =
2174 _field->fld_data.fld_from->frm_mb_list;
2175 pEp_identity *ident;
2177 ident = mbl_to_identity(mbl);
2181 free_identity(msg->from);
2186 case MAILIMF_FIELD_TO:
2188 struct mailimf_address_list *mal =
2189 _field->fld_data.fld_to->to_addr_list;
2190 identity_list *il = mal_to_identity_list(mal);
2194 free_identity_list(msg->to);
2199 case MAILIMF_FIELD_CC:
2201 struct mailimf_address_list *mal =
2202 _field->fld_data.fld_cc->cc_addr_list;
2203 identity_list *il = mal_to_identity_list(mal);
2207 free_identity_list(msg->cc);
2212 case MAILIMF_FIELD_BCC:
2214 struct mailimf_address_list *mal =
2215 _field->fld_data.fld_bcc->bcc_addr_list;
2216 identity_list *il = mal_to_identity_list(mal);
2220 free_identity_list(msg->bcc);
2225 case MAILIMF_FIELD_REPLY_TO:
2227 struct mailimf_address_list *mal =
2228 _field->fld_data.fld_reply_to->rt_addr_list;
2229 identity_list *il = mal_to_identity_list(mal);
2233 free_identity_list(msg->reply_to);
2238 case MAILIMF_FIELD_IN_REPLY_TO:
2240 clist *list = _field->fld_data.fld_in_reply_to->mid_list;
2241 stringlist_t *sl = clist_to_stringlist(list);
2245 free_stringlist(msg->in_reply_to);
2246 msg->in_reply_to = sl;
2250 case MAILIMF_FIELD_REFERENCES:
2252 clist *list = _field->fld_data.fld_references->mid_list;
2253 stringlist_t *sl = clist_to_stringlist(list);
2257 free_stringlist(msg->references);
2258 msg->references = sl;
2262 case MAILIMF_FIELD_KEYWORDS:
2264 clist *list = _field->fld_data.fld_keywords->kw_list;
2265 stringlist_t *sl = clist_to_stringlist(list);
2269 free_stringlist(msg->keywords);
2274 case MAILIMF_FIELD_COMMENTS:
2276 char * text = _field->fld_data.fld_comments->cm_value;
2278 free(msg->comments);
2280 r = mailmime_encoded_phrase_parse("utf-8", text,
2281 strlen(text), &index, "utf-8", &msg->comments);
2287 case MAILIMF_FIELD_OPTIONAL_FIELD:
2290 _field->fld_data.fld_optional_field->fld_name;
2292 _field->fld_data.fld_optional_field->fld_value;
2296 r = mailmime_encoded_phrase_parse("utf-8", value,
2297 strlen(value), &index, "utf-8", &_value);
2301 stringpair_t *pair = new_stringpair(name, _value);
2305 opt = stringpair_list_add(opt, pair);
2310 if (msg->opt_fields == NULL)
2311 msg->opt_fields = opt;
2317 return PEP_STATUS_OK;
2320 status = PEP_OUT_OF_MEMORY;
2326 static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
2334 char *charset = NULL;
2343 if (part->mm_body == NULL)
2344 return PEP_ILLEGAL_VALUE;
2346 text = part->mm_body-> dt_data.dt_text.dt_data;
2348 return PEP_ILLEGAL_VALUE;
2350 length = part->mm_body->dt_data.dt_text.dt_length;
2352 if (part->mm_body->dt_encoded) {
2353 int code = part->mm_body->dt_encoding;
2355 int r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
2357 case MAILIMF_NO_ERROR:
2359 case MAILIMF_ERROR_MEMORY:
2360 return PEP_OUT_OF_MEMORY;
2362 return PEP_ILLEGAL_VALUE;
2367 _longmsg = strndup(text, length);
2368 if (_longmsg == NULL)
2369 return PEP_OUT_OF_MEMORY;
2372 if (part->mm_content_type) {
2373 if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
2374 if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
2376 int r = charconv("utf-8", charset, _longmsg, _size, &_text);
2378 case MAILIMF_NO_ERROR:
2380 case MAILIMF_ERROR_MEMORY:
2381 return PEP_OUT_OF_MEMORY;
2383 return PEP_ILLEGAL_VALUE;
2390 // FIXME: KG - we now have the text we want.
2391 // Now we need to strip sigs and process them if they are there..
2394 *longmsg = _longmsg;
2398 return PEP_STATUS_OK;
2401 // THIS IS A BEST-EFFORT ONLY FUNCTION, AND WE ARE NOT DOING MORE THAN THE
2403 static PEP_STATUS interpret_protected_headers(
2404 struct mailmime* mime,
2408 // N.B. this is *very much* enigmail output specific, and right now,
2409 // we only care about subject replacement.
2410 const char* header_string = "Content-Type: text/rfc822-headers; protected-headers=\"v1\"\nContent-Disposition: inline\n\n";
2411 size_t content_length = mime->mm_length;
2412 size_t header_strlen = strlen(header_string);
2413 if (header_strlen < content_length) {
2414 const char* headerblock = mime->mm_mime_start;
2415 size_t subject_len = 0;
2416 headerblock = strstr(headerblock, header_string);
2418 const char* subj_start = "Subject: ";
2419 headerblock = strstr(headerblock, subj_start);
2421 size_t subj_len = strlen(subj_start);
2422 headerblock += subj_len;
2423 char* end_pt = strstr(headerblock, "\n");
2425 if (end_pt != mime->mm_mime_start && *(end_pt - 1) == '\r')
2427 subject_len = end_pt - headerblock;
2428 char* new_subj = (char*)calloc(subject_len + 1, 1);
2430 strlcpy(new_subj, headerblock, subject_len + 1);
2431 free(msg->shortmsg);
2432 msg->shortmsg = new_subj;
2434 } // if there's no endpoint, there's something wrong here so we ignore all
2435 // This is best effort.
2439 return PEP_STATUS_OK;
2442 // ONLY for main part!!!
2443 static PEP_STATUS process_multipart_related(struct mailmime *mime,
2445 PEP_STATUS status = PEP_STATUS_OK;
2450 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2452 if (partlist == NULL)
2453 return PEP_ILLEGAL_VALUE;
2455 clistiter *cur = clist_begin(partlist);
2456 struct mailmime *part = clist_content(cur);
2459 return PEP_ILLEGAL_VALUE;
2461 struct mailmime_content *content = part->mm_content_type;
2464 if (content == NULL)
2465 return PEP_ILLEGAL_VALUE;
2467 if (_is_text_part(content, "html")) {
2468 status = interpret_body(part, &msg->longmsg_formatted,
2475 // This is what we would have done before, so... no
2476 // worse than the status quo. But FIXME!
2477 status = interpret_MIME(part, msg, NULL);
2482 for (cur = clist_next(cur); cur; cur = clist_next(cur)) {
2483 part = clist_content(cur);
2485 return PEP_ILLEGAL_VALUE;
2487 content = part->mm_content_type;
2489 if (content == NULL)
2490 return PEP_ILLEGAL_VALUE;
2492 status = interpret_MIME(part, msg, NULL);
2499 static PEP_STATUS interpret_MIME(
2500 struct mailmime *mime,
2502 bool* raise_msg_attachment
2505 PEP_STATUS status = PEP_STATUS_OK;
2510 struct mailmime_content *content = mime->mm_content_type;
2512 if (_is_multipart(content, "alternative")) {
2513 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2514 if (partlist == NULL)
2515 return PEP_ILLEGAL_VALUE;
2518 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
2519 struct mailmime *part = clist_content(cur);
2521 return PEP_ILLEGAL_VALUE;
2523 content = part->mm_content_type;
2525 if (content == NULL)
2526 return PEP_ILLEGAL_VALUE;
2528 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
2529 status = interpret_body(part, &msg->longmsg, NULL);
2533 else if (_is_text_part(content, "rfc822-headers")) {
2534 status = interpret_protected_headers(part, msg);
2538 else if (_is_text_part(content, "html") &&
2539 msg->longmsg_formatted == NULL) {
2540 status = interpret_body(part, &msg->longmsg_formatted,
2545 else if (_is_multipart(content, "related") &&
2546 msg->longmsg_formatted == NULL) {
2547 status = process_multipart_related(part, msg);
2551 else /* add as attachment */ {
2552 status = interpret_MIME(part, msg, NULL);
2558 else if (_is_multipart(content, "encrypted")) {
2559 if (msg->longmsg == NULL)
2560 msg->longmsg = strdup("");
2561 assert(msg->longmsg);
2563 return PEP_OUT_OF_MEMORY;
2565 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2566 if (partlist == NULL)
2567 return PEP_ILLEGAL_VALUE;
2570 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
2571 struct mailmime *part= clist_content(cur);
2573 return PEP_ILLEGAL_VALUE;
2575 status = interpret_MIME(part, msg, NULL);
2576 if (status != PEP_STATUS_OK)
2580 else if (_is_multipart(content, NULL)) {
2581 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2582 if (partlist == NULL)
2583 return PEP_ILLEGAL_VALUE;
2586 // only add raise_msg_attachment on 2nd part!
2588 for (cur = clist_begin(partlist); cur; cur = clist_next(cur), _att_count++) {
2589 struct mailmime *part= clist_content(cur);
2591 return PEP_ILLEGAL_VALUE;
2592 status = interpret_MIME(part, msg, _att_count == 1 ? raise_msg_attachment : NULL);
2593 if (status != PEP_STATUS_OK)
2598 if (_is_text_part(content, "html") &&
2599 msg->longmsg_formatted == NULL &&
2600 msg->longmsg == NULL) {
2601 status = interpret_body(mime, &msg->longmsg_formatted,
2606 else if (_is_text_part(content, "rfc822-headers")) {
2607 status = interpret_protected_headers(mime, msg);
2611 else if (_is_text_part(content, "plain") &&
2612 msg->longmsg == NULL && msg->longmsg_formatted == NULL) {
2613 status = interpret_body(mime, &msg->longmsg, NULL);
2617 else if (_is_text_part(content, NULL) &&
2618 !_is_text_part(content, "plain") &&
2619 msg->longmsg == NULL) {
2620 status = interpret_body(mime, &msg->longmsg, NULL);
2625 // Fixme - we need a control on recursion level here - KG: maybe NOT. We only go to depth 1.
2626 if (raise_msg_attachment != NULL) {
2627 bool is_msg = (_is_message_part(content, "rfc822") || _is_text_part(content, "rfc822"));
2629 if (content->ct_parameters) {
2631 for (cur = clist_begin(content->ct_parameters); cur; cur =
2633 struct mailmime_parameter * param = clist_content(cur);
2634 if (param && param->pa_name && strcasecmp(param->pa_name, "forwarded") == 0) {
2635 if (param->pa_value && strcasecmp(param->pa_value, "no") == 0) {
2636 *raise_msg_attachment = true;
2651 r = _get_content_type(content, &mime_type, &charset);
2656 return PEP_ILLEGAL_VALUE;
2658 return PEP_OUT_OF_MEMORY;
2660 return PEP_UNKNOWN_ERROR;
2665 status = interpret_body(mime, &data, &size);
2669 pEp_rid_list_t* resource_id_list = _get_resource_id_list(mime);
2670 pEp_rid_list_t* chosen_resource_id = choose_resource_id(resource_id_list);
2672 //filename = _get_filename_or_cid(mime);
2673 char *_filename = NULL;
2675 if (chosen_resource_id) {
2676 filename = chosen_resource_id->rid;
2679 /* The prefix we just added shouldn't be a problem - this is about decoding %XX (RFC 2392) */
2680 /* If it becomes one, we have some MESSY fixing to do. :( */
2681 r = mailmime_encoded_phrase_parse("utf-8", filename,
2682 strlen(filename), &index, "utf-8", &_filename);
2686 char* file_prefix = NULL;
2688 /* in case there are others later */
2689 switch (chosen_resource_id->rid_type) {
2691 file_prefix = "cid";
2693 case PEP_RID_FILENAME:
2694 file_prefix = "file";
2702 filename = build_uri(file_prefix, _filename);
2704 _filename = filename;
2708 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
2709 mime_type, _filename);
2711 free_rid_list(resource_id_list);
2712 resource_id_list = NULL;
2714 return PEP_OUT_OF_MEMORY;
2715 if (msg->attachments == NULL)
2716 msg->attachments = _a;
2721 return PEP_STATUS_OK;
2724 return PEP_OUT_OF_MEMORY;
2727 DYNAMIC_API PEP_STATUS mime_decode_message(
2728 const char *mimetext,
2733 return _mime_decode_message_internal(mimetext, size, msg, NULL);
2737 PEP_STATUS _mime_decode_message_internal(
2738 const char *mimetext,
2741 bool* raise_msg_attachment
2744 PEP_STATUS status = PEP_STATUS_OK;
2745 struct mailmime * mime = NULL;
2747 message *_msg = NULL;
2753 if (!(mimetext && msg))
2754 return PEP_ILLEGAL_VALUE;
2759 r = mailmime_parse(mimetext, size, &index, &mime);
2763 if (r == MAILIMF_ERROR_MEMORY)
2769 _msg = calloc(1, sizeof(message));
2774 clist * _fieldlist = _get_fields(mime);
2776 status = read_fields(_msg, _fieldlist);
2777 if (status != PEP_STATUS_OK)
2781 struct mailmime_content *content = _get_content(mime);
2784 status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
2785 _msg, raise_msg_attachment);
2786 if (status != PEP_STATUS_OK)
2790 mailmime_free(mime);
2796 status = PEP_ILLEGAL_VALUE;
2800 status = PEP_OUT_OF_MEMORY;
2806 mailmime_free(mime);