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 struct tm *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;
531 result->dt_zone = (int) (ts->tm_gmtoff / 36L);
536 struct tm * etpantime_to_timestamp(const struct mailimf_date_time *et)
538 struct tm * result = calloc(1, sizeof(struct tm));
545 result->tm_sec = et->dt_sec;
546 result->tm_min = et->dt_min;
547 result->tm_hour = et->dt_hour;
548 result->tm_mday = et->dt_day;
549 result->tm_mon = et->dt_month - 1;
550 result->tm_year = et->dt_year - 1900;
552 result->tm_gmtoff = 36L * (long) et->dt_zone;
557 struct mailimf_mailbox * mailbox_from_string(
562 struct mailimf_mailbox *mb = NULL;
564 char *_address = NULL;
568 _name = name ? strdup(name) : strdup("");
572 _address = strdup(address);
573 if (_address == NULL)
576 mb = mailimf_mailbox_new(_name, _address);
591 struct mailimf_field * create_optional_field(
598 struct mailimf_optional_field *optional_field = NULL;
600 _field = strdup(field);
604 if (!must_field_value_be_encoded(value))
605 _value = strdup(value);
607 _value = mailmime_encode_subject_header("utf-8", value, 0);
611 optional_field = mailimf_optional_field_new(_field, _value);
612 if (optional_field == NULL)
615 struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
620 result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
621 result->fld_data.fld_optional_field = optional_field;
626 if (optional_field) {
627 mailimf_optional_field_free(optional_field);
637 int _append_optional_field(
644 struct mailimf_field * optional_field =
645 create_optional_field(field, value);
647 if (optional_field == NULL)
650 r = clist_append(list, optional_field);
652 mailimf_field_free(optional_field);
657 clist * _get_fields(struct mailmime * mime)
659 clist * _fieldlist = NULL;
663 if (mime->mm_data.mm_message.mm_fields &&
664 mime->mm_data.mm_message.mm_fields->fld_list) {
665 _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
671 struct mailmime_content * _get_content(struct mailmime * mime)
673 struct mailmime_content * content = NULL;
677 if (mime->mm_data.mm_message.mm_msg_mime)
678 content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
684 /* Return a list of identifier_type and resource id (filename, cid, etc) */
685 pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
687 clist * _fieldlist = NULL;
691 if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
692 _fieldlist = mime->mm_mime_fields->fld_list;
698 pEp_rid_list_t* rid_list = NULL;
699 pEp_rid_list_t** rid_list_curr_p = &rid_list;
701 for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
702 struct mailmime_field * _field = clist_content(cur);
704 if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
705 pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
706 new_rid->rid_type = PEP_RID_CID;
707 new_rid->rid = strdup(_field->fld_data.fld_id);
708 *rid_list_curr_p = new_rid;
709 rid_list_curr_p = &new_rid->next;
711 else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
713 if (_field->fld_data.fld_disposition &&
714 _field->fld_data.fld_disposition->dsp_parms) {
716 _field->fld_data.fld_disposition->dsp_parms;
718 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
720 struct mailmime_disposition_parm * param =
722 if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
723 pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
724 new_rid->rid_type = PEP_RID_FILENAME;
725 new_rid->rid = strdup(param->pa_data.pa_filename);
726 *rid_list_curr_p = new_rid;
727 rid_list_curr_p = &new_rid->next;
733 /* Will almost certainly usually be a singleton, but we need to be able to decide */
738 /* FIXME: about to be obsoleted? */
739 char * _get_filename_or_cid(struct mailmime *mime)
741 clist * _fieldlist = NULL;
745 if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
746 _fieldlist = mime->mm_mime_fields->fld_list;
752 char* _temp_filename_ptr = NULL;
754 for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
755 struct mailmime_field * _field = clist_content(cur);
756 if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
757 /* We prefer CIDs to filenames when both are present */
758 free(_temp_filename_ptr); /* can be null, it's ok */
759 return build_uri("cid", _field->fld_data.fld_id);
761 else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
762 if (_field->fld_data.fld_disposition &&
763 _field->fld_data.fld_disposition->dsp_parms &&
764 !_temp_filename_ptr) {
766 _field->fld_data.fld_disposition->dsp_parms;
768 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
770 struct mailmime_disposition_parm * param =
772 if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
773 _temp_filename_ptr = build_uri("file", param->pa_data.pa_filename);
780 /* Ok, it wasn't a CID */
781 return _temp_filename_ptr;
784 static bool parameter_has_value(
785 struct mailmime_content *content,
795 clist * list = content->ct_parameters;
799 for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
800 struct mailmime_parameter * param = clist_content(cur);
802 param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
803 param->pa_value && strcasecmp(value, param->pa_value) == 0)
810 bool _is_multipart(struct mailmime_content *content, const char *subtype)
814 if (content->ct_type && content->ct_type->tp_type ==
815 MAILMIME_TYPE_COMPOSITE_TYPE &&
816 content->ct_type->tp_data.tp_composite_type &&
817 content->ct_type->tp_data.tp_composite_type->ct_type ==
818 MAILMIME_COMPOSITE_TYPE_MULTIPART) {
820 return content->ct_subtype &&
821 strcasecmp(content->ct_subtype, subtype) == 0;
829 bool _is_PGP_MIME(struct mailmime_content *content)
833 if (_is_multipart(content, "encrypted") &&
834 parameter_has_value(content, "protocol",
835 "application/pgp-encrypted"))
841 bool _is_text_part(struct mailmime_content *content, const char *subtype)
845 if (content->ct_type && content->ct_type->tp_type ==
846 MAILMIME_TYPE_DISCRETE_TYPE &&
847 content->ct_type->tp_data.tp_discrete_type &&
848 content->ct_type->tp_data.tp_discrete_type->dt_type ==
849 MAILMIME_DISCRETE_TYPE_TEXT) {
851 return content->ct_subtype &&
852 strcasecmp(content->ct_subtype, subtype) == 0;
860 bool _is_message_part(struct mailmime_content *content, const char* subtype) {
862 if (content->ct_type && content->ct_type->tp_type == MAILMIME_TYPE_COMPOSITE_TYPE &&
863 content->ct_type->tp_data.tp_composite_type &&
864 content->ct_type->tp_data.tp_composite_type->ct_type ==
865 MAILMIME_COMPOSITE_TYPE_MESSAGE) {
867 return content->ct_subtype &&
868 strcasecmp(content->ct_subtype, subtype) == 0;
876 int _get_content_type(
877 const struct mailmime_content *content,
883 char *_charset = NULL;
892 if (content->ct_subtype == NULL)
895 if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
897 const char *_main_type;
899 switch (content->ct_type->tp_data.tp_discrete_type->dt_type) {
900 case MAILMIME_DISCRETE_TYPE_TEXT:
903 case MAILMIME_DISCRETE_TYPE_IMAGE:
904 _main_type = "image";
906 case MAILMIME_DISCRETE_TYPE_AUDIO:
907 _main_type = "audio";
909 case MAILMIME_DISCRETE_TYPE_VIDEO:
910 _main_type = "video";
912 case MAILMIME_DISCRETE_TYPE_APPLICATION:
913 _main_type = "application";
915 case MAILMIME_DISCRETE_TYPE_EXTENSION:
916 _main_type = "extension";
922 len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
923 _type = calloc(1, len);
928 strncpy(_type, _main_type, len);
929 len -= strlen(_main_type);
930 strncat(_type, "/", len--);
931 strncat(_type, content->ct_subtype, len);
933 if (content->ct_parameters) {
935 for (cur = clist_begin(content->ct_parameters); cur; cur =
937 struct mailmime_parameter * param = clist_content(cur);
938 if (param && param->pa_name && strcasecmp(param->pa_name,
940 _charset = param->pa_value;
945 *charset = strdup(_charset);
955 // Only for null-terminated field strings.
956 // can this field be transported as is without modification?)
957 // (See rfc2822, section 2.2.3 - libetpan's handling isn't quite what
959 bool must_field_value_be_encoded(const char* field_value) {
963 return must_chunk_be_encoded((const void*)field_value, strlen(field_value), false);
966 bool must_chunk_be_encoded(const void* value, size_t size, bool ignore_fws) {
968 const char* begin_ptr = (const char*)value;
970 const char* end_ptr = begin_ptr + size;
972 const char* cur_char_ptr = begin_ptr;
973 while (cur_char_ptr < end_ptr) {
974 char cur_char = *cur_char_ptr;
975 if (cur_char > 127 || cur_char < 0)
977 // FIXME - do we need to deal with CRCRLF here?
978 // I guess in the worst case, it gets encoded, which
979 // is *supposed* to be harmless...
981 if (cur_char == '\r') {
982 const char* next = cur_char_ptr + 1;
983 const char* nextnext = next + 1;
984 if (next >= end_ptr || nextnext >= end_ptr
986 || (*nextnext != ' ' && *nextnext != '\t')) {
990 else if (cur_char == '\n') {
991 const char* prev = cur_char_ptr - 1;
992 if (prev == begin_ptr || *prev != '\r')
1001 #define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
1003 #define PATH_SEP '\\'
1005 #define PATH_SEP '/'
1008 static PEP_STATUS interpret_MIME(struct mailmime *mime,
1010 bool* raise_msg_attachment);
1012 // This function was rewritten to use in-memory buffers instead of
1013 // temporary files when the pgp/mime support was implemented for
1014 // outlook, as the existing code did not work well on windows.
1016 static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
1018 PEP_STATUS status = PEP_STATUS_OK;
1026 buffer = mmap_string_new(NULL);
1031 r = mailmime_write_mem(buffer, &col, mime);
1032 assert(r == MAILIMF_NO_ERROR);
1033 if (r == MAILIMF_ERROR_MEMORY)
1035 else if (r != MAILIMF_NO_ERROR)
1038 // we overallocate by 1 byte, so we have a terminating 0.
1040 buf = calloc(len + 1, 1);
1044 memcpy(buf, buffer->str, len);
1045 mmap_string_free(buffer);
1048 return PEP_STATUS_OK;
1051 status = PEP_CANNOT_CREATE_TEMP_FILE;
1055 status = PEP_OUT_OF_MEMORY;
1059 mmap_string_free(buffer);
1065 static PEP_STATUS mime_attachment(
1067 struct mailmime **result,
1068 bool transport_encode,
1069 bool set_attachment_forward_comment
1072 PEP_STATUS status = PEP_STATUS_OK;
1073 struct mailmime * mime = NULL;
1080 // TODO: It seems the pEp COM server adapter sends an empty string here,
1081 // which leads to a crash later. Thus, we workaround here by treating an
1082 // empty string as NULL. We need to check whether the bug really is here,
1083 // or the pEp COM server adapter needs to be changed.
1084 if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
1085 mime_type = "application/octet-stream";
1087 mime_type = blob->mime_type;
1089 pEp_rid_list_t* resource = parse_uri(blob->filename);
1091 bool already_ascii = !(must_chunk_be_encoded(blob->value, blob->size, true));
1093 mime = get_file_part(resource, mime_type, blob->value, blob->size,
1094 (already_ascii ? false : transport_encode),
1095 set_attachment_forward_comment);
1096 free_rid_list(resource);
1103 return PEP_STATUS_OK;
1106 status = PEP_OUT_OF_MEMORY;
1109 mailmime_free(mime);
1114 static PEP_STATUS mime_html_text(
1115 const char *plaintext,
1116 const char *htmltext,
1117 bloblist_t *attachments,
1118 struct mailmime **result,
1119 bool transport_encode
1122 PEP_STATUS status = PEP_STATUS_OK;
1123 struct mailmime * top_level_html_mime = NULL;
1124 struct mailmime * mime = NULL;
1125 struct mailmime * submime = NULL;
1134 mime = part_multiple_new("multipart/alternative");
1139 pEp_rid_list_t* resource = NULL;
1141 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
1142 submime = get_text_part(NULL, "text/plain", plaintext, strlen(plaintext),
1144 free_rid_list(resource);
1148 if (submime == NULL)
1151 r = mailmime_smart_add_part(mime, submime);
1152 assert(r == MAILIMF_NO_ERROR);
1153 if (r == MAILIMF_ERROR_MEMORY) {
1157 // mailmime_smart_add_part() takes ownership of submime
1161 bool inlined_attachments = false;
1163 bloblist_t* traversal_ptr = attachments;
1165 while (traversal_ptr) {
1166 if (traversal_ptr->disposition == PEP_CONTENT_DISP_INLINE) {
1167 inlined_attachments = true;
1170 traversal_ptr = traversal_ptr->next;
1173 if (inlined_attachments) {
1174 /* Noooooo... dirk, why do you do this to me? */
1175 submime = part_multiple_new("multipart/related");
1177 if (submime == NULL)
1180 top_level_html_mime = submime;
1182 r = mailmime_smart_add_part(mime, top_level_html_mime);
1183 assert(r == MAILIMF_NO_ERROR);
1184 if (r == MAILIMF_ERROR_MEMORY) {
1188 // mailmime_smart_add_part() takes ownership of submime
1193 top_level_html_mime = mime;
1196 // resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
1197 submime = get_text_part(NULL, "text/html", htmltext, strlen(htmltext),
1199 free_rid_list(resource);
1203 if (submime == NULL)
1206 r = mailmime_smart_add_part(top_level_html_mime, submime);
1207 assert(r == MAILIMF_NO_ERROR);
1208 if (r == MAILIMF_ERROR_MEMORY)
1211 // mailmime_smart_add_part() takes ownership of submime
1216 for (_a = attachments; _a != NULL; _a = _a->next) {
1217 if (_a->disposition != PEP_CONTENT_DISP_INLINE)
1219 status = mime_attachment(_a, &submime, transport_encode, false);
1220 if (status != PEP_STATUS_OK)
1221 return PEP_UNKNOWN_ERROR; // FIXME
1223 r = mailmime_smart_add_part(top_level_html_mime, submime);
1224 assert(r == MAILIMF_NO_ERROR);
1225 if (r == MAILIMF_ERROR_MEMORY) {
1229 // mailmime_smart_add_part() takes ownership of submime
1235 return PEP_STATUS_OK;
1238 status = PEP_OUT_OF_MEMORY;
1241 mailmime_free(mime);
1244 mailmime_free(submime);
1250 // FIXME: maybe need to add transport_encode field here
1251 static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
1253 char *_username = NULL;
1254 struct mailimf_mailbox *mb;
1256 if (!ident->username)
1257 _username = strdup("");
1259 _username = must_field_value_be_encoded(ident->username) ?
1260 mailmime_encode_subject_header("utf-8", ident->username, 0) :
1261 strdup(ident->username);
1264 if (_username == NULL)
1267 mb = mailbox_from_string(_username, ident->address);
1281 static struct mailimf_mailbox_list * identity_to_mbl(
1282 const pEp_identity *ident)
1284 struct mailimf_mailbox_list *mbl = NULL;
1285 struct mailimf_mailbox *mb = NULL;
1295 mb = identity_to_mailbox(ident);
1299 r = clist_append(list, mb);
1303 mbl = mailimf_mailbox_list_new(list);
1311 mailimf_mailbox_free(mb);
1319 static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
1321 struct mailimf_address_list *mal = NULL;
1322 struct mailimf_mailbox *mb = NULL;
1323 struct mailimf_address * addr = NULL;
1334 for (_il = il; _il && _il->ident; _il = _il->next) {
1335 mb = identity_to_mailbox(_il->ident);
1339 addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
1344 r = clist_append(list, addr);
1349 mal = mailimf_address_list_new(list);
1357 mailimf_mailbox_free(mb);
1360 mailimf_address_free(addr);
1368 static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
1370 clist * cl = clist_new();
1375 if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
1379 for (_sl = sl; _sl; _sl = _sl->next) {
1381 char * value = ((transport_encode && must_field_value_be_encoded(_sl->value)) ?
1382 mailmime_encode_subject_header("utf-8", _sl->value, 0) :
1383 strdup(_sl->value));
1385 if (value == NULL) {
1389 r = clist_append(cl, value);
1401 static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
1403 PEP_STATUS status = PEP_STATUS_OK;
1404 struct mailimf_fields * fields = NULL;
1406 clist * fields_list = NULL;
1407 unsigned char pEpstr[] = PEP_SUBJ_STRING; // unsigned due to UTF-8 byte fun
1409 char* altstr = "pEp";
1411 char* altstr = (char*)pEpstr;
1413 char *subject = msg->shortmsg && msg->shortmsg[0] ? msg->shortmsg : altstr;
1420 fields_list = clist_new();
1421 assert(fields_list);
1422 if (fields_list == NULL)
1425 if (msg->id && msg->id[0]) {
1426 char *_msgid = strdup(msg->id);
1431 r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
1432 (_new_func_t) mailimf_message_id_new, _msgid);
1440 struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
1444 r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
1445 (_new_func_t) mailimf_orig_date_new, dt);
1447 mailimf_date_time_free(dt);
1454 struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
1458 r = _append_field(fields_list, MAILIMF_FIELD_FROM,
1459 (_new_func_t) mailimf_from_new, from);
1461 mailimf_mailbox_list_free(from);
1466 if (msg->to && msg->to->ident) {
1467 struct mailimf_address_list *to = identity_list_to_mal(msg->to);
1471 r = _append_field(fields_list, MAILIMF_FIELD_TO,
1472 (_new_func_t) mailimf_to_new, to);
1474 mailimf_address_list_free(to);
1479 char* _subject = NULL;
1480 if (!must_field_value_be_encoded(subject)) {
1481 _subject = strdup(subject);
1485 _subject = mailmime_encode_subject_header("utf-8", subject, 1);
1487 if (_subject == NULL)
1490 r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
1491 (_new_func_t) mailimf_subject_new, _subject);
1497 if (msg->cc && msg->cc->ident) {
1498 struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
1502 r = _append_field(fields_list, MAILIMF_FIELD_CC,
1503 (_new_func_t) mailimf_cc_new, cc);
1505 mailimf_address_list_free(cc);
1510 if (msg->bcc && msg->bcc->ident) {
1511 struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
1515 r = _append_field(fields_list, MAILIMF_FIELD_BCC,
1516 (_new_func_t) mailimf_bcc_new, bcc);
1518 mailimf_address_list_free(bcc);
1523 if (msg->reply_to && msg->reply_to->ident) {
1524 struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
1525 if (reply_to == NULL)
1528 r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
1529 (_new_func_t) mailimf_reply_to_new, reply_to);
1531 mailimf_address_list_free(reply_to);
1536 if (msg->in_reply_to && msg->in_reply_to->value) {
1537 clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
1538 if (in_reply_to == NULL)
1541 r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
1542 (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
1544 clist_free(in_reply_to);
1549 if (msg->references && msg->references->value) {
1550 clist *references = stringlist_to_clist(msg->references, true);
1551 if (references == NULL)
1554 r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
1555 (_new_func_t) mailimf_references_new, references);
1557 clist_free(references);
1562 if (msg->keywords && msg->keywords->value) {
1563 clist *keywords = stringlist_to_clist(msg->keywords, true);
1564 if (keywords == NULL)
1567 r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
1568 (_new_func_t) mailimf_keywords_new, keywords);
1570 clist_free(keywords);
1575 if (msg->comments && msg->comments[0]) {
1576 char *comments = NULL;
1577 if (!must_field_value_be_encoded(msg->comments)) {
1578 comments = strdup(msg->comments);
1582 comments = mailmime_encode_subject_header("utf-8", msg->comments, 0);
1584 if (comments == NULL)
1587 r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
1588 (_new_func_t) mailimf_comments_new, comments);
1595 if (msg->opt_fields && msg->opt_fields->value) {
1596 stringpair_list_t *_l;
1597 for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
1598 char *key = _l->value->key;
1599 char *value = _l->value->value;
1601 r = _append_optional_field(fields_list, key, value);
1609 fields = mailimf_fields_new(fields_list);
1616 return PEP_STATUS_OK;
1619 status = PEP_OUT_OF_MEMORY;
1622 clist_free(fields_list);
1625 mailimf_fields_free(fields);
1630 static bool has_exceptional_extension(char* filename) {
1633 int len = strlen(filename);
1636 char* ext_start = filename + (len - 4);
1637 if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
1638 strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
1643 static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
1644 pEp_rid_list_t* retval = rid_list;
1646 /* multiple elements - least common case */
1647 if (rid_list && rid_list->next) {
1648 pEp_rid_list_t* rid_list_curr = rid_list;
1651 while (rid_list_curr) {
1652 pEp_resource_id_type rid_type = rid_list_curr->rid_type;
1653 if (rid_type == PEP_RID_CID)
1654 retval = rid_list_curr;
1655 else if (rid_type == PEP_RID_FILENAME && has_exceptional_extension(rid_list_curr->rid))
1656 return rid_list_curr;
1657 rid_list_curr = rid_list_curr->next;
1663 // static void split_inlined_and_attached(bloblist_t** inlined, bloblist_t** attached) {
1664 // bloblist_t** curr_pp = attached;
1665 // bloblist_t* curr = *curr_pp;
1667 // bloblist_t* inline_ret = NULL;
1668 // bloblist_t** inline_curr_pp = &inline_ret;
1670 // bloblist_t* att_ret = NULL;
1671 // bloblist_t** att_curr_pp = &att_ret;
1674 // if (curr->disposition == PEP_CONTENT_DISP_INLINE) {
1675 // *inline_curr_pp = curr;
1676 // inline_curr_pp = &(curr->next);
1679 // *att_curr_pp = curr;
1680 // att_curr_pp = &(curr->next);
1682 // *curr_pp = curr->next;
1683 // curr->next = NULL;
1687 // *inlined = inline_ret;
1688 // *attached = att_ret;
1692 static PEP_STATUS mime_encode_message_plain(
1695 struct mailmime **result,
1696 bool transport_encode,
1697 bool set_attachment_forward_comment
1700 struct mailmime * mime = NULL;
1701 struct mailmime * submime = NULL;
1711 //subject = (msg->shortmsg) ? msg->shortmsg : "pEp"; // not used, yet.
1712 plaintext = (msg->longmsg) ? msg->longmsg : "";
1713 htmltext = msg->longmsg_formatted;
1715 if (htmltext && (htmltext[0] != '\0')) {
1716 /* first, we need to strip out the inlined attachments to ensure this
1717 gets set up correctly */
1719 status = mime_html_text(plaintext, htmltext, msg->attachments, &mime,
1722 if (status != PEP_STATUS_OK)
1726 pEp_rid_list_t* resource = NULL;
1727 if (is_PGP_message_text(plaintext)) {
1729 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
1730 mime = get_text_part(resource, "application/octet-stream", plaintext,
1731 strlen(plaintext), encoding_type);
1735 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
1736 mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
1739 free_rid_list(resource);
1746 bool normal_attachments = false;
1748 bloblist_t* traversal_ptr = msg->attachments;
1750 while (traversal_ptr) {
1751 if (traversal_ptr->disposition != PEP_CONTENT_DISP_INLINE) {
1752 normal_attachments = true;
1755 traversal_ptr = traversal_ptr->next;
1758 if (normal_attachments) {
1760 mime = part_multiple_new("multipart/mixed");
1765 r = mailmime_smart_add_part(mime, submime);
1766 assert(r == MAILIMF_NO_ERROR);
1767 if (r == MAILIMF_ERROR_MEMORY) {
1771 // mailmime_smart_add_part() takes ownership of submime
1776 bool first_one = true;
1778 for (_a = msg->attachments; _a != NULL; _a = _a->next) {
1780 if (_a->disposition == PEP_CONTENT_DISP_INLINE)
1783 status = mime_attachment(_a, &submime, transport_encode,
1784 (first_one && set_attachment_forward_comment));
1785 if (status != PEP_STATUS_OK)
1790 r = mailmime_smart_add_part(mime, submime);
1791 assert(r == MAILIMF_NO_ERROR);
1792 if (r == MAILIMF_ERROR_MEMORY) {
1796 // mailmime_smart_add_part() takes ownership of submime
1803 return PEP_STATUS_OK;
1806 status = PEP_OUT_OF_MEMORY;
1810 mailmime_free(mime);
1813 mailmime_free(submime);
1818 static PEP_STATUS mime_encode_message_PGP_MIME(
1819 const message * msg,
1821 struct mailmime **result
1824 struct mailmime * mime = NULL;
1825 struct mailmime * submime = NULL;
1826 struct mailmime_parameter * param;
1830 size_t plaintext_size;
1832 assert(msg->attachments && msg->attachments->next &&
1833 msg->attachments->next->value);
1835 plaintext = msg->attachments->next->value;
1836 plaintext_size = msg->attachments->next->size;
1838 mime = part_multiple_new("multipart/encrypted");
1843 param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
1844 clist_append(mime->mm_content_type->ct_parameters, param);
1846 submime = get_pgp_encrypted_part();
1848 if (submime == NULL)
1851 r = mailmime_smart_add_part(mime, submime);
1852 assert(r == MAILIMF_NO_ERROR);
1853 if (r == MAILIMF_ERROR_MEMORY) {
1857 // mailmime_smart_add_part() takes ownership of submime
1861 pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
1862 submime = get_text_part(resource, "application/octet-stream", plaintext,
1863 plaintext_size, MAILMIME_MECHANISM_7BIT);
1865 free_rid_list(resource);
1868 if (submime == NULL)
1871 r = mailmime_smart_add_part(mime, submime);
1872 assert(r == MAILIMF_NO_ERROR);
1873 if (r == MAILIMF_ERROR_MEMORY) {
1877 // mailmime_smart_add_part() takes ownership of submime
1882 return PEP_STATUS_OK;
1885 status = PEP_OUT_OF_MEMORY;
1888 mailmime_free(mime);
1891 mailmime_free(submime);
1896 PEP_STATUS _mime_encode_message_internal(
1897 const message * msg,
1900 bool transport_encode,
1901 bool set_attachment_forward_comment
1904 PEP_STATUS status = PEP_STATUS_OK;
1905 struct mailmime * msg_mime = NULL;
1906 struct mailmime * mime = NULL;
1907 struct mailimf_fields * fields = NULL;
1914 if (!(msg && mimetext))
1915 return PEP_ILLEGAL_VALUE;
1919 switch (msg->enc_format) {
1921 status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode, set_attachment_forward_comment);
1924 // I'm presuming we should hardcore ignoring set_attachment_forward_comment here...
1925 case PEP_enc_inline:
1926 status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode, false);
1929 case PEP_enc_S_MIME:
1932 case PEP_enc_PGP_MIME:
1933 status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
1937 // today's pEp message format is PGP/MIME from the outside
1938 status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
1945 if (status != PEP_STATUS_OK)
1948 msg_mime = mailmime_new_message_data(NULL);
1950 if (msg_mime == NULL)
1953 r = mailmime_add_part(msg_mime, mime);
1955 mailmime_free(mime);
1961 status = build_fields(msg, &fields);
1962 if (status != PEP_STATUS_OK)
1965 mailmime_set_imf_fields(msg_mime, fields);
1968 status = render_mime(msg_mime, &buf);
1969 if (status != PEP_STATUS_OK)
1972 mailmime_free(msg_mime);
1975 return PEP_STATUS_OK;
1978 status = PEP_OUT_OF_MEMORY;
1982 mailmime_free(msg_mime);
1985 mailmime_free(mime);
1990 static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
1992 char *username = NULL;
1995 assert(mb->mb_addr_spec);
1997 if (mb->mb_addr_spec == NULL)
2000 if (mb->mb_display_name) {
2002 const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
2003 strlen(mb->mb_display_name), &index, "utf-8", &username);
2008 pEp_identity *ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
2020 static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
2022 struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
2023 return mailbox_to_identity(mb);
2026 static identity_list * mal_to_identity_list(
2027 const struct mailimf_address_list *mal
2031 clist *list = mal->ad_list;
2033 identity_list *il = new_identity_list(NULL);
2037 identity_list *_il = il;
2038 for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
2039 pEp_identity *ident;
2041 struct mailimf_address *addr = clist_content(cur);
2042 switch(addr->ad_type) {
2043 case MAILIMF_ADDRESS_MAILBOX:
2044 ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
2047 _il = identity_list_add(_il, ident);
2052 case MAILIMF_ADDRESS_GROUP:
2054 struct mailimf_mailbox_list * mbl =
2055 addr->ad_data.ad_group->grp_mb_list;
2056 for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
2057 cur2 = clist_next(cur2)) {
2058 ident = mailbox_to_identity(clist_content(cur));
2061 _il = identity_list_add(_il, ident);
2077 free_identity_list(il);
2081 static stringlist_t * clist_to_stringlist(const clist *list)
2084 stringlist_t * sl = new_stringlist(NULL);
2088 stringlist_t *_sl = sl;
2089 for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
2090 char *phrase = clist_content(cur);
2093 const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
2094 &index, "utf-8", &text);
2098 _sl = stringlist_add(_sl, text);
2109 free_stringlist(sl);
2115 static PEP_STATUS read_fields(message *msg, clist *fieldlist)
2117 PEP_STATUS status = PEP_STATUS_OK;
2118 struct mailimf_field * _field;
2123 stringpair_list_t *opt = msg->opt_fields;
2126 return PEP_STATUS_OK;
2128 for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
2129 _field = clist_content(cur);
2131 switch (_field->fld_type) {
2132 case MAILIMF_FIELD_MESSAGE_ID:
2134 char * text = _field->fld_data.fld_message_id->mid_value;
2138 r = mailmime_encoded_phrase_parse("utf-8", text,
2139 strlen(text), &index, "utf-8", &msg->id);
2145 case MAILIMF_FIELD_SUBJECT:
2147 char * text = _field->fld_data.fld_subject->sbj_value;
2149 free(msg->shortmsg);
2151 r = mailmime_encoded_phrase_parse("utf-8", text,
2152 strlen(text), &index, "utf-8", &msg->shortmsg);
2158 case MAILIMF_FIELD_ORIG_DATE:
2160 struct mailimf_date_time *date =
2161 _field->fld_data.fld_orig_date->dt_date_time;
2163 free_timestamp(msg->sent);
2164 msg->sent = etpantime_to_timestamp(date);
2165 if (msg->sent == NULL)
2170 case MAILIMF_FIELD_FROM:
2172 struct mailimf_mailbox_list *mbl =
2173 _field->fld_data.fld_from->frm_mb_list;
2174 pEp_identity *ident;
2176 ident = mbl_to_identity(mbl);
2180 free_identity(msg->from);
2185 case MAILIMF_FIELD_TO:
2187 struct mailimf_address_list *mal =
2188 _field->fld_data.fld_to->to_addr_list;
2189 identity_list *il = mal_to_identity_list(mal);
2193 free_identity_list(msg->to);
2198 case MAILIMF_FIELD_CC:
2200 struct mailimf_address_list *mal =
2201 _field->fld_data.fld_cc->cc_addr_list;
2202 identity_list *il = mal_to_identity_list(mal);
2206 free_identity_list(msg->cc);
2211 case MAILIMF_FIELD_BCC:
2213 struct mailimf_address_list *mal =
2214 _field->fld_data.fld_bcc->bcc_addr_list;
2215 identity_list *il = mal_to_identity_list(mal);
2219 free_identity_list(msg->bcc);
2224 case MAILIMF_FIELD_REPLY_TO:
2226 struct mailimf_address_list *mal =
2227 _field->fld_data.fld_reply_to->rt_addr_list;
2228 identity_list *il = mal_to_identity_list(mal);
2232 free_identity_list(msg->reply_to);
2237 case MAILIMF_FIELD_IN_REPLY_TO:
2239 clist *list = _field->fld_data.fld_in_reply_to->mid_list;
2240 stringlist_t *sl = clist_to_stringlist(list);
2244 free_stringlist(msg->in_reply_to);
2245 msg->in_reply_to = sl;
2249 case MAILIMF_FIELD_REFERENCES:
2251 clist *list = _field->fld_data.fld_references->mid_list;
2252 stringlist_t *sl = clist_to_stringlist(list);
2256 free_stringlist(msg->references);
2257 msg->references = sl;
2261 case MAILIMF_FIELD_KEYWORDS:
2263 clist *list = _field->fld_data.fld_keywords->kw_list;
2264 stringlist_t *sl = clist_to_stringlist(list);
2268 free_stringlist(msg->keywords);
2273 case MAILIMF_FIELD_COMMENTS:
2275 char * text = _field->fld_data.fld_comments->cm_value;
2277 free(msg->comments);
2279 r = mailmime_encoded_phrase_parse("utf-8", text,
2280 strlen(text), &index, "utf-8", &msg->comments);
2286 case MAILIMF_FIELD_OPTIONAL_FIELD:
2289 _field->fld_data.fld_optional_field->fld_name;
2291 _field->fld_data.fld_optional_field->fld_value;
2295 r = mailmime_encoded_phrase_parse("utf-8", value,
2296 strlen(value), &index, "utf-8", &_value);
2300 stringpair_t *pair = new_stringpair(name, _value);
2304 opt = stringpair_list_add(opt, pair);
2309 if (msg->opt_fields == NULL)
2310 msg->opt_fields = opt;
2316 return PEP_STATUS_OK;
2319 status = PEP_OUT_OF_MEMORY;
2325 static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
2333 char *charset = NULL;
2342 if (part->mm_body == NULL)
2343 return PEP_ILLEGAL_VALUE;
2345 text = part->mm_body-> dt_data.dt_text.dt_data;
2347 return PEP_ILLEGAL_VALUE;
2349 length = part->mm_body->dt_data.dt_text.dt_length;
2351 if (part->mm_body->dt_encoded) {
2352 int code = part->mm_body->dt_encoding;
2354 int r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
2356 case MAILIMF_NO_ERROR:
2358 case MAILIMF_ERROR_MEMORY:
2359 return PEP_OUT_OF_MEMORY;
2361 return PEP_ILLEGAL_VALUE;
2366 _longmsg = strndup(text, length);
2367 if (_longmsg == NULL)
2368 return PEP_OUT_OF_MEMORY;
2371 if (part->mm_content_type) {
2372 if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
2373 if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
2375 int r = charconv("utf-8", charset, _longmsg, _size, &_text);
2377 case MAILIMF_NO_ERROR:
2379 case MAILIMF_ERROR_MEMORY:
2380 return PEP_OUT_OF_MEMORY;
2382 return PEP_ILLEGAL_VALUE;
2389 // FIXME: KG - we now have the text we want.
2390 // Now we need to strip sigs and process them if they are there..
2393 *longmsg = _longmsg;
2397 return PEP_STATUS_OK;
2400 // THIS IS A BEST-EFFORT ONLY FUNCTION, AND WE ARE NOT DOING MORE THAN THE
2402 static PEP_STATUS interpret_protected_headers(
2403 struct mailmime* mime,
2407 // N.B. this is *very much* enigmail output specific, and right now,
2408 // we only care about subject replacement.
2409 const char* header_string = "Content-Type: text/rfc822-headers; protected-headers=\"v1\"\nContent-Disposition: inline\n\n";
2410 size_t content_length = mime->mm_length;
2411 size_t header_strlen = strlen(header_string);
2412 if (header_strlen < content_length) {
2413 const char* headerblock = mime->mm_mime_start;
2414 size_t subject_len = 0;
2415 headerblock = strstr(headerblock, header_string);
2417 const char* subj_start = "Subject: ";
2418 headerblock = strstr(headerblock, subj_start);
2420 size_t subj_len = strlen(subj_start);
2421 headerblock += subj_len;
2422 char* end_pt = strstr(headerblock, "\n");
2424 if (end_pt != mime->mm_mime_start && *(end_pt - 1) == '\r')
2426 subject_len = end_pt - headerblock;
2427 char* new_subj = (char*)calloc(subject_len + 1, 1);
2429 strlcpy(new_subj, headerblock, subject_len + 1);
2430 free(msg->shortmsg);
2431 msg->shortmsg = new_subj;
2433 } // if there's no endpoint, there's something wrong here so we ignore all
2434 // This is best effort.
2438 return PEP_STATUS_OK;
2441 // ONLY for main part!!!
2442 static PEP_STATUS process_multipart_related(struct mailmime *mime,
2444 PEP_STATUS status = PEP_STATUS_OK;
2449 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2451 if (partlist == NULL)
2452 return PEP_ILLEGAL_VALUE;
2454 clistiter *cur = clist_begin(partlist);
2455 struct mailmime *part = clist_content(cur);
2458 return PEP_ILLEGAL_VALUE;
2460 struct mailmime_content *content = part->mm_content_type;
2463 if (content == NULL)
2464 return PEP_ILLEGAL_VALUE;
2466 if (_is_text_part(content, "html")) {
2467 status = interpret_body(part, &msg->longmsg_formatted,
2474 // This is what we would have done before, so... no
2475 // worse than the status quo. But FIXME!
2476 status = interpret_MIME(part, msg, NULL);
2481 for (cur = clist_next(cur); cur; cur = clist_next(cur)) {
2482 part = clist_content(cur);
2484 return PEP_ILLEGAL_VALUE;
2486 content = part->mm_content_type;
2488 if (content == NULL)
2489 return PEP_ILLEGAL_VALUE;
2491 status = interpret_MIME(part, msg, NULL);
2498 static PEP_STATUS interpret_MIME(
2499 struct mailmime *mime,
2501 bool* raise_msg_attachment
2504 PEP_STATUS status = PEP_STATUS_OK;
2509 struct mailmime_content *content = mime->mm_content_type;
2511 if (_is_multipart(content, "alternative")) {
2512 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2513 if (partlist == NULL)
2514 return PEP_ILLEGAL_VALUE;
2517 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
2518 struct mailmime *part = clist_content(cur);
2520 return PEP_ILLEGAL_VALUE;
2522 content = part->mm_content_type;
2524 if (content == NULL)
2525 return PEP_ILLEGAL_VALUE;
2527 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
2528 status = interpret_body(part, &msg->longmsg, NULL);
2532 else if (_is_text_part(content, "rfc822-headers")) {
2533 status = interpret_protected_headers(part, msg);
2537 else if (_is_text_part(content, "html") &&
2538 msg->longmsg_formatted == NULL) {
2539 status = interpret_body(part, &msg->longmsg_formatted,
2544 else if (_is_multipart(content, "related") &&
2545 msg->longmsg_formatted == NULL) {
2546 status = process_multipart_related(part, msg);
2550 else /* add as attachment */ {
2551 status = interpret_MIME(part, msg, NULL);
2557 else if (_is_multipart(content, "encrypted")) {
2558 if (msg->longmsg == NULL)
2559 msg->longmsg = strdup("");
2560 assert(msg->longmsg);
2562 return PEP_OUT_OF_MEMORY;
2564 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2565 if (partlist == NULL)
2566 return PEP_ILLEGAL_VALUE;
2569 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
2570 struct mailmime *part= clist_content(cur);
2572 return PEP_ILLEGAL_VALUE;
2574 status = interpret_MIME(part, msg, NULL);
2575 if (status != PEP_STATUS_OK)
2579 else if (_is_multipart(content, NULL)) {
2580 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2581 if (partlist == NULL)
2582 return PEP_ILLEGAL_VALUE;
2585 // only add raise_msg_attachment on 2nd part!
2587 for (cur = clist_begin(partlist); cur; cur = clist_next(cur), _att_count++) {
2588 struct mailmime *part= clist_content(cur);
2590 return PEP_ILLEGAL_VALUE;
2591 status = interpret_MIME(part, msg, _att_count == 1 ? raise_msg_attachment : NULL);
2592 if (status != PEP_STATUS_OK)
2597 if (_is_text_part(content, "html") &&
2598 msg->longmsg_formatted == NULL &&
2599 msg->longmsg == NULL) {
2600 status = interpret_body(mime, &msg->longmsg_formatted,
2605 else if (_is_text_part(content, "rfc822-headers")) {
2606 status = interpret_protected_headers(mime, msg);
2610 else if (_is_text_part(content, "plain") &&
2611 msg->longmsg == NULL && msg->longmsg_formatted == NULL) {
2612 status = interpret_body(mime, &msg->longmsg, NULL);
2616 else if (_is_text_part(content, NULL) &&
2617 !_is_text_part(content, "plain") &&
2618 msg->longmsg == NULL) {
2619 status = interpret_body(mime, &msg->longmsg, NULL);
2624 // Fixme - we need a control on recursion level here - KG: maybe NOT. We only go to depth 1.
2625 if (raise_msg_attachment != NULL) {
2626 bool is_msg = (_is_message_part(content, "rfc822") || _is_text_part(content, "rfc822"));
2628 if (content->ct_parameters) {
2630 for (cur = clist_begin(content->ct_parameters); cur; cur =
2632 struct mailmime_parameter * param = clist_content(cur);
2633 if (param && param->pa_name && strcasecmp(param->pa_name, "forwarded") == 0) {
2634 if (param->pa_value && strcasecmp(param->pa_value, "no") == 0) {
2635 *raise_msg_attachment = true;
2650 r = _get_content_type(content, &mime_type, &charset);
2655 return PEP_ILLEGAL_VALUE;
2657 return PEP_OUT_OF_MEMORY;
2659 return PEP_UNKNOWN_ERROR;
2664 status = interpret_body(mime, &data, &size);
2668 pEp_rid_list_t* resource_id_list = _get_resource_id_list(mime);
2669 pEp_rid_list_t* chosen_resource_id = choose_resource_id(resource_id_list);
2671 //filename = _get_filename_or_cid(mime);
2672 char *_filename = NULL;
2674 if (chosen_resource_id) {
2675 filename = chosen_resource_id->rid;
2678 /* The prefix we just added shouldn't be a problem - this is about decoding %XX (RFC 2392) */
2679 /* If it becomes one, we have some MESSY fixing to do. :( */
2680 r = mailmime_encoded_phrase_parse("utf-8", filename,
2681 strlen(filename), &index, "utf-8", &_filename);
2685 char* file_prefix = NULL;
2687 /* in case there are others later */
2688 switch (chosen_resource_id->rid_type) {
2690 file_prefix = "cid";
2692 case PEP_RID_FILENAME:
2693 file_prefix = "file";
2701 filename = build_uri(file_prefix, _filename);
2703 _filename = filename;
2707 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
2708 mime_type, _filename);
2710 free_rid_list(resource_id_list);
2711 resource_id_list = NULL;
2713 return PEP_OUT_OF_MEMORY;
2714 if (msg->attachments == NULL)
2715 msg->attachments = _a;
2720 return PEP_STATUS_OK;
2723 return PEP_OUT_OF_MEMORY;
2726 DYNAMIC_API PEP_STATUS mime_decode_message(
2727 const char *mimetext,
2732 return _mime_decode_message_internal(mimetext, size, msg, NULL);
2736 PEP_STATUS _mime_decode_message_internal(
2737 const char *mimetext,
2740 bool* raise_msg_attachment
2743 PEP_STATUS status = PEP_STATUS_OK;
2744 struct mailmime * mime = NULL;
2746 message *_msg = NULL;
2752 if (!(mimetext && msg))
2753 return PEP_ILLEGAL_VALUE;
2758 r = mailmime_parse(mimetext, size, &index, &mime);
2762 if (r == MAILIMF_ERROR_MEMORY)
2768 _msg = calloc(1, sizeof(message));
2773 clist * _fieldlist = _get_fields(mime);
2775 status = read_fields(_msg, _fieldlist);
2776 if (status != PEP_STATUS_OK)
2780 struct mailmime_content *content = _get_content(mime);
2783 status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
2784 _msg, raise_msg_attachment);
2785 if (status != PEP_STATUS_OK)
2789 mailmime_free(mime);
2795 status = PEP_ILLEGAL_VALUE;
2799 status = PEP_OUT_OF_MEMORY;
2805 mailmime_free(mime);