Replace use of Sequoia's backend with a custom key store.
- Sequoia's key store doesn't meet pep's needs (in particular, the
ability to search on a key's user id) and trying to shoehorn pep's
needs onto Sequoia's key store abstractions is just introducing
overhead with no appreciable gain in functionality.
- This patch changes the Sequoia backend to use a local sqlite
database to store the public keys.
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;
453 fields_list = clist_new();
455 if (fields_list == NULL)
459 char *_msgid = strdup(msg->id);
464 r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
465 (_new_func_t) mailimf_message_id_new, _msgid);
473 struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
477 r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
478 (_new_func_t) mailimf_orig_date_new, dt);
480 mailimf_date_time_free(dt);
487 struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
491 r = _append_field(fields_list, MAILIMF_FIELD_FROM,
492 (_new_func_t) mailimf_from_new, from);
494 mailimf_mailbox_list_free(from);
500 struct mailimf_address_list *to = identity_list_to_mal(msg->to);
504 r = _append_field(fields_list, MAILIMF_FIELD_TO,
505 (_new_func_t) mailimf_to_new, to);
507 mailimf_address_list_free(to);
512 char* _subject = NULL;
513 if (!must_field_value_be_encoded(subject)) {
514 _subject = strdup(subject);
518 _subject = mailmime_encode_subject_header("utf-8", subject, 1);
520 if (_subject == NULL)
523 r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
524 (_new_func_t) mailimf_subject_new, _subject);
531 struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
535 r = _append_field(fields_list, MAILIMF_FIELD_CC,
536 (_new_func_t) mailimf_cc_new, cc);
538 mailimf_address_list_free(cc);
544 struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
548 r = _append_field(fields_list, MAILIMF_FIELD_BCC,
549 (_new_func_t) mailimf_bcc_new, bcc);
551 mailimf_address_list_free(bcc);
557 struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
558 if (reply_to == NULL)
561 r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
562 (_new_func_t) mailimf_reply_to_new, reply_to);
564 mailimf_address_list_free(reply_to);
569 if (msg->in_reply_to) {
570 clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
571 if (in_reply_to == NULL)
574 r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
575 (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
577 clist_free(in_reply_to);
582 if (msg->references) {
583 clist *references = stringlist_to_clist(msg->references, true);
584 if (references == NULL)
587 r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
588 (_new_func_t) mailimf_references_new, references);
590 clist_free(references);
596 clist *keywords = stringlist_to_clist(msg->keywords, true);
597 if (keywords == NULL)
600 r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
601 (_new_func_t) mailimf_keywords_new, keywords);
603 clist_free(keywords);
609 char *comments = NULL;
610 if (!must_field_value_be_encoded(msg->comments)) {
611 comments = strdup(msg->comments);
615 comments = mailmime_encode_subject_header("utf-8", msg->comments, 0);
617 if (comments == NULL)
620 r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
621 (_new_func_t) mailimf_comments_new, comments);
628 if (msg->opt_fields) {
629 stringpair_list_t *_l;
630 for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
631 char *key = _l->value->key;
632 char *value = _l->value->value;
634 r = _append_optional_field(fields_list, key, value);
642 fields = mailimf_fields_new(fields_list);
649 return PEP_STATUS_OK;
652 status = PEP_OUT_OF_MEMORY;
655 clist_free(fields_list);
658 mailimf_fields_free(fields);
663 static bool has_exceptional_extension(char* filename) {
666 int len = strlen(filename);
669 char* ext_start = filename + (len - 4);
670 if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
671 strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
676 static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
677 pEp_rid_list_t* retval = rid_list;
679 /* multiple elements - least common case */
680 if (rid_list && rid_list->next) {
681 pEp_rid_list_t* rid_list_curr = rid_list;
684 while (rid_list_curr) {
685 pEp_resource_id_type rid_type = rid_list_curr->rid_type;
686 if (rid_type == PEP_RID_CID)
687 retval = rid_list_curr;
688 else if (rid_type == PEP_RID_FILENAME && has_exceptional_extension(rid_list_curr->rid))
689 return rid_list_curr;
690 rid_list_curr = rid_list_curr->next;
696 // static void split_inlined_and_attached(bloblist_t** inlined, bloblist_t** attached) {
697 // bloblist_t** curr_pp = attached;
698 // bloblist_t* curr = *curr_pp;
700 // bloblist_t* inline_ret = NULL;
701 // bloblist_t** inline_curr_pp = &inline_ret;
703 // bloblist_t* att_ret = NULL;
704 // bloblist_t** att_curr_pp = &att_ret;
707 // if (curr->disposition == PEP_CONTENT_DISP_INLINE) {
708 // *inline_curr_pp = curr;
709 // inline_curr_pp = &(curr->next);
712 // *att_curr_pp = curr;
713 // att_curr_pp = &(curr->next);
715 // *curr_pp = curr->next;
716 // curr->next = NULL;
720 // *inlined = inline_ret;
721 // *attached = att_ret;
725 static PEP_STATUS mime_encode_message_plain(
728 struct mailmime **result,
729 bool transport_encode
732 struct mailmime * mime = NULL;
733 struct mailmime * submime = NULL;
743 //subject = (msg->shortmsg) ? msg->shortmsg : "pEp"; // not used, yet.
744 plaintext = (msg->longmsg) ? msg->longmsg : "";
745 htmltext = msg->longmsg_formatted;
747 if (htmltext && (htmltext[0] != '\0')) {
748 /* first, we need to strip out the inlined attachments to ensure this
749 gets set up correctly */
751 status = mime_html_text(plaintext, htmltext, msg->attachments, &mime,
754 if (status != PEP_STATUS_OK)
758 pEp_rid_list_t* resource = NULL;
759 if (is_PGP_message_text(plaintext)) {
760 resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
761 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
762 mime = get_text_part(resource, "application/octet-stream", plaintext,
763 strlen(plaintext), encoding_type);
766 resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
767 int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
768 mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
771 free_rid_list(resource);
778 bool normal_attachments = false;
780 bloblist_t* traversal_ptr = msg->attachments;
782 while (traversal_ptr) {
783 if (traversal_ptr->disposition != PEP_CONTENT_DISP_INLINE) {
784 normal_attachments = true;
787 traversal_ptr = traversal_ptr->next;
790 if (normal_attachments) {
792 mime = part_multiple_new("multipart/mixed");
797 r = mailmime_smart_add_part(mime, submime);
798 assert(r == MAILIMF_NO_ERROR);
799 if (r == MAILIMF_ERROR_MEMORY) {
803 // mailmime_smart_add_part() takes ownership of submime
808 for (_a = msg->attachments; _a != NULL; _a = _a->next) {
810 if (_a->disposition == PEP_CONTENT_DISP_INLINE)
813 status = mime_attachment(_a, &submime, transport_encode);
814 if (status != PEP_STATUS_OK)
817 r = mailmime_smart_add_part(mime, submime);
818 assert(r == MAILIMF_NO_ERROR);
819 if (r == MAILIMF_ERROR_MEMORY) {
823 // mailmime_smart_add_part() takes ownership of submime
830 return PEP_STATUS_OK;
833 status = PEP_OUT_OF_MEMORY;
840 mailmime_free(submime);
845 static PEP_STATUS mime_encode_message_PGP_MIME(
848 struct mailmime **result
851 struct mailmime * mime = NULL;
852 struct mailmime * submime = NULL;
853 struct mailmime_parameter * param;
857 size_t plaintext_size;
859 assert(msg->attachments && msg->attachments->next &&
860 msg->attachments->next->value);
862 plaintext = msg->attachments->next->value;
863 plaintext_size = msg->attachments->next->size;
865 mime = part_multiple_new("multipart/encrypted");
870 param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
871 clist_append(mime->mm_content_type->ct_parameters, param);
873 submime = get_pgp_encrypted_part();
878 r = mailmime_smart_add_part(mime, submime);
879 assert(r == MAILIMF_NO_ERROR);
880 if (r == MAILIMF_ERROR_MEMORY) {
884 // mailmime_smart_add_part() takes ownership of submime
888 pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
889 submime = get_text_part(resource, "application/octet-stream", plaintext,
890 plaintext_size, MAILMIME_MECHANISM_7BIT);
892 free_rid_list(resource);
898 r = mailmime_smart_add_part(mime, submime);
899 assert(r == MAILIMF_NO_ERROR);
900 if (r == MAILIMF_ERROR_MEMORY) {
904 // mailmime_smart_add_part() takes ownership of submime
909 return PEP_STATUS_OK;
912 status = PEP_OUT_OF_MEMORY;
918 mailmime_free(submime);
923 DYNAMIC_API PEP_STATUS mime_encode_message(
929 return _mime_encode_message_internal(msg, omit_fields, mimetext, true);
932 PEP_STATUS _mime_encode_message_internal(
936 bool transport_encode
939 PEP_STATUS status = PEP_STATUS_OK;
940 struct mailmime * msg_mime = NULL;
941 struct mailmime * mime = NULL;
942 struct mailimf_fields * fields = NULL;
949 if (!(msg && mimetext))
950 return PEP_ILLEGAL_VALUE;
954 switch (msg->enc_format) {
956 status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode);
960 status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode);
966 case PEP_enc_PGP_MIME:
967 status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
977 if (status != PEP_STATUS_OK)
980 msg_mime = mailmime_new_message_data(NULL);
982 if (msg_mime == NULL)
985 r = mailmime_add_part(msg_mime, mime);
993 status = build_fields(msg, &fields);
994 if (status != PEP_STATUS_OK)
997 mailmime_set_imf_fields(msg_mime, fields);
1000 status = render_mime(msg_mime, &buf);
1001 if (status != PEP_STATUS_OK)
1004 mailmime_free(msg_mime);
1007 return PEP_STATUS_OK;
1010 status = PEP_OUT_OF_MEMORY;
1014 mailmime_free(msg_mime);
1017 mailmime_free(mime);
1022 static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
1024 char *username = NULL;
1027 assert(mb->mb_addr_spec);
1029 if (mb->mb_addr_spec == NULL)
1032 if (mb->mb_display_name) {
1034 const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
1035 strlen(mb->mb_display_name), &index, "utf-8", &username);
1040 pEp_identity *ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
1052 static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
1054 struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
1055 return mailbox_to_identity(mb);
1058 static identity_list * mal_to_identity_list(
1059 const struct mailimf_address_list *mal
1063 clist *list = mal->ad_list;
1065 identity_list *il = new_identity_list(NULL);
1069 identity_list *_il = il;
1070 for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
1071 pEp_identity *ident;
1073 struct mailimf_address *addr = clist_content(cur);
1074 switch(addr->ad_type) {
1075 case MAILIMF_ADDRESS_MAILBOX:
1076 ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
1079 _il = identity_list_add(_il, ident);
1084 case MAILIMF_ADDRESS_GROUP:
1086 struct mailimf_mailbox_list * mbl =
1087 addr->ad_data.ad_group->grp_mb_list;
1088 for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
1089 cur2 = clist_next(cur2)) {
1090 ident = mailbox_to_identity(clist_content(cur));
1093 _il = identity_list_add(_il, ident);
1109 free_identity_list(il);
1113 static stringlist_t * clist_to_stringlist(const clist *list)
1116 stringlist_t * sl = new_stringlist(NULL);
1120 stringlist_t *_sl = sl;
1121 for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
1122 char *phrase = clist_content(cur);
1125 const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
1126 &index, "utf-8", &text);
1130 _sl = stringlist_add(_sl, text);
1141 free_stringlist(sl);
1147 static PEP_STATUS read_fields(message *msg, clist *fieldlist)
1149 PEP_STATUS status = PEP_STATUS_OK;
1150 struct mailimf_field * _field;
1155 stringpair_list_t *opt = msg->opt_fields;
1158 return PEP_STATUS_OK;
1160 for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
1161 _field = clist_content(cur);
1163 switch (_field->fld_type) {
1164 case MAILIMF_FIELD_MESSAGE_ID:
1166 char * text = _field->fld_data.fld_message_id->mid_value;
1170 r = mailmime_encoded_phrase_parse("utf-8", text,
1171 strlen(text), &index, "utf-8", &msg->id);
1177 case MAILIMF_FIELD_SUBJECT:
1179 char * text = _field->fld_data.fld_subject->sbj_value;
1181 free(msg->shortmsg);
1183 r = mailmime_encoded_phrase_parse("utf-8", text,
1184 strlen(text), &index, "utf-8", &msg->shortmsg);
1190 case MAILIMF_FIELD_ORIG_DATE:
1192 struct mailimf_date_time *date =
1193 _field->fld_data.fld_orig_date->dt_date_time;
1195 free_timestamp(msg->sent);
1196 msg->sent = etpantime_to_timestamp(date);
1197 if (msg->sent == NULL)
1202 case MAILIMF_FIELD_FROM:
1204 struct mailimf_mailbox_list *mbl =
1205 _field->fld_data.fld_from->frm_mb_list;
1206 pEp_identity *ident;
1208 ident = mbl_to_identity(mbl);
1212 free_identity(msg->from);
1217 case MAILIMF_FIELD_TO:
1219 struct mailimf_address_list *mal =
1220 _field->fld_data.fld_to->to_addr_list;
1221 identity_list *il = mal_to_identity_list(mal);
1225 free_identity_list(msg->to);
1230 case MAILIMF_FIELD_CC:
1232 struct mailimf_address_list *mal =
1233 _field->fld_data.fld_cc->cc_addr_list;
1234 identity_list *il = mal_to_identity_list(mal);
1238 free_identity_list(msg->cc);
1243 case MAILIMF_FIELD_BCC:
1245 struct mailimf_address_list *mal =
1246 _field->fld_data.fld_bcc->bcc_addr_list;
1247 identity_list *il = mal_to_identity_list(mal);
1251 free_identity_list(msg->bcc);
1256 case MAILIMF_FIELD_REPLY_TO:
1258 struct mailimf_address_list *mal =
1259 _field->fld_data.fld_reply_to->rt_addr_list;
1260 identity_list *il = mal_to_identity_list(mal);
1264 free_identity_list(msg->reply_to);
1269 case MAILIMF_FIELD_IN_REPLY_TO:
1271 clist *list = _field->fld_data.fld_in_reply_to->mid_list;
1272 stringlist_t *sl = clist_to_stringlist(list);
1276 free_stringlist(msg->in_reply_to);
1277 msg->in_reply_to = sl;
1281 case MAILIMF_FIELD_REFERENCES:
1283 clist *list = _field->fld_data.fld_references->mid_list;
1284 stringlist_t *sl = clist_to_stringlist(list);
1288 free_stringlist(msg->references);
1289 msg->references = sl;
1293 case MAILIMF_FIELD_KEYWORDS:
1295 clist *list = _field->fld_data.fld_keywords->kw_list;
1296 stringlist_t *sl = clist_to_stringlist(list);
1300 free_stringlist(msg->keywords);
1305 case MAILIMF_FIELD_COMMENTS:
1307 char * text = _field->fld_data.fld_comments->cm_value;
1309 free(msg->comments);
1311 r = mailmime_encoded_phrase_parse("utf-8", text,
1312 strlen(text), &index, "utf-8", &msg->comments);
1318 case MAILIMF_FIELD_OPTIONAL_FIELD:
1321 _field->fld_data.fld_optional_field->fld_name;
1323 _field->fld_data.fld_optional_field->fld_value;
1327 r = mailmime_encoded_phrase_parse("utf-8", value,
1328 strlen(value), &index, "utf-8", &_value);
1332 stringpair_t *pair = new_stringpair(name, _value);
1336 opt = stringpair_list_add(opt, pair);
1341 if (msg->opt_fields == NULL)
1342 msg->opt_fields = opt;
1348 return PEP_STATUS_OK;
1351 status = PEP_OUT_OF_MEMORY;
1357 static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
1365 char *charset = NULL;
1374 if (part->mm_body == NULL)
1375 return PEP_ILLEGAL_VALUE;
1377 text = part->mm_body-> dt_data.dt_text.dt_data;
1379 return PEP_ILLEGAL_VALUE;
1381 length = part->mm_body->dt_data.dt_text.dt_length;
1383 if (part->mm_body->dt_encoded) {
1384 int code = part->mm_body->dt_encoding;
1386 int r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
1388 case MAILIMF_NO_ERROR:
1390 case MAILIMF_ERROR_MEMORY:
1391 return PEP_OUT_OF_MEMORY;
1393 return PEP_ILLEGAL_VALUE;
1398 _longmsg = strndup(text, length);
1399 if (_longmsg == NULL)
1400 return PEP_OUT_OF_MEMORY;
1403 if (part->mm_content_type) {
1404 if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
1405 if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
1407 int r = charconv("utf-8", charset, _longmsg, _size, &_text);
1409 case MAILIMF_NO_ERROR:
1411 case MAILIMF_ERROR_MEMORY:
1412 return PEP_OUT_OF_MEMORY;
1414 return PEP_ILLEGAL_VALUE;
1421 // FIXME: KG - we now have the text we want.
1422 // Now we need to strip sigs and process them if they are there..
1425 *longmsg = _longmsg;
1429 return PEP_STATUS_OK;
1432 // THIS IS A BEST-EFFORT ONLY FUNCTION, AND WE ARE NOT DOING MORE THAN THE
1434 static PEP_STATUS interpret_protected_headers(
1435 struct mailmime* mime,
1439 // N.B. this is *very much* enigmail output specific, and right now,
1440 // we only care about subject replacement.
1441 const char* header_string = "Content-Type: text/rfc822-headers; protected-headers=\"v1\"\nContent-Disposition: inline\n\n";
1442 size_t content_length = mime->mm_length;
1443 size_t header_strlen = strlen(header_string);
1444 if (header_strlen < content_length) {
1445 const char* headerblock = mime->mm_mime_start;
1446 size_t subject_len = 0;
1447 headerblock = strstr(headerblock, header_string);
1449 const char* subj_start = "Subject: ";
1450 headerblock = strstr(headerblock, subj_start);
1452 size_t subj_len = strlen(subj_start);
1453 headerblock += subj_len;
1454 char* end_pt = strstr(headerblock, "\n");
1456 if (end_pt != mime->mm_mime_start && *(end_pt - 1) == '\r')
1458 subject_len = end_pt - headerblock;
1459 char* new_subj = (char*)calloc(subject_len + 1, 1);
1461 strlcpy(new_subj, headerblock, subject_len + 1);
1462 free(msg->shortmsg);
1463 msg->shortmsg = new_subj;
1465 } // if there's no endpoint, there's something wrong here so we ignore all
1466 // This is best effort.
1470 return PEP_STATUS_OK;
1473 static PEP_STATUS interpret_MIME(
1474 struct mailmime *mime,
1478 PEP_STATUS status = PEP_STATUS_OK;
1483 struct mailmime_content *content = mime->mm_content_type;
1485 if (_is_multipart(content, "alternative")) {
1486 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
1487 if (partlist == NULL)
1488 return PEP_ILLEGAL_VALUE;
1491 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
1492 struct mailmime *part = clist_content(cur);
1494 return PEP_ILLEGAL_VALUE;
1496 content = part->mm_content_type;
1498 if (content == NULL)
1499 return PEP_ILLEGAL_VALUE;
1501 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
1502 status = interpret_body(part, &msg->longmsg, NULL);
1506 else if (_is_text_part(content, "rfc822-headers")) {
1507 status = interpret_protected_headers(part, msg);
1511 else if (_is_text_part(content, "html") &&
1512 msg->longmsg_formatted == NULL) {
1513 status = interpret_body(part, &msg->longmsg_formatted,
1518 else /* add as attachment */ {
1519 status = interpret_MIME(part, msg);
1525 else if (_is_multipart(content, "encrypted")) {
1526 if (msg->longmsg == NULL)
1527 msg->longmsg = strdup("");
1528 assert(msg->longmsg);
1530 return PEP_OUT_OF_MEMORY;
1532 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
1533 if (partlist == NULL)
1534 return PEP_ILLEGAL_VALUE;
1537 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
1538 struct mailmime *part= clist_content(cur);
1540 return PEP_ILLEGAL_VALUE;
1542 status = interpret_MIME(part, msg);
1543 if (status != PEP_STATUS_OK)
1547 else if (_is_multipart(content, NULL)) {
1548 clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
1549 if (partlist == NULL)
1550 return PEP_ILLEGAL_VALUE;
1553 for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
1554 struct mailmime *part= clist_content(cur);
1556 return PEP_ILLEGAL_VALUE;
1557 status = interpret_MIME(part, msg);
1558 if (status != PEP_STATUS_OK)
1563 if (_is_text_part(content, "html") &&
1564 msg->longmsg_formatted == NULL) {
1565 status = interpret_body(mime, &msg->longmsg_formatted,
1570 else if (_is_text_part(content, "rfc822-headers")) {
1571 status = interpret_protected_headers(mime, msg);
1575 else if (_is_text_part(content, NULL) && msg->longmsg == NULL) {
1576 status = interpret_body(mime, &msg->longmsg, NULL);
1588 r = _get_content_type(content, &mime_type, &charset);
1593 return PEP_ILLEGAL_VALUE;
1595 return PEP_OUT_OF_MEMORY;
1597 return PEP_UNKNOWN_ERROR;
1602 status = interpret_body(mime, &data, &size);
1606 pEp_rid_list_t* resource_id_list = _get_resource_id_list(mime);
1607 pEp_rid_list_t* chosen_resource_id = choose_resource_id(resource_id_list);
1609 //filename = _get_filename_or_cid(mime);
1610 char *_filename = NULL;
1612 if (chosen_resource_id) {
1613 filename = chosen_resource_id->rid;
1616 /* The prefix we just added shouldn't be a problem - this is about decoding %XX (RFC 2392) */
1617 /* If it becomes one, we have some MESSY fixing to do. :( */
1618 r = mailmime_encoded_phrase_parse("utf-8", filename,
1619 strlen(filename), &index, "utf-8", &_filename);
1623 char* file_prefix = NULL;
1625 /* in case there are others later */
1626 switch (chosen_resource_id->rid_type) {
1628 file_prefix = "cid";
1630 case PEP_RID_FILENAME:
1631 file_prefix = "file";
1639 filename = build_uri(file_prefix, _filename);
1641 _filename = filename;
1645 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
1646 mime_type, _filename);
1648 free_rid_list(resource_id_list);
1649 resource_id_list = NULL;
1651 return PEP_OUT_OF_MEMORY;
1652 if (msg->attachments == NULL)
1653 msg->attachments = _a;
1658 return PEP_STATUS_OK;
1661 return PEP_OUT_OF_MEMORY;
1664 DYNAMIC_API PEP_STATUS mime_decode_message(
1665 const char *mimetext,
1670 PEP_STATUS status = PEP_STATUS_OK;
1671 struct mailmime * mime = NULL;
1673 message *_msg = NULL;
1679 if (!(mimetext && msg))
1680 return PEP_ILLEGAL_VALUE;
1685 r = mailmime_parse(mimetext, size, &index, &mime);
1689 if (r == MAILIMF_ERROR_MEMORY)
1695 _msg = calloc(1, sizeof(message));
1700 clist * _fieldlist = _get_fields(mime);
1702 status = read_fields(_msg, _fieldlist);
1703 if (status != PEP_STATUS_OK)
1707 struct mailmime_content *content = _get_content(mime);
1710 status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
1712 if (status != PEP_STATUS_OK)
1716 mailmime_free(mime);
1722 status = PEP_ILLEGAL_VALUE;
1726 status = PEP_OUT_OF_MEMORY;
1732 mailmime_free(mime);