1 // This file is under GNU General Public License 3.0
4 #include "pEp_internal.h"
12 #include "resource_id.h"
13 #include "etpan_mime.h"
16 static bool is_whitespace(char c)
30 DYNAMIC_API bool is_PGP_message_text(const char *text)
35 for (; *text && is_whitespace(*text); text++);
37 return strncmp(text, "-----BEGIN PGP MESSAGE-----", 27) == 0;
40 #define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
47 // This function was rewritten to use in-memory buffers instead of
48 // temporary files when the pgp/mime support was implemented for
49 // outlook, as the existing code did not work well on windows.
51 static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
53 PEP_STATUS status = PEP_STATUS_OK;
61 buffer = mmap_string_new(NULL);
66 r = mailmime_write_mem(buffer, &col, mime);
67 assert(r == MAILIMF_NO_ERROR);
68 if (r == MAILIMF_ERROR_MEMORY)
70 else if (r != MAILIMF_NO_ERROR)
73 // we overallocate by 1 byte, so we have a terminating 0.
75 buf = calloc(len + 1, 1);
79 memcpy(buf, buffer->str, len);
80 mmap_string_free(buffer);
86 status = PEP_CANNOT_CREATE_TEMP_FILE;
90 status = PEP_OUT_OF_MEMORY;
94 mmap_string_free(buffer);
100 static PEP_STATUS mime_attachment(
102 struct mailmime **result,
103 bool transport_encode
106 PEP_STATUS status = PEP_STATUS_OK;
107 struct mailmime * mime = NULL;
114 // TODO: It seems the pEp COM server adapter sends an empty string here,
115 // which leads to a crash later. Thus, we workaround here by treating an
116 // empty string as NULL. We need to check whether the bug really is here,
117 // or the pEp COM server adapter needs to be changed.
118 if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
119 mime_type = "application/octet-stream";
121 mime_type = blob->mime_type;
123 pEp_rid_list_t* resource = parse_uri(blob->filename);
125 bool already_ascii = !(must_chunk_be_encoded(blob->value, blob->size, true));
127 mime = get_file_part(resource, mime_type, blob->value, blob->size,
128 (already_ascii ? false : transport_encode));
129 free_rid_list(resource);
136 return PEP_STATUS_OK;
139 status = PEP_OUT_OF_MEMORY;
147 static PEP_STATUS mime_html_text(
148 const char *plaintext,
149 const char *htmltext,
150 bloblist_t *attachments,
151 struct mailmime **result,
152 bool transport_encode
155 PEP_STATUS status = PEP_STATUS_OK;
156 struct mailmime * top_level_html_mime = NULL;
157 struct mailmime * mime = NULL;
158 struct mailmime * submime = NULL;
167 mime = part_multiple_new("multipart/alternative");
172 pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
174 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
175 submime = get_text_part(NULL, "text/plain", plaintext, strlen(plaintext),
177 free_rid_list(resource);
184 r = mailmime_smart_add_part(mime, submime);
185 assert(r == MAILIMF_NO_ERROR);
186 if (r == MAILIMF_ERROR_MEMORY) {
190 // mailmime_smart_add_part() takes ownership of submime
194 bool inlined_attachments = false;
196 bloblist_t* traversal_ptr = attachments;
198 while (traversal_ptr) {
199 if (traversal_ptr->disposition == PEP_CONTENT_DISP_INLINE) {
200 inlined_attachments = true;
203 traversal_ptr = traversal_ptr->next;
206 if (inlined_attachments) {
207 /* Noooooo... dirk, why do you do this to me? */
208 submime = part_multiple_new("multipart/related");
213 top_level_html_mime = submime;
215 r = mailmime_smart_add_part(mime, top_level_html_mime);
216 assert(r == MAILIMF_NO_ERROR);
217 if (r == MAILIMF_ERROR_MEMORY) {
221 // mailmime_smart_add_part() takes ownership of submime
226 top_level_html_mime = mime;
229 // resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
230 submime = get_text_part(NULL, "text/html", htmltext, strlen(htmltext),
232 free_rid_list(resource);
239 r = mailmime_smart_add_part(top_level_html_mime, submime);
240 assert(r == MAILIMF_NO_ERROR);
241 if (r == MAILIMF_ERROR_MEMORY)
244 // mailmime_smart_add_part() takes ownership of submime
249 for (_a = attachments; _a != NULL; _a = _a->next) {
250 if (_a->disposition != PEP_CONTENT_DISP_INLINE)
252 status = mime_attachment(_a, &submime, transport_encode);
253 if (status != PEP_STATUS_OK)
254 return PEP_UNKNOWN_ERROR; // FIXME
256 r = mailmime_smart_add_part(top_level_html_mime, submime);
257 assert(r == MAILIMF_NO_ERROR);
258 if (r == MAILIMF_ERROR_MEMORY) {
262 // mailmime_smart_add_part() takes ownership of submime
268 return PEP_STATUS_OK;
271 status = PEP_OUT_OF_MEMORY;
277 mailmime_free(submime);
283 // FIXME: maybe need to add transport_encode field here
284 static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
286 char *_username = NULL;
287 struct mailimf_mailbox *mb;
289 if (!ident->username)
290 _username = strdup("");
292 _username = must_field_value_be_encoded(ident->username) ?
293 mailmime_encode_subject_header("utf-8", ident->username, 0) :
294 strdup(ident->username);
297 if (_username == NULL)
300 mb = mailbox_from_string(_username, ident->address);
314 static struct mailimf_mailbox_list * identity_to_mbl(
315 const pEp_identity *ident)
317 struct mailimf_mailbox_list *mbl = NULL;
318 struct mailimf_mailbox *mb = NULL;
328 mb = identity_to_mailbox(ident);
332 r = clist_append(list, mb);
336 mbl = mailimf_mailbox_list_new(list);
344 mailimf_mailbox_free(mb);
352 static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
354 struct mailimf_address_list *mal = NULL;
355 struct mailimf_mailbox *mb = NULL;
356 struct mailimf_address * addr = NULL;
367 for (_il = il; _il && _il->ident; _il = _il->next) {
368 mb = identity_to_mailbox(_il->ident);
372 addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
377 r = clist_append(list, addr);
382 mal = mailimf_address_list_new(list);
390 mailimf_mailbox_free(mb);
393 mailimf_address_free(addr);
401 static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
403 clist * cl = clist_new();
408 if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
412 for (_sl = sl; _sl; _sl = _sl->next) {
414 char * value = ((transport_encode && must_field_value_be_encoded(_sl->value)) ?
415 mailmime_encode_subject_header("utf-8", _sl->value, 0) :
422 r = clist_append(cl, value);
434 static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
436 PEP_STATUS status = PEP_STATUS_OK;
437 struct mailimf_fields * fields = NULL;
439 clist * fields_list = NULL;
440 unsigned char pEpstr[] = PEP_SUBJ_STRING; // unsigned due to UTF-8 byte fun
442 char* altstr = "pEp";
444 char* altstr = (char*)pEpstr;
446 char *subject = msg->shortmsg ? msg->shortmsg : altstr;
450 assert(msg->from->address);
455 fields_list = clist_new();
457 if (fields_list == NULL)
461 char *_msgid = strdup(msg->id);
466 r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
467 (_new_func_t) mailimf_message_id_new, _msgid);
475 struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
479 r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
480 (_new_func_t) mailimf_orig_date_new, dt);
482 mailimf_date_time_free(dt);
488 /* if (msg->from) */ {
489 struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
493 r = _append_field(fields_list, MAILIMF_FIELD_FROM,
494 (_new_func_t) mailimf_from_new, from);
496 mailimf_mailbox_list_free(from);
502 struct mailimf_address_list *to = identity_list_to_mal(msg->to);
506 r = _append_field(fields_list, MAILIMF_FIELD_TO,
507 (_new_func_t) mailimf_to_new, to);
509 mailimf_address_list_free(to);
514 char* _subject = NULL;
515 if (!must_field_value_be_encoded(subject)) {
516 _subject = strdup(subject);
520 _subject = mailmime_encode_subject_header("utf-8", subject, 1);
522 if (_subject == NULL)
525 r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
526 (_new_func_t) mailimf_subject_new, _subject);
533 struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
537 r = _append_field(fields_list, MAILIMF_FIELD_CC,
538 (_new_func_t) mailimf_cc_new, cc);
540 mailimf_address_list_free(cc);
546 struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
550 r = _append_field(fields_list, MAILIMF_FIELD_BCC,
551 (_new_func_t) mailimf_bcc_new, bcc);
553 mailimf_address_list_free(bcc);
559 struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
560 if (reply_to == NULL)
563 r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
564 (_new_func_t) mailimf_reply_to_new, reply_to);
566 mailimf_address_list_free(reply_to);
571 if (msg->in_reply_to) {
572 clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
573 if (in_reply_to == NULL)
576 r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
577 (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
579 clist_free(in_reply_to);
584 if (msg->references) {
585 clist *references = stringlist_to_clist(msg->references, true);
586 if (references == NULL)
589 r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
590 (_new_func_t) mailimf_references_new, references);
592 clist_free(references);
598 clist *keywords = stringlist_to_clist(msg->keywords, true);
599 if (keywords == NULL)
602 r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
603 (_new_func_t) mailimf_keywords_new, keywords);
605 clist_free(keywords);
611 char *comments = NULL;
612 if (!must_field_value_be_encoded(msg->comments)) {
613 comments = strdup(msg->comments);
617 comments = mailmime_encode_subject_header("utf-8", msg->comments, 0);
619 if (comments == NULL)
622 r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
623 (_new_func_t) mailimf_comments_new, comments);
630 if (msg->opt_fields) {
631 stringpair_list_t *_l;
632 for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
633 char *key = _l->value->key;
634 char *value = _l->value->value;
636 r = _append_optional_field(fields_list, key, value);
644 fields = mailimf_fields_new(fields_list);
651 return PEP_STATUS_OK;
654 status = PEP_OUT_OF_MEMORY;
657 clist_free(fields_list);
660 mailimf_fields_free(fields);
665 static bool has_exceptional_extension(char* filename) {
668 int len = strlen(filename);
671 char* ext_start = filename + (len - 4);
672 if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
673 strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
678 static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
679 pEp_rid_list_t* retval = rid_list;
681 /* multiple elements - least common case */
682 if (rid_list && rid_list->next) {
683 pEp_rid_list_t* rid_list_curr = rid_list;
686 while (rid_list_curr) {
687 pEp_resource_id_type rid_type = rid_list_curr->rid_type;
688 if (rid_type == PEP_RID_CID)
689 retval = rid_list_curr;
690 else if (rid_type == PEP_RID_FILENAME && has_exceptional_extension(rid_list_curr->rid))
691 return rid_list_curr;
692 rid_list_curr = rid_list_curr->next;
698 // static void split_inlined_and_attached(bloblist_t** inlined, bloblist_t** attached) {
699 // bloblist_t** curr_pp = attached;
700 // bloblist_t* curr = *curr_pp;
702 // bloblist_t* inline_ret = NULL;
703 // bloblist_t** inline_curr_pp = &inline_ret;
705 // bloblist_t* att_ret = NULL;
706 // bloblist_t** att_curr_pp = &att_ret;
709 // if (curr->disposition == PEP_CONTENT_DISP_INLINE) {
710 // *inline_curr_pp = curr;
711 // inline_curr_pp = &(curr->next);
714 // *att_curr_pp = curr;
715 // att_curr_pp = &(curr->next);
717 // *curr_pp = curr->next;
718 // curr->next = NULL;
722 // *inlined = inline_ret;
723 // *attached = att_ret;
727 static PEP_STATUS mime_encode_message_plain(
730 struct mailmime **result,
731 bool transport_encode
734 struct mailmime * mime = NULL;
735 struct mailmime * submime = NULL;
745 //subject = (msg->shortmsg) ? msg->shortmsg : "pEp"; // not used, yet.
746 plaintext = (msg->longmsg) ? msg->longmsg : "";
747 htmltext = msg->longmsg_formatted;
749 if (htmltext && (htmltext[0] != '\0')) {
750 /* first, we need to strip out the inlined attachments to ensure this
751 gets set up correctly */
753 status = mime_html_text(plaintext, htmltext, msg->attachments, &mime,
756 if (status != PEP_STATUS_OK)
760 pEp_rid_list_t* resource = NULL;
761 if (is_PGP_message_text(plaintext)) {
762 resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
763 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
764 mime = get_text_part(resource, "application/octet-stream", plaintext,
765 strlen(plaintext), encoding_type);
768 resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
769 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
770 mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
773 free_rid_list(resource);
780 bool normal_attachments = false;
782 bloblist_t* traversal_ptr = msg->attachments;
784 while (traversal_ptr) {
785 if (traversal_ptr->disposition != PEP_CONTENT_DISP_INLINE) {
786 normal_attachments = true;
789 traversal_ptr = traversal_ptr->next;
792 if (normal_attachments) {
794 mime = part_multiple_new("multipart/mixed");
799 r = mailmime_smart_add_part(mime, submime);
800 assert(r == MAILIMF_NO_ERROR);
801 if (r == MAILIMF_ERROR_MEMORY) {
805 // mailmime_smart_add_part() takes ownership of submime
810 for (_a = msg->attachments; _a != NULL; _a = _a->next) {
812 if (_a->disposition == PEP_CONTENT_DISP_INLINE)
815 status = mime_attachment(_a, &submime, transport_encode);
816 if (status != PEP_STATUS_OK)
819 r = mailmime_smart_add_part(mime, submime);
820 assert(r == MAILIMF_NO_ERROR);
821 if (r == MAILIMF_ERROR_MEMORY) {
825 // mailmime_smart_add_part() takes ownership of submime
832 return PEP_STATUS_OK;
835 status = PEP_OUT_OF_MEMORY;
842 mailmime_free(submime);
847 static PEP_STATUS mime_encode_message_PGP_MIME(
850 struct mailmime **result
853 struct mailmime * mime = NULL;
854 struct mailmime * submime = NULL;
855 struct mailmime_parameter * param;
859 size_t plaintext_size;
861 assert(msg->attachments && msg->attachments->next &&
862 msg->attachments->next->value);
864 plaintext = msg->attachments->next->value;
865 plaintext_size = msg->attachments->next->size;
867 mime = part_multiple_new("multipart/encrypted");
872 param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
873 clist_append(mime->mm_content_type->ct_parameters, param);
875 submime = get_pgp_encrypted_part();
880 r = mailmime_smart_add_part(mime, submime);
881 assert(r == MAILIMF_NO_ERROR);
882 if (r == MAILIMF_ERROR_MEMORY) {
886 // mailmime_smart_add_part() takes ownership of submime
890 pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
891 submime = get_text_part(resource, "application/octet-stream", plaintext,
892 plaintext_size, MAILMIME_MECHANISM_7BIT);
894 free_rid_list(resource);
900 r = mailmime_smart_add_part(mime, submime);
901 assert(r == MAILIMF_NO_ERROR);
902 if (r == MAILIMF_ERROR_MEMORY) {
906 // mailmime_smart_add_part() takes ownership of submime
911 return PEP_STATUS_OK;
914 status = PEP_OUT_OF_MEMORY;
920 mailmime_free(submime);
925 DYNAMIC_API PEP_STATUS mime_encode_message(
931 return _mime_encode_message_internal(msg, omit_fields, mimetext, true);
934 PEP_STATUS _mime_encode_message_internal(
938 bool transport_encode
941 PEP_STATUS status = PEP_STATUS_OK;
942 struct mailmime * msg_mime = NULL;
943 struct mailmime * mime = NULL;
944 struct mailimf_fields * fields = NULL;
951 if (!(msg && mimetext))
952 return PEP_ILLEGAL_VALUE;
956 switch (msg->enc_format) {
958 status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode);
962 status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode);
968 case PEP_enc_PGP_MIME:
969 status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
979 if (status != PEP_STATUS_OK)
982 msg_mime = mailmime_new_message_data(NULL);
984 if (msg_mime == NULL)
987 r = mailmime_add_part(msg_mime, mime);
995 status = build_fields(msg, &fields);
996 if (status != PEP_STATUS_OK)
999 mailmime_set_imf_fields(msg_mime, fields);
1002 status = render_mime(msg_mime, &buf);
1003 if (status != PEP_STATUS_OK)
1006 mailmime_free(msg_mime);
1009 return PEP_STATUS_OK;
1012 status = PEP_OUT_OF_MEMORY;
1016 mailmime_free(msg_mime);
1019 mailmime_free(mime);
1024 static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
1026 char *username = NULL;
1029 assert(mb->mb_addr_spec);
1031 if (mb->mb_addr_spec == NULL)
1034 if (mb->mb_display_name) {
1036 const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
1037 strlen(mb->mb_display_name), &index, "utf-8", &username);
1042 pEp_identity *ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
1054 static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
1056 struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
1057 return mailbox_to_identity(mb);
1060 static identity_list * mal_to_identity_list(
1061 const struct mailimf_address_list *mal
1065 clist *list = mal->ad_list;
1067 identity_list *il = new_identity_list(NULL);
1071 identity_list *_il = il;
1072 for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
1073 pEp_identity *ident;
1075 struct mailimf_address *addr = clist_content(cur);
1076 switch(addr->ad_type) {
1077 case MAILIMF_ADDRESS_MAILBOX:
1078 ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
1081 _il = identity_list_add(_il, ident);
1086 case MAILIMF_ADDRESS_GROUP:
1088 struct mailimf_mailbox_list * mbl =
1089 addr->ad_data.ad_group->grp_mb_list;
1090 for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
1091 cur2 = clist_next(cur2)) {
1092 ident = mailbox_to_identity(clist_content(cur));
1095 _il = identity_list_add(_il, ident);
1111 free_identity_list(il);
1115 static stringlist_t * clist_to_stringlist(const clist *list)
1118 stringlist_t * sl = new_stringlist(NULL);
1122 stringlist_t *_sl = sl;
1123 for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
1124 char *phrase = clist_content(cur);
1127 const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
1128 &index, "utf-8", &text);
1132 _sl = stringlist_add(_sl, text);
1143 free_stringlist(sl);
1149 static PEP_STATUS read_fields(message *msg, clist *fieldlist)
1151 PEP_STATUS status = PEP_STATUS_OK;
1152 struct mailimf_field * _field;
1157 stringpair_list_t *opt = msg->opt_fields;
1160 return PEP_STATUS_OK;
1162 for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
1163 _field = clist_content(cur);
1165 switch (_field->fld_type) {
1166 case MAILIMF_FIELD_MESSAGE_ID:
1168 char * text = _field->fld_data.fld_message_id->mid_value;
1172 r = mailmime_encoded_phrase_parse("utf-8", text,
1173 strlen(text), &index, "utf-8", &msg->id);
1179 case MAILIMF_FIELD_SUBJECT:
1181 char * text = _field->fld_data.fld_subject->sbj_value;
1183 free(msg->shortmsg);
1185 r = mailmime_encoded_phrase_parse("utf-8", text,
1186 strlen(text), &index, "utf-8", &msg->shortmsg);
1192 case MAILIMF_FIELD_ORIG_DATE:
1194 struct mailimf_date_time *date =
1195 _field->fld_data.fld_orig_date->dt_date_time;
1197 free_timestamp(msg->sent);
1198 msg->sent = etpantime_to_timestamp(date);
1199 if (msg->sent == NULL)
1204 case MAILIMF_FIELD_FROM:
1206 struct mailimf_mailbox_list *mbl =
1207 _field->fld_data.fld_from->frm_mb_list;
1208 pEp_identity *ident;
1210 ident = mbl_to_identity(mbl);
1214 free_identity(msg->from);
1219 case MAILIMF_FIELD_TO:
1221 struct mailimf_address_list *mal =
1222 _field->fld_data.fld_to->to_addr_list;
1223 identity_list *il = mal_to_identity_list(mal);
1227 free_identity_list(msg->to);
1232 case MAILIMF_FIELD_CC:
1234 struct mailimf_address_list *mal =
1235 _field->fld_data.fld_cc->cc_addr_list;
1236 identity_list *il = mal_to_identity_list(mal);
1240 free_identity_list(msg->cc);
1245 case MAILIMF_FIELD_BCC:
1247 struct mailimf_address_list *mal =
1248 _field->fld_data.fld_bcc->bcc_addr_list;
1249 identity_list *il = mal_to_identity_list(mal);
1253 free_identity_list(msg->bcc);
1258 case MAILIMF_FIELD_REPLY_TO:
1260 struct mailimf_address_list *mal =
1261 _field->fld_data.fld_reply_to->rt_addr_list;
1262 identity_list *il = mal_to_identity_list(mal);
1266 free_identity_list(msg->reply_to);
1271 case MAILIMF_FIELD_IN_REPLY_TO:
1273 clist *list = _field->fld_data.fld_in_reply_to->mid_list;
1274 stringlist_t *sl = clist_to_stringlist(list);
1278 free_stringlist(msg->in_reply_to);
1279 msg->in_reply_to = sl;
1283 case MAILIMF_FIELD_REFERENCES:
1285 clist *list = _field->fld_data.fld_references->mid_list;
1286 stringlist_t *sl = clist_to_stringlist(list);
1290 free_stringlist(msg->references);
1291 msg->references = sl;
1295 case MAILIMF_FIELD_KEYWORDS:
1297 clist *list = _field->fld_data.fld_keywords->kw_list;
1298 stringlist_t *sl = clist_to_stringlist(list);
1302 free_stringlist(msg->keywords);
1307 case MAILIMF_FIELD_COMMENTS:
1309 char * text = _field->fld_data.fld_comments->cm_value;
1311 free(msg->comments);
1313 r = mailmime_encoded_phrase_parse("utf-8", text,
1314 strlen(text), &index, "utf-8", &msg->comments);
1320 case MAILIMF_FIELD_OPTIONAL_FIELD:
1323 _field->fld_data.fld_optional_field->fld_name;
1325 _field->fld_data.fld_optional_field->fld_value;
1329 r = mailmime_encoded_phrase_parse("utf-8", value,
1330 strlen(value), &index, "utf-8", &_value);
1334 stringpair_t *pair = new_stringpair(name, _value);
1338 opt = stringpair_list_add(opt, pair);
1343 if (msg->opt_fields == NULL)
1344 msg->opt_fields = opt;
1350 return PEP_STATUS_OK;
1353 status = PEP_OUT_OF_MEMORY;
1359 static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
1369 char *charset = NULL;
1378 if (part->mm_body == NULL)
1379 return PEP_ILLEGAL_VALUE;
1381 text = part->mm_body-> dt_data.dt_text.dt_data;
1383 return PEP_ILLEGAL_VALUE;
1385 length = part->mm_body->dt_data.dt_text.dt_length;
1387 if (part->mm_body->dt_encoded) {
1388 code = part->mm_body->dt_encoding;
1390 r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
1392 case MAILIMF_NO_ERROR:
1394 case MAILIMF_ERROR_MEMORY:
1395 return PEP_OUT_OF_MEMORY;
1397 return PEP_ILLEGAL_VALUE;
1402 _longmsg = strndup(text, length);
1403 if (_longmsg == NULL)
1404 return PEP_OUT_OF_MEMORY;
1407 if (part->mm_content_type) {
1408 if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
1409 if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
1411 int r = charconv("utf-8", charset, _longmsg, _size, &_text);
1413 case MAILIMF_NO_ERROR:
1415 case MAILIMF_ERROR_MEMORY:
1416 return PEP_OUT_OF_MEMORY;
1418 return PEP_ILLEGAL_VALUE;
1425 // FIXME: KG - we now have the text we want.
1426 // Now we need to strip sigs and process them if they are there..
1429 *longmsg = _longmsg;
1433 return PEP_STATUS_OK;
1436 // THIS IS A BEST-EFFORT ONLY FUNCTION, AND WE ARE NOT DOING MORE THAN THE
1438 static PEP_STATUS interpret_protected_headers(
1439 struct mailmime* mime,
1443 // N.B. this is *very much* enigmail output specific, and right now,
1444 // we only care about subject replacement.
1445 const char* header_string = "Content-Type: text/rfc822-headers; protected-headers=\"v1\"\nContent-Disposition: inline\n\n";
1446 size_t content_length = mime->mm_length;
1447 size_t header_strlen = strlen(header_string);
1448 if (header_strlen < content_length) {
1449 const char* headerblock = mime->mm_mime_start;
1450 size_t subject_len = 0;
1451 headerblock = strstr(headerblock, header_string);
1453 const char* subj_start = "Subject: ";
1454 size_t subj_len = strlen(subj_start);
1455 headerblock = strstr(headerblock, subj_start);
1457 headerblock += subj_len;
1458 char* end_pt = strstr(headerblock, "\n");
1460 if (end_pt != mime->mm_mime_start && *(end_pt - 1) == '\r')
1462 subject_len = end_pt - headerblock;
1463 char* new_subj = (char*)calloc(subject_len + 1, 1);
1465 strlcpy(new_subj, headerblock, subject_len + 1);
1466 free(msg->shortmsg);
1467 msg->shortmsg = new_subj;
1469 } // if there's no endpoint, there's something wrong here so we ignore all
1470 // This is best effort.
1474 return PEP_STATUS_OK;
1477 static PEP_STATUS interpret_MIME(
1478 struct mailmime *mime,
1482 PEP_STATUS status = PEP_STATUS_OK;
1487 struct mailmime_content *content = mime->mm_content_type;
1489 if (_is_multipart(content, "alternative")) {
1490 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
1491 if (partlist == NULL)
1492 return PEP_ILLEGAL_VALUE;
1495 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
1496 struct mailmime *part = clist_content(cur);
1498 return PEP_ILLEGAL_VALUE;
1500 content = part->mm_content_type;
1502 if (content == NULL)
1503 return PEP_ILLEGAL_VALUE;
1505 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
1506 status = interpret_body(part, &msg->longmsg, NULL);
1510 else if (_is_text_part(content, "rfc822-headers")) {
1511 status = interpret_protected_headers(part, msg);
1515 else if (_is_text_part(content, "html") &&
1516 msg->longmsg_formatted == NULL) {
1517 status = interpret_body(part, &msg->longmsg_formatted,
1522 else /* add as attachment */ {
1523 status = interpret_MIME(part, msg);
1529 else if (_is_multipart(content, "encrypted")) {
1530 if (msg->longmsg == NULL)
1531 msg->longmsg = strdup("");
1532 assert(msg->longmsg);
1534 return PEP_OUT_OF_MEMORY;
1536 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
1537 if (partlist == NULL)
1538 return PEP_ILLEGAL_VALUE;
1541 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
1542 struct mailmime *part= clist_content(cur);
1544 return PEP_ILLEGAL_VALUE;
1546 status = interpret_MIME(part, msg);
1547 if (status != PEP_STATUS_OK)
1551 else if (_is_multipart(content, NULL)) {
1552 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
1553 if (partlist == NULL)
1554 return PEP_ILLEGAL_VALUE;
1557 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
1558 struct mailmime *part= clist_content(cur);
1560 return PEP_ILLEGAL_VALUE;
1561 status = interpret_MIME(part, msg);
1562 if (status != PEP_STATUS_OK)
1567 if (_is_text_part(content, "html") &&
1568 msg->longmsg_formatted == NULL) {
1569 status = interpret_body(mime, &msg->longmsg_formatted,
1574 else if (_is_text_part(content, "rfc822-headers")) {
1575 status = interpret_protected_headers(mime, msg);
1579 else if (_is_text_part(content, NULL) && msg->longmsg == NULL) {
1580 status = interpret_body(mime, &msg->longmsg, NULL);
1592 r = _get_content_type(content, &mime_type, &charset);
1597 return PEP_ILLEGAL_VALUE;
1599 return PEP_OUT_OF_MEMORY;
1601 return PEP_UNKNOWN_ERROR;
1606 status = interpret_body(mime, &data, &size);
1610 pEp_rid_list_t* resource_id_list = _get_resource_id_list(mime);
1611 pEp_rid_list_t* chosen_resource_id = choose_resource_id(resource_id_list);
1613 //filename = _get_filename_or_cid(mime);
1614 char *_filename = NULL;
1616 if (chosen_resource_id) {
1617 filename = chosen_resource_id->rid;
1620 /* The prefix we just added shouldn't be a problem - this is about decoding %XX (RFC 2392) */
1621 /* If it becomes one, we have some MESSY fixing to do. :( */
1622 r = mailmime_encoded_phrase_parse("utf-8", filename,
1623 strlen(filename), &index, "utf-8", &_filename);
1627 char* file_prefix = NULL;
1629 /* in case there are others later */
1630 switch (chosen_resource_id->rid_type) {
1632 file_prefix = "cid";
1634 case PEP_RID_FILENAME:
1635 file_prefix = "file";
1643 filename = build_uri(file_prefix, _filename);
1645 _filename = filename;
1649 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
1650 mime_type, _filename);
1652 free_rid_list(resource_id_list);
1653 resource_id_list = NULL;
1655 return PEP_OUT_OF_MEMORY;
1656 if (msg->attachments == NULL)
1657 msg->attachments = _a;
1662 return PEP_STATUS_OK;
1665 return PEP_OUT_OF_MEMORY;
1668 DYNAMIC_API PEP_STATUS mime_decode_message(
1669 const char *mimetext,
1674 PEP_STATUS status = PEP_STATUS_OK;
1675 struct mailmime * mime = NULL;
1677 message *_msg = NULL;
1683 if (!(mimetext && msg))
1684 return PEP_ILLEGAL_VALUE;
1689 r = mailmime_parse(mimetext, size, &index, &mime);
1693 if (r == MAILIMF_ERROR_MEMORY)
1699 _msg = calloc(1, sizeof(message));
1704 clist * _fieldlist = _get_fields(mime);
1706 status = read_fields(_msg, _fieldlist);
1707 if (status != PEP_STATUS_OK)
1711 struct mailmime_content *content = _get_content(mime);
1714 status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
1716 if (status != PEP_STATUS_OK)
1720 mailmime_free(mime);
1726 status = PEP_ILLEGAL_VALUE;
1730 status = PEP_OUT_OF_MEMORY;
1736 mailmime_free(mime);