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,
44 struct mailmime * build_info;
48 char * attr_name = NULL;
49 char * attr_value = NULL;
50 struct mailmime_parameter * param = NULL;
51 clist * parameters = NULL;
52 char *boundary = NULL;
57 mime_type = MAILMIME_SINGLE;
60 switch (content->ct_type->tp_type) {
61 case MAILMIME_TYPE_DISCRETE_TYPE:
62 mime_type = MAILMIME_SINGLE;
65 case MAILMIME_TYPE_COMPOSITE_TYPE:
66 switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
67 case MAILMIME_COMPOSITE_TYPE_MULTIPART:
68 mime_type = MAILMIME_MULTIPLE;
71 case MAILMIME_COMPOSITE_TYPE_MESSAGE:
72 if (strcasecmp(content->ct_subtype, "rfc822") == 0)
73 mime_type = MAILMIME_MESSAGE;
75 mime_type = MAILMIME_SINGLE;
88 if (mime_type == MAILMIME_MULTIPLE) {
94 attr_name = strdup("boundary");
96 if (attr_name == NULL)
99 boundary = generate_boundary();
101 attr_value = boundary;
102 if (attr_value == NULL)
105 param = mailmime_parameter_new(attr_name, attr_value);
112 if (content->ct_parameters == NULL) {
113 parameters = clist_new();
115 if (parameters == NULL)
119 parameters = content->ct_parameters;
122 r = clist_append(parameters, param);
127 if (content->ct_parameters == NULL)
128 content->ct_parameters = parameters;
131 build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
132 NULL, NULL, list, NULL, NULL);
133 if (build_info == NULL)
143 if (content->ct_parameters == NULL)
145 clist_free(parameters);
147 mailmime_parameter_free(param);
151 struct mailmime * get_pgp_encrypted_part(void)
153 struct mailmime * mime = NULL;
154 struct mailmime_fields * mime_fields = NULL;
155 struct mailmime_content * content = NULL;
158 content = mailmime_content_new_with_str("application/pgp-encrypted");
162 mime_fields = mailmime_fields_new_empty();
163 if (mime_fields == NULL)
166 mime = part_new_empty(content, mime_fields, 1);
172 r = mailmime_set_body_text(mime, "Version: 1\n", 10);
180 mailmime_content_free(content);
182 mailmime_fields_free(mime_fields);
189 struct mailmime * get_text_part(
190 pEp_rid_list_t* resource,
191 const char * mime_type,
197 char * disposition_name = NULL;
198 struct mailmime_fields * mime_fields = NULL;
199 struct mailmime * mime = NULL;
200 struct mailmime_content * content = NULL;
201 struct mailmime_parameter * param = NULL;
202 struct mailmime_disposition * disposition = NULL;
203 struct mailmime_mechanism * encoding = NULL;
204 char* content_id = NULL;
207 if (resource != NULL && resource->rid != NULL) {
208 switch (resource->rid_type) {
210 content_id = strdup(resource->rid);
212 case PEP_RID_FILENAME:
214 disposition_name = strdup(resource->rid);
215 if (disposition_name == NULL)
219 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
220 disposition_name, NULL, NULL, NULL, (size_t) -1);
222 if (disposition == NULL)
225 disposition_name = NULL;
231 encoding = mailmime_mechanism_new(encoding_type, NULL);
232 if (encoding == NULL)
236 mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
238 if (mime_fields == NULL)
244 content = mailmime_content_new_with_str(mime_type);
248 if (encoding_type != MAILMIME_MECHANISM_7BIT) {
249 param = mailmime_param_new_with_data("charset", "utf-8");
250 r = clist_append(content->ct_parameters, param);
255 mime = part_new_empty(content, mime_fields, 1);
262 r = mailmime_set_body_text(mime, (char *) text, length);
270 free(disposition_name);
272 mailmime_fields_free(mime_fields);
276 mailmime_content_free(content);
278 mailmime_parameter_free(param);
280 mailmime_disposition_free(disposition);
282 mailmime_mechanism_free(encoding);
287 struct mailmime * get_file_part(
288 pEp_rid_list_t* resource,
289 const char * mime_type,
292 bool transport_encode
295 char * disposition_name = NULL;
297 struct mailmime_disposition * disposition = NULL;
298 struct mailmime_mechanism * encoding = NULL;
299 struct mailmime_content * content = NULL;
300 struct mailmime * mime = NULL;
301 struct mailmime_fields * mime_fields = NULL;
302 char* content_id = NULL;
305 if (resource != NULL && resource->rid != NULL) {
306 switch (resource->rid_type) {
308 content_id = strdup(resource->rid);
310 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
311 NULL, NULL, NULL, NULL, (size_t) -1);
312 if (disposition == NULL)
315 case PEP_RID_FILENAME:
317 disposition_name = strdup(resource->rid);
318 if (disposition_name == NULL)
322 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
323 disposition_name, NULL, NULL, NULL, (size_t) -1);
325 if (disposition == NULL)
327 disposition_name = NULL;
334 content = mailmime_content_new_with_str(mime_type);
340 if (transport_encode) {
341 encoding_type = MAILMIME_MECHANISM_BASE64;
342 encoding = mailmime_mechanism_new(encoding_type, NULL);
343 if (encoding == NULL)
347 mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
349 if (mime_fields == NULL)
354 mime = part_new_empty(content, mime_fields, 1);
362 r = mailmime_set_body_text(mime, data, length);
370 free(disposition_name);
372 mailmime_disposition_free(disposition);
374 mailmime_mechanism_free(encoding);
376 mailmime_content_free(content);
378 mailmime_fields_free(mime_fields);
385 struct mailmime * part_multiple_new(const char *type)
387 struct mailmime_fields *mime_fields = NULL;
388 struct mailmime_content *content = NULL;
389 struct mailmime *mp = NULL;
391 mime_fields = mailmime_fields_new_empty();
392 if (mime_fields == NULL)
395 content = mailmime_content_new_with_str(type);
399 mp = part_new_empty(content, mime_fields, 0);
407 mailmime_content_free(content);
409 mailmime_fields_free(mime_fields);
414 struct mailimf_field * _new_field(
416 _new_func_t new_func,
420 void *data = new_func(value);
425 struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
427 if (result == NULL) {
432 result->fld_type = type;
433 result->fld_data.fld_return_path = data;
438 void _free_field(struct mailimf_field *field)
441 free(field->fld_data.fld_return_path);
448 _new_func_t new_func,
453 struct mailimf_field * field;
459 field = _new_field(type, new_func, value);
463 r = clist_append(list, field);
470 // http://media2.giga.de/2014/02/Image-28.jpg
472 struct mailimf_date_time * timestamp_to_etpantime(const struct tm *ts)
474 struct mailimf_date_time * result = calloc(1,
475 sizeof(struct mailimf_date_time));
482 result->dt_sec = ts->tm_sec;
483 result->dt_min = ts->tm_min;
484 result->dt_hour = ts->tm_hour;
485 result->dt_day = ts->tm_mday;
486 result->dt_month = ts->tm_mon + 1;
487 result->dt_year = ts->tm_year + 1900;
489 result->dt_zone = (int) (ts->tm_gmtoff / 36L);
494 struct tm * etpantime_to_timestamp(const struct mailimf_date_time *et)
496 struct tm * result = calloc(1, sizeof(struct tm));
503 result->tm_sec = et->dt_sec;
504 result->tm_min = et->dt_min;
505 result->tm_hour = et->dt_hour;
506 result->tm_mday = et->dt_day;
507 result->tm_mon = et->dt_month - 1;
508 result->tm_year = et->dt_year - 1900;
510 result->tm_gmtoff = 36L * (long) et->dt_zone;
515 struct mailimf_mailbox * mailbox_from_string(
520 struct mailimf_mailbox *mb = NULL;
522 char *_address = NULL;
526 _name = name ? strdup(name) : strdup("");
530 _address = strdup(address);
531 if (_address == NULL)
534 mb = mailimf_mailbox_new(_name, _address);
549 struct mailimf_field * create_optional_field(
556 struct mailimf_optional_field *optional_field = NULL;
558 _field = strdup(field);
562 if (!must_field_value_be_encoded(value))
563 _value = strdup(value);
565 _value = mailmime_encode_subject_header("utf-8", value, 0);
569 optional_field = mailimf_optional_field_new(_field, _value);
570 if (optional_field == NULL)
573 struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
578 result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
579 result->fld_data.fld_optional_field = optional_field;
584 if (optional_field) {
585 mailimf_optional_field_free(optional_field);
595 int _append_optional_field(
602 struct mailimf_field * optional_field =
603 create_optional_field(field, value);
605 if (optional_field == NULL)
608 r = clist_append(list, optional_field);
610 mailimf_field_free(optional_field);
615 clist * _get_fields(struct mailmime * mime)
617 clist * _fieldlist = NULL;
621 if (mime->mm_data.mm_message.mm_fields &&
622 mime->mm_data.mm_message.mm_fields->fld_list) {
623 _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
629 struct mailmime_content * _get_content(struct mailmime * mime)
631 struct mailmime_content * content = NULL;
635 if (mime->mm_data.mm_message.mm_msg_mime)
636 content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
642 /* Return a list of identifier_type and resource id (filename, cid, etc) */
643 pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
645 clist * _fieldlist = NULL;
649 if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
650 _fieldlist = mime->mm_mime_fields->fld_list;
656 pEp_rid_list_t* rid_list = NULL;
657 pEp_rid_list_t** rid_list_curr_p = &rid_list;
659 for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
660 struct mailmime_field * _field = clist_content(cur);
662 if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
663 pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
664 new_rid->rid_type = PEP_RID_CID;
665 new_rid->rid = strdup(_field->fld_data.fld_id);
666 *rid_list_curr_p = new_rid;
667 rid_list_curr_p = &new_rid->next;
669 else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
671 if (_field->fld_data.fld_disposition &&
672 _field->fld_data.fld_disposition->dsp_parms) {
674 _field->fld_data.fld_disposition->dsp_parms;
676 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
678 struct mailmime_disposition_parm * param =
680 if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
681 pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
682 new_rid->rid_type = PEP_RID_FILENAME;
683 new_rid->rid = strdup(param->pa_data.pa_filename);
684 *rid_list_curr_p = new_rid;
685 rid_list_curr_p = &new_rid->next;
691 /* Will almost certainly usually be a singleton, but we need to be able to decide */
696 /* FIXME: about to be obsoleted? */
697 char * _get_filename_or_cid(struct mailmime *mime)
699 clist * _fieldlist = NULL;
703 if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
704 _fieldlist = mime->mm_mime_fields->fld_list;
710 char* _temp_filename_ptr = NULL;
712 for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
713 struct mailmime_field * _field = clist_content(cur);
714 if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
715 /* We prefer CIDs to filenames when both are present */
716 free(_temp_filename_ptr); /* can be null, it's ok */
717 return build_uri("cid", _field->fld_data.fld_id);
719 else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
720 if (_field->fld_data.fld_disposition &&
721 _field->fld_data.fld_disposition->dsp_parms &&
722 !_temp_filename_ptr) {
724 _field->fld_data.fld_disposition->dsp_parms;
726 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
728 struct mailmime_disposition_parm * param =
730 if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
731 _temp_filename_ptr = build_uri("file", param->pa_data.pa_filename);
738 /* Ok, it wasn't a CID */
739 return _temp_filename_ptr;
742 static bool parameter_has_value(
743 struct mailmime_content *content,
753 clist * list = content->ct_parameters;
757 for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
758 struct mailmime_parameter * param = clist_content(cur);
760 param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
761 param->pa_value && strcasecmp(value, param->pa_value) == 0)
768 bool _is_multipart(struct mailmime_content *content, const char *subtype)
772 if (content->ct_type && content->ct_type->tp_type ==
773 MAILMIME_TYPE_COMPOSITE_TYPE &&
774 content->ct_type->tp_data.tp_composite_type &&
775 content->ct_type->tp_data.tp_composite_type->ct_type ==
776 MAILMIME_COMPOSITE_TYPE_MULTIPART) {
778 return content->ct_subtype &&
779 strcasecmp(content->ct_subtype, subtype) == 0;
787 bool _is_PGP_MIME(struct mailmime_content *content)
791 if (_is_multipart(content, "encrypted") &&
792 parameter_has_value(content, "protocol",
793 "application/pgp-encrypted"))
799 bool _is_text_part(struct mailmime_content *content, const char *subtype)
803 if (content->ct_type && content->ct_type->tp_type ==
804 MAILMIME_TYPE_DISCRETE_TYPE &&
805 content->ct_type->tp_data.tp_discrete_type &&
806 content->ct_type->tp_data.tp_discrete_type->dt_type ==
807 MAILMIME_DISCRETE_TYPE_TEXT) {
809 return content->ct_subtype &&
810 strcasecmp(content->ct_subtype, subtype) == 0;
818 int _get_content_type(
819 const struct mailmime_content *content,
825 char *_charset = NULL;
834 if (content->ct_subtype == NULL)
837 if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
839 const char *_main_type;
841 switch (content->ct_type->tp_data.tp_discrete_type->dt_type) {
842 case MAILMIME_DISCRETE_TYPE_TEXT:
845 case MAILMIME_DISCRETE_TYPE_IMAGE:
846 _main_type = "image";
848 case MAILMIME_DISCRETE_TYPE_AUDIO:
849 _main_type = "audio";
851 case MAILMIME_DISCRETE_TYPE_VIDEO:
852 _main_type = "video";
854 case MAILMIME_DISCRETE_TYPE_APPLICATION:
855 _main_type = "application";
857 case MAILMIME_DISCRETE_TYPE_EXTENSION:
858 _main_type = "extension";
864 len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
865 _type = calloc(1, len);
870 strncpy(_type, _main_type, len);
871 len -= strlen(_main_type);
872 strncat(_type, "/", len--);
873 strncat(_type, content->ct_subtype, len);
875 if (content->ct_parameters) {
877 for (cur = clist_begin(content->ct_parameters); cur; cur =
879 struct mailmime_parameter * param = clist_content(cur);
880 if (param && param->pa_name && strcasecmp(param->pa_name,
882 _charset = param->pa_value;
887 *charset = strdup(_charset);
897 // Only for null-terminated field strings.
898 // can this field be transported as is without modification?)
899 // (See rfc2822, section 2.2.3 - libetpan's handling isn't quite what
901 bool must_field_value_be_encoded(const char* field_value) {
905 return must_chunk_be_encoded((const void*)field_value, strlen(field_value), false);
908 bool must_chunk_be_encoded(const void* value, size_t size, bool ignore_fws) {
910 const char* begin_ptr = (const char*)value;
912 const char* end_ptr = begin_ptr + size;
914 const char* cur_char_ptr = begin_ptr;
915 while (cur_char_ptr < end_ptr) {
916 char cur_char = *cur_char_ptr;
917 if (cur_char > 127 || cur_char < 0)
919 // FIXME - do we need to deal with CRCRLF here?
920 // I guess in the worst case, it gets encoded, which
921 // is *supposed* to be harmless...
923 if (cur_char == '\r') {
924 const char* next = cur_char_ptr + 1;
925 const char* nextnext = next + 1;
926 if (next >= end_ptr || nextnext >= end_ptr
928 || (*nextnext != ' ' && *nextnext != '\t')) {
932 else if (cur_char == '\n') {
933 const char* prev = cur_char_ptr - 1;
934 if (prev == begin_ptr || *prev != '\r')
943 #define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
945 #define PATH_SEP '\\'
950 static PEP_STATUS interpret_MIME(struct mailmime *mime,
953 // This function was rewritten to use in-memory buffers instead of
954 // temporary files when the pgp/mime support was implemented for
955 // outlook, as the existing code did not work well on windows.
957 static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
959 PEP_STATUS status = PEP_STATUS_OK;
967 buffer = mmap_string_new(NULL);
972 r = mailmime_write_mem(buffer, &col, mime);
973 assert(r == MAILIMF_NO_ERROR);
974 if (r == MAILIMF_ERROR_MEMORY)
976 else if (r != MAILIMF_NO_ERROR)
979 // we overallocate by 1 byte, so we have a terminating 0.
981 buf = calloc(len + 1, 1);
985 memcpy(buf, buffer->str, len);
986 mmap_string_free(buffer);
989 return PEP_STATUS_OK;
992 status = PEP_CANNOT_CREATE_TEMP_FILE;
996 status = PEP_OUT_OF_MEMORY;
1000 mmap_string_free(buffer);
1006 static PEP_STATUS mime_attachment(
1008 struct mailmime **result,
1009 bool transport_encode
1012 PEP_STATUS status = PEP_STATUS_OK;
1013 struct mailmime * mime = NULL;
1020 // TODO: It seems the pEp COM server adapter sends an empty string here,
1021 // which leads to a crash later. Thus, we workaround here by treating an
1022 // empty string as NULL. We need to check whether the bug really is here,
1023 // or the pEp COM server adapter needs to be changed.
1024 if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
1025 mime_type = "application/octet-stream";
1027 mime_type = blob->mime_type;
1029 pEp_rid_list_t* resource = parse_uri(blob->filename);
1031 bool already_ascii = !(must_chunk_be_encoded(blob->value, blob->size, true));
1033 mime = get_file_part(resource, mime_type, blob->value, blob->size,
1034 (already_ascii ? false : transport_encode));
1035 free_rid_list(resource);
1042 return PEP_STATUS_OK;
1045 status = PEP_OUT_OF_MEMORY;
1048 mailmime_free(mime);
1053 static PEP_STATUS mime_html_text(
1054 const char *plaintext,
1055 const char *htmltext,
1056 bloblist_t *attachments,
1057 struct mailmime **result,
1058 bool transport_encode
1061 PEP_STATUS status = PEP_STATUS_OK;
1062 struct mailmime * top_level_html_mime = NULL;
1063 struct mailmime * mime = NULL;
1064 struct mailmime * submime = NULL;
1073 mime = part_multiple_new("multipart/alternative");
1078 pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
1080 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
1081 submime = get_text_part(NULL, "text/plain", plaintext, strlen(plaintext),
1083 free_rid_list(resource);
1087 if (submime == NULL)
1090 r = mailmime_smart_add_part(mime, submime);
1091 assert(r == MAILIMF_NO_ERROR);
1092 if (r == MAILIMF_ERROR_MEMORY) {
1096 // mailmime_smart_add_part() takes ownership of submime
1100 bool inlined_attachments = false;
1102 bloblist_t* traversal_ptr = attachments;
1104 while (traversal_ptr) {
1105 if (traversal_ptr->disposition == PEP_CONTENT_DISP_INLINE) {
1106 inlined_attachments = true;
1109 traversal_ptr = traversal_ptr->next;
1112 if (inlined_attachments) {
1113 /* Noooooo... dirk, why do you do this to me? */
1114 submime = part_multiple_new("multipart/related");
1116 if (submime == NULL)
1119 top_level_html_mime = submime;
1121 r = mailmime_smart_add_part(mime, top_level_html_mime);
1122 assert(r == MAILIMF_NO_ERROR);
1123 if (r == MAILIMF_ERROR_MEMORY) {
1127 // mailmime_smart_add_part() takes ownership of submime
1132 top_level_html_mime = mime;
1135 // resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
1136 submime = get_text_part(NULL, "text/html", htmltext, strlen(htmltext),
1138 free_rid_list(resource);
1142 if (submime == NULL)
1145 r = mailmime_smart_add_part(top_level_html_mime, submime);
1146 assert(r == MAILIMF_NO_ERROR);
1147 if (r == MAILIMF_ERROR_MEMORY)
1150 // mailmime_smart_add_part() takes ownership of submime
1155 for (_a = attachments; _a != NULL; _a = _a->next) {
1156 if (_a->disposition != PEP_CONTENT_DISP_INLINE)
1158 status = mime_attachment(_a, &submime, transport_encode);
1159 if (status != PEP_STATUS_OK)
1160 return PEP_UNKNOWN_ERROR; // FIXME
1162 r = mailmime_smart_add_part(top_level_html_mime, submime);
1163 assert(r == MAILIMF_NO_ERROR);
1164 if (r == MAILIMF_ERROR_MEMORY) {
1168 // mailmime_smart_add_part() takes ownership of submime
1174 return PEP_STATUS_OK;
1177 status = PEP_OUT_OF_MEMORY;
1180 mailmime_free(mime);
1183 mailmime_free(submime);
1189 // FIXME: maybe need to add transport_encode field here
1190 static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
1192 char *_username = NULL;
1193 struct mailimf_mailbox *mb;
1195 if (!ident->username)
1196 _username = strdup("");
1198 _username = must_field_value_be_encoded(ident->username) ?
1199 mailmime_encode_subject_header("utf-8", ident->username, 0) :
1200 strdup(ident->username);
1203 if (_username == NULL)
1206 mb = mailbox_from_string(_username, ident->address);
1220 static struct mailimf_mailbox_list * identity_to_mbl(
1221 const pEp_identity *ident)
1223 struct mailimf_mailbox_list *mbl = NULL;
1224 struct mailimf_mailbox *mb = NULL;
1234 mb = identity_to_mailbox(ident);
1238 r = clist_append(list, mb);
1242 mbl = mailimf_mailbox_list_new(list);
1250 mailimf_mailbox_free(mb);
1258 static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
1260 struct mailimf_address_list *mal = NULL;
1261 struct mailimf_mailbox *mb = NULL;
1262 struct mailimf_address * addr = NULL;
1273 for (_il = il; _il && _il->ident; _il = _il->next) {
1274 mb = identity_to_mailbox(_il->ident);
1278 addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
1283 r = clist_append(list, addr);
1288 mal = mailimf_address_list_new(list);
1296 mailimf_mailbox_free(mb);
1299 mailimf_address_free(addr);
1307 static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
1309 clist * cl = clist_new();
1314 if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
1318 for (_sl = sl; _sl; _sl = _sl->next) {
1320 char * value = ((transport_encode && must_field_value_be_encoded(_sl->value)) ?
1321 mailmime_encode_subject_header("utf-8", _sl->value, 0) :
1322 strdup(_sl->value));
1324 if (value == NULL) {
1328 r = clist_append(cl, value);
1340 static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
1342 PEP_STATUS status = PEP_STATUS_OK;
1343 struct mailimf_fields * fields = NULL;
1345 clist * fields_list = NULL;
1346 unsigned char pEpstr[] = PEP_SUBJ_STRING; // unsigned due to UTF-8 byte fun
1348 char* altstr = "pEp";
1350 char* altstr = (char*)pEpstr;
1352 char *subject = msg->shortmsg ? msg->shortmsg : altstr;
1359 fields_list = clist_new();
1360 assert(fields_list);
1361 if (fields_list == NULL)
1365 char *_msgid = strdup(msg->id);
1370 r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
1371 (_new_func_t) mailimf_message_id_new, _msgid);
1379 struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
1383 r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
1384 (_new_func_t) mailimf_orig_date_new, dt);
1386 mailimf_date_time_free(dt);
1393 struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
1397 r = _append_field(fields_list, MAILIMF_FIELD_FROM,
1398 (_new_func_t) mailimf_from_new, from);
1400 mailimf_mailbox_list_free(from);
1406 struct mailimf_address_list *to = identity_list_to_mal(msg->to);
1410 r = _append_field(fields_list, MAILIMF_FIELD_TO,
1411 (_new_func_t) mailimf_to_new, to);
1413 mailimf_address_list_free(to);
1418 char* _subject = NULL;
1419 if (!must_field_value_be_encoded(subject)) {
1420 _subject = strdup(subject);
1424 _subject = mailmime_encode_subject_header("utf-8", subject, 1);
1426 if (_subject == NULL)
1429 r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
1430 (_new_func_t) mailimf_subject_new, _subject);
1437 struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
1441 r = _append_field(fields_list, MAILIMF_FIELD_CC,
1442 (_new_func_t) mailimf_cc_new, cc);
1444 mailimf_address_list_free(cc);
1450 struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
1454 r = _append_field(fields_list, MAILIMF_FIELD_BCC,
1455 (_new_func_t) mailimf_bcc_new, bcc);
1457 mailimf_address_list_free(bcc);
1462 if (msg->reply_to) {
1463 struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
1464 if (reply_to == NULL)
1467 r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
1468 (_new_func_t) mailimf_reply_to_new, reply_to);
1470 mailimf_address_list_free(reply_to);
1475 if (msg->in_reply_to) {
1476 clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
1477 if (in_reply_to == NULL)
1480 r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
1481 (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
1483 clist_free(in_reply_to);
1488 if (msg->references) {
1489 clist *references = stringlist_to_clist(msg->references, true);
1490 if (references == NULL)
1493 r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
1494 (_new_func_t) mailimf_references_new, references);
1496 clist_free(references);
1501 if (msg->keywords) {
1502 clist *keywords = stringlist_to_clist(msg->keywords, true);
1503 if (keywords == NULL)
1506 r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
1507 (_new_func_t) mailimf_keywords_new, keywords);
1509 clist_free(keywords);
1514 if (msg->comments) {
1515 char *comments = NULL;
1516 if (!must_field_value_be_encoded(msg->comments)) {
1517 comments = strdup(msg->comments);
1521 comments = mailmime_encode_subject_header("utf-8", msg->comments, 0);
1523 if (comments == NULL)
1526 r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
1527 (_new_func_t) mailimf_comments_new, comments);
1534 if (msg->opt_fields) {
1535 stringpair_list_t *_l;
1536 for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
1537 char *key = _l->value->key;
1538 char *value = _l->value->value;
1540 r = _append_optional_field(fields_list, key, value);
1548 fields = mailimf_fields_new(fields_list);
1555 return PEP_STATUS_OK;
1558 status = PEP_OUT_OF_MEMORY;
1561 clist_free(fields_list);
1564 mailimf_fields_free(fields);
1569 static bool has_exceptional_extension(char* filename) {
1572 int len = strlen(filename);
1575 char* ext_start = filename + (len - 4);
1576 if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
1577 strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
1582 static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
1583 pEp_rid_list_t* retval = rid_list;
1585 /* multiple elements - least common case */
1586 if (rid_list && rid_list->next) {
1587 pEp_rid_list_t* rid_list_curr = rid_list;
1590 while (rid_list_curr) {
1591 pEp_resource_id_type rid_type = rid_list_curr->rid_type;
1592 if (rid_type == PEP_RID_CID)
1593 retval = rid_list_curr;
1594 else if (rid_type == PEP_RID_FILENAME && has_exceptional_extension(rid_list_curr->rid))
1595 return rid_list_curr;
1596 rid_list_curr = rid_list_curr->next;
1602 // static void split_inlined_and_attached(bloblist_t** inlined, bloblist_t** attached) {
1603 // bloblist_t** curr_pp = attached;
1604 // bloblist_t* curr = *curr_pp;
1606 // bloblist_t* inline_ret = NULL;
1607 // bloblist_t** inline_curr_pp = &inline_ret;
1609 // bloblist_t* att_ret = NULL;
1610 // bloblist_t** att_curr_pp = &att_ret;
1613 // if (curr->disposition == PEP_CONTENT_DISP_INLINE) {
1614 // *inline_curr_pp = curr;
1615 // inline_curr_pp = &(curr->next);
1618 // *att_curr_pp = curr;
1619 // att_curr_pp = &(curr->next);
1621 // *curr_pp = curr->next;
1622 // curr->next = NULL;
1626 // *inlined = inline_ret;
1627 // *attached = att_ret;
1631 static PEP_STATUS mime_encode_message_plain(
1634 struct mailmime **result,
1635 bool transport_encode
1638 struct mailmime * mime = NULL;
1639 struct mailmime * submime = NULL;
1649 //subject = (msg->shortmsg) ? msg->shortmsg : "pEp"; // not used, yet.
1650 plaintext = (msg->longmsg) ? msg->longmsg : "";
1651 htmltext = msg->longmsg_formatted;
1653 if (htmltext && (htmltext[0] != '\0')) {
1654 /* first, we need to strip out the inlined attachments to ensure this
1655 gets set up correctly */
1657 status = mime_html_text(plaintext, htmltext, msg->attachments, &mime,
1660 if (status != PEP_STATUS_OK)
1664 pEp_rid_list_t* resource = NULL;
1665 if (is_PGP_message_text(plaintext)) {
1666 resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
1667 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
1668 mime = get_text_part(resource, "application/octet-stream", plaintext,
1669 strlen(plaintext), encoding_type);
1672 resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
1673 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
1674 mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
1677 free_rid_list(resource);
1684 bool normal_attachments = false;
1686 bloblist_t* traversal_ptr = msg->attachments;
1688 while (traversal_ptr) {
1689 if (traversal_ptr->disposition != PEP_CONTENT_DISP_INLINE) {
1690 normal_attachments = true;
1693 traversal_ptr = traversal_ptr->next;
1696 if (normal_attachments) {
1698 mime = part_multiple_new("multipart/mixed");
1703 r = mailmime_smart_add_part(mime, submime);
1704 assert(r == MAILIMF_NO_ERROR);
1705 if (r == MAILIMF_ERROR_MEMORY) {
1709 // mailmime_smart_add_part() takes ownership of submime
1714 for (_a = msg->attachments; _a != NULL; _a = _a->next) {
1716 if (_a->disposition == PEP_CONTENT_DISP_INLINE)
1719 status = mime_attachment(_a, &submime, transport_encode);
1720 if (status != PEP_STATUS_OK)
1723 r = mailmime_smart_add_part(mime, submime);
1724 assert(r == MAILIMF_NO_ERROR);
1725 if (r == MAILIMF_ERROR_MEMORY) {
1729 // mailmime_smart_add_part() takes ownership of submime
1736 return PEP_STATUS_OK;
1739 status = PEP_OUT_OF_MEMORY;
1743 mailmime_free(mime);
1746 mailmime_free(submime);
1751 static PEP_STATUS mime_encode_message_PGP_MIME(
1752 const message * msg,
1754 struct mailmime **result
1757 struct mailmime * mime = NULL;
1758 struct mailmime * submime = NULL;
1759 struct mailmime_parameter * param;
1763 size_t plaintext_size;
1765 assert(msg->attachments && msg->attachments->next &&
1766 msg->attachments->next->value);
1768 plaintext = msg->attachments->next->value;
1769 plaintext_size = msg->attachments->next->size;
1771 mime = part_multiple_new("multipart/encrypted");
1776 param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
1777 clist_append(mime->mm_content_type->ct_parameters, param);
1779 submime = get_pgp_encrypted_part();
1781 if (submime == NULL)
1784 r = mailmime_smart_add_part(mime, submime);
1785 assert(r == MAILIMF_NO_ERROR);
1786 if (r == MAILIMF_ERROR_MEMORY) {
1790 // mailmime_smart_add_part() takes ownership of submime
1794 pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
1795 submime = get_text_part(resource, "application/octet-stream", plaintext,
1796 plaintext_size, MAILMIME_MECHANISM_7BIT);
1798 free_rid_list(resource);
1801 if (submime == NULL)
1804 r = mailmime_smart_add_part(mime, submime);
1805 assert(r == MAILIMF_NO_ERROR);
1806 if (r == MAILIMF_ERROR_MEMORY) {
1810 // mailmime_smart_add_part() takes ownership of submime
1815 return PEP_STATUS_OK;
1818 status = PEP_OUT_OF_MEMORY;
1821 mailmime_free(mime);
1824 mailmime_free(submime);
1829 PEP_STATUS _mime_encode_message_internal(
1830 const message * msg,
1833 bool transport_encode
1836 PEP_STATUS status = PEP_STATUS_OK;
1837 struct mailmime * msg_mime = NULL;
1838 struct mailmime * mime = NULL;
1839 struct mailimf_fields * fields = NULL;
1846 if (!(msg && mimetext))
1847 return PEP_ILLEGAL_VALUE;
1851 switch (msg->enc_format) {
1853 status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode);
1856 case PEP_enc_inline:
1857 status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode);
1860 case PEP_enc_S_MIME:
1863 case PEP_enc_PGP_MIME:
1864 status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
1874 if (status != PEP_STATUS_OK)
1877 msg_mime = mailmime_new_message_data(NULL);
1879 if (msg_mime == NULL)
1882 r = mailmime_add_part(msg_mime, mime);
1884 mailmime_free(mime);
1890 status = build_fields(msg, &fields);
1891 if (status != PEP_STATUS_OK)
1894 mailmime_set_imf_fields(msg_mime, fields);
1897 status = render_mime(msg_mime, &buf);
1898 if (status != PEP_STATUS_OK)
1901 mailmime_free(msg_mime);
1904 return PEP_STATUS_OK;
1907 status = PEP_OUT_OF_MEMORY;
1911 mailmime_free(msg_mime);
1914 mailmime_free(mime);
1919 static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
1921 char *username = NULL;
1924 assert(mb->mb_addr_spec);
1926 if (mb->mb_addr_spec == NULL)
1929 if (mb->mb_display_name) {
1931 const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
1932 strlen(mb->mb_display_name), &index, "utf-8", &username);
1937 pEp_identity *ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
1949 static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
1951 struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
1952 return mailbox_to_identity(mb);
1955 static identity_list * mal_to_identity_list(
1956 const struct mailimf_address_list *mal
1960 clist *list = mal->ad_list;
1962 identity_list *il = new_identity_list(NULL);
1966 identity_list *_il = il;
1967 for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
1968 pEp_identity *ident;
1970 struct mailimf_address *addr = clist_content(cur);
1971 switch(addr->ad_type) {
1972 case MAILIMF_ADDRESS_MAILBOX:
1973 ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
1976 _il = identity_list_add(_il, ident);
1981 case MAILIMF_ADDRESS_GROUP:
1983 struct mailimf_mailbox_list * mbl =
1984 addr->ad_data.ad_group->grp_mb_list;
1985 for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
1986 cur2 = clist_next(cur2)) {
1987 ident = mailbox_to_identity(clist_content(cur));
1990 _il = identity_list_add(_il, ident);
2006 free_identity_list(il);
2010 static stringlist_t * clist_to_stringlist(const clist *list)
2013 stringlist_t * sl = new_stringlist(NULL);
2017 stringlist_t *_sl = sl;
2018 for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
2019 char *phrase = clist_content(cur);
2022 const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
2023 &index, "utf-8", &text);
2027 _sl = stringlist_add(_sl, text);
2038 free_stringlist(sl);
2044 static PEP_STATUS read_fields(message *msg, clist *fieldlist)
2046 PEP_STATUS status = PEP_STATUS_OK;
2047 struct mailimf_field * _field;
2052 stringpair_list_t *opt = msg->opt_fields;
2055 return PEP_STATUS_OK;
2057 for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
2058 _field = clist_content(cur);
2060 switch (_field->fld_type) {
2061 case MAILIMF_FIELD_MESSAGE_ID:
2063 char * text = _field->fld_data.fld_message_id->mid_value;
2067 r = mailmime_encoded_phrase_parse("utf-8", text,
2068 strlen(text), &index, "utf-8", &msg->id);
2074 case MAILIMF_FIELD_SUBJECT:
2076 char * text = _field->fld_data.fld_subject->sbj_value;
2078 free(msg->shortmsg);
2080 r = mailmime_encoded_phrase_parse("utf-8", text,
2081 strlen(text), &index, "utf-8", &msg->shortmsg);
2087 case MAILIMF_FIELD_ORIG_DATE:
2089 struct mailimf_date_time *date =
2090 _field->fld_data.fld_orig_date->dt_date_time;
2092 free_timestamp(msg->sent);
2093 msg->sent = etpantime_to_timestamp(date);
2094 if (msg->sent == NULL)
2099 case MAILIMF_FIELD_FROM:
2101 struct mailimf_mailbox_list *mbl =
2102 _field->fld_data.fld_from->frm_mb_list;
2103 pEp_identity *ident;
2105 ident = mbl_to_identity(mbl);
2109 free_identity(msg->from);
2114 case MAILIMF_FIELD_TO:
2116 struct mailimf_address_list *mal =
2117 _field->fld_data.fld_to->to_addr_list;
2118 identity_list *il = mal_to_identity_list(mal);
2122 free_identity_list(msg->to);
2127 case MAILIMF_FIELD_CC:
2129 struct mailimf_address_list *mal =
2130 _field->fld_data.fld_cc->cc_addr_list;
2131 identity_list *il = mal_to_identity_list(mal);
2135 free_identity_list(msg->cc);
2140 case MAILIMF_FIELD_BCC:
2142 struct mailimf_address_list *mal =
2143 _field->fld_data.fld_bcc->bcc_addr_list;
2144 identity_list *il = mal_to_identity_list(mal);
2148 free_identity_list(msg->bcc);
2153 case MAILIMF_FIELD_REPLY_TO:
2155 struct mailimf_address_list *mal =
2156 _field->fld_data.fld_reply_to->rt_addr_list;
2157 identity_list *il = mal_to_identity_list(mal);
2161 free_identity_list(msg->reply_to);
2166 case MAILIMF_FIELD_IN_REPLY_TO:
2168 clist *list = _field->fld_data.fld_in_reply_to->mid_list;
2169 stringlist_t *sl = clist_to_stringlist(list);
2173 free_stringlist(msg->in_reply_to);
2174 msg->in_reply_to = sl;
2178 case MAILIMF_FIELD_REFERENCES:
2180 clist *list = _field->fld_data.fld_references->mid_list;
2181 stringlist_t *sl = clist_to_stringlist(list);
2185 free_stringlist(msg->references);
2186 msg->references = sl;
2190 case MAILIMF_FIELD_KEYWORDS:
2192 clist *list = _field->fld_data.fld_keywords->kw_list;
2193 stringlist_t *sl = clist_to_stringlist(list);
2197 free_stringlist(msg->keywords);
2202 case MAILIMF_FIELD_COMMENTS:
2204 char * text = _field->fld_data.fld_comments->cm_value;
2206 free(msg->comments);
2208 r = mailmime_encoded_phrase_parse("utf-8", text,
2209 strlen(text), &index, "utf-8", &msg->comments);
2215 case MAILIMF_FIELD_OPTIONAL_FIELD:
2218 _field->fld_data.fld_optional_field->fld_name;
2220 _field->fld_data.fld_optional_field->fld_value;
2224 r = mailmime_encoded_phrase_parse("utf-8", value,
2225 strlen(value), &index, "utf-8", &_value);
2229 stringpair_t *pair = new_stringpair(name, _value);
2233 opt = stringpair_list_add(opt, pair);
2238 if (msg->opt_fields == NULL)
2239 msg->opt_fields = opt;
2245 return PEP_STATUS_OK;
2248 status = PEP_OUT_OF_MEMORY;
2254 static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
2262 char *charset = NULL;
2271 if (part->mm_body == NULL)
2272 return PEP_ILLEGAL_VALUE;
2274 text = part->mm_body-> dt_data.dt_text.dt_data;
2276 return PEP_ILLEGAL_VALUE;
2278 length = part->mm_body->dt_data.dt_text.dt_length;
2280 if (part->mm_body->dt_encoded) {
2281 int code = part->mm_body->dt_encoding;
2283 int r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
2285 case MAILIMF_NO_ERROR:
2287 case MAILIMF_ERROR_MEMORY:
2288 return PEP_OUT_OF_MEMORY;
2290 return PEP_ILLEGAL_VALUE;
2295 _longmsg = strndup(text, length);
2296 if (_longmsg == NULL)
2297 return PEP_OUT_OF_MEMORY;
2300 if (part->mm_content_type) {
2301 if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
2302 if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
2304 int r = charconv("utf-8", charset, _longmsg, _size, &_text);
2306 case MAILIMF_NO_ERROR:
2308 case MAILIMF_ERROR_MEMORY:
2309 return PEP_OUT_OF_MEMORY;
2311 return PEP_ILLEGAL_VALUE;
2318 // FIXME: KG - we now have the text we want.
2319 // Now we need to strip sigs and process them if they are there..
2322 *longmsg = _longmsg;
2326 return PEP_STATUS_OK;
2329 // THIS IS A BEST-EFFORT ONLY FUNCTION, AND WE ARE NOT DOING MORE THAN THE
2331 static PEP_STATUS interpret_protected_headers(
2332 struct mailmime* mime,
2336 // N.B. this is *very much* enigmail output specific, and right now,
2337 // we only care about subject replacement.
2338 const char* header_string = "Content-Type: text/rfc822-headers; protected-headers=\"v1\"\nContent-Disposition: inline\n\n";
2339 size_t content_length = mime->mm_length;
2340 size_t header_strlen = strlen(header_string);
2341 if (header_strlen < content_length) {
2342 const char* headerblock = mime->mm_mime_start;
2343 size_t subject_len = 0;
2344 headerblock = strstr(headerblock, header_string);
2346 const char* subj_start = "Subject: ";
2347 headerblock = strstr(headerblock, subj_start);
2349 size_t subj_len = strlen(subj_start);
2350 headerblock += subj_len;
2351 char* end_pt = strstr(headerblock, "\n");
2353 if (end_pt != mime->mm_mime_start && *(end_pt - 1) == '\r')
2355 subject_len = end_pt - headerblock;
2356 char* new_subj = (char*)calloc(subject_len + 1, 1);
2358 strlcpy(new_subj, headerblock, subject_len + 1);
2359 free(msg->shortmsg);
2360 msg->shortmsg = new_subj;
2362 } // if there's no endpoint, there's something wrong here so we ignore all
2363 // This is best effort.
2367 return PEP_STATUS_OK;
2370 // ONLY for main part!!!
2371 static PEP_STATUS process_multipart_related(struct mailmime *mime,
2373 PEP_STATUS status = PEP_STATUS_OK;
2378 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2380 if (partlist == NULL)
2381 return PEP_ILLEGAL_VALUE;
2383 clistiter *cur = clist_begin(partlist);
2384 struct mailmime *part = clist_content(cur);
2387 return PEP_ILLEGAL_VALUE;
2389 struct mailmime_content *content = part->mm_content_type;
2392 if (content == NULL)
2393 return PEP_ILLEGAL_VALUE;
2395 if (_is_text_part(content, "html")) {
2396 status = interpret_body(part, &msg->longmsg_formatted,
2403 // This is what we would have done before, so... no
2404 // worse than the status quo. But FIXME!
2405 status = interpret_MIME(part, msg);
2410 for (cur = clist_next(cur); cur; cur = clist_next(cur)) {
2411 part = clist_content(cur);
2413 return PEP_ILLEGAL_VALUE;
2415 content = part->mm_content_type;
2417 if (content == NULL)
2418 return PEP_ILLEGAL_VALUE;
2420 status = interpret_MIME(part, msg);
2427 static PEP_STATUS interpret_MIME(
2428 struct mailmime *mime,
2432 PEP_STATUS status = PEP_STATUS_OK;
2437 struct mailmime_content *content = mime->mm_content_type;
2439 if (_is_multipart(content, "alternative")) {
2440 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2441 if (partlist == NULL)
2442 return PEP_ILLEGAL_VALUE;
2445 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
2446 struct mailmime *part = clist_content(cur);
2448 return PEP_ILLEGAL_VALUE;
2450 content = part->mm_content_type;
2452 if (content == NULL)
2453 return PEP_ILLEGAL_VALUE;
2455 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
2456 status = interpret_body(part, &msg->longmsg, NULL);
2460 else if (_is_text_part(content, "rfc822-headers")) {
2461 status = interpret_protected_headers(part, msg);
2465 else if (_is_text_part(content, "html") &&
2466 msg->longmsg_formatted == NULL) {
2467 status = interpret_body(part, &msg->longmsg_formatted,
2472 else if (_is_multipart(content, "related") &&
2473 msg->longmsg_formatted == NULL) {
2474 status = process_multipart_related(part, msg);
2478 else /* add as attachment */ {
2479 status = interpret_MIME(part, msg);
2485 else if (_is_multipart(content, "encrypted")) {
2486 if (msg->longmsg == NULL)
2487 msg->longmsg = strdup("");
2488 assert(msg->longmsg);
2490 return PEP_OUT_OF_MEMORY;
2492 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2493 if (partlist == NULL)
2494 return PEP_ILLEGAL_VALUE;
2497 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
2498 struct mailmime *part= clist_content(cur);
2500 return PEP_ILLEGAL_VALUE;
2502 status = interpret_MIME(part, msg);
2503 if (status != PEP_STATUS_OK)
2507 else if (_is_multipart(content, NULL)) {
2508 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
2509 if (partlist == NULL)
2510 return PEP_ILLEGAL_VALUE;
2513 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
2514 struct mailmime *part= clist_content(cur);
2516 return PEP_ILLEGAL_VALUE;
2517 status = interpret_MIME(part, msg);
2518 if (status != PEP_STATUS_OK)
2523 if (_is_text_part(content, "html") &&
2524 msg->longmsg_formatted == NULL &&
2525 msg->longmsg == NULL) {
2526 status = interpret_body(mime, &msg->longmsg_formatted,
2531 else if (_is_text_part(content, "rfc822-headers")) {
2532 status = interpret_protected_headers(mime, msg);
2536 else if (_is_text_part(content, "plain") &&
2537 msg->longmsg == NULL && msg->longmsg_formatted == NULL) {
2538 status = interpret_body(mime, &msg->longmsg, NULL);
2542 else if (_is_text_part(content, NULL) &&
2543 !_is_text_part(content, "plain") &&
2544 msg->longmsg == NULL) {
2545 status = interpret_body(mime, &msg->longmsg, NULL);
2557 r = _get_content_type(content, &mime_type, &charset);
2562 return PEP_ILLEGAL_VALUE;
2564 return PEP_OUT_OF_MEMORY;
2566 return PEP_UNKNOWN_ERROR;
2571 status = interpret_body(mime, &data, &size);
2575 pEp_rid_list_t* resource_id_list = _get_resource_id_list(mime);
2576 pEp_rid_list_t* chosen_resource_id = choose_resource_id(resource_id_list);
2578 //filename = _get_filename_or_cid(mime);
2579 char *_filename = NULL;
2581 if (chosen_resource_id) {
2582 filename = chosen_resource_id->rid;
2585 /* The prefix we just added shouldn't be a problem - this is about decoding %XX (RFC 2392) */
2586 /* If it becomes one, we have some MESSY fixing to do. :( */
2587 r = mailmime_encoded_phrase_parse("utf-8", filename,
2588 strlen(filename), &index, "utf-8", &_filename);
2592 char* file_prefix = NULL;
2594 /* in case there are others later */
2595 switch (chosen_resource_id->rid_type) {
2597 file_prefix = "cid";
2599 case PEP_RID_FILENAME:
2600 file_prefix = "file";
2608 filename = build_uri(file_prefix, _filename);
2610 _filename = filename;
2614 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
2615 mime_type, _filename);
2617 free_rid_list(resource_id_list);
2618 resource_id_list = NULL;
2620 return PEP_OUT_OF_MEMORY;
2621 if (msg->attachments == NULL)
2622 msg->attachments = _a;
2627 return PEP_STATUS_OK;
2630 return PEP_OUT_OF_MEMORY;
2633 DYNAMIC_API PEP_STATUS mime_decode_message(
2634 const char *mimetext,
2639 PEP_STATUS status = PEP_STATUS_OK;
2640 struct mailmime * mime = NULL;
2642 message *_msg = NULL;
2648 if (!(mimetext && msg))
2649 return PEP_ILLEGAL_VALUE;
2654 r = mailmime_parse(mimetext, size, &index, &mime);
2658 if (r == MAILIMF_ERROR_MEMORY)
2664 _msg = calloc(1, sizeof(message));
2669 clist * _fieldlist = _get_fields(mime);
2671 status = read_fields(_msg, _fieldlist);
2672 if (status != PEP_STATUS_OK)
2676 struct mailmime_content *content = _get_content(mime);
2679 status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
2681 if (status != PEP_STATUS_OK)
2685 mailmime_free(mime);
2691 status = PEP_ILLEGAL_VALUE;
2695 status = PEP_OUT_OF_MEMORY;
2701 mailmime_free(mime);