src/mime.c
author Krista Bennett <krista@pep-project.org>
Fri, 13 Apr 2018 14:46:44 +0200
branchENGINE-420
changeset 2597 d8a4f5d437ae
parent 2581 752b9b14e0bc
child 2598 eaf109aa1e6c
permissions -rw-r--r--
ENGINE-420: test mods and a mime.c fix for disappearing usernames in mime_encode
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 #include "pEp_internal.h"
     5 #include "mime.h"
     6 
     7 #include <string.h>
     8 #include <stdlib.h>
     9 #include <assert.h>
    10 #include <errno.h>
    11 
    12 #include "resource_id.h"
    13 #include "etpan_mime.h"
    14 #include "wrappers.h"
    15 
    16 static bool is_whitespace(char c)
    17 {
    18     switch (c) {
    19         case ' ':
    20         case '\t':
    21         case '\r':
    22         case '\n':
    23             return true;
    24 
    25         default:
    26             return false;
    27     }
    28 }
    29 
    30 DYNAMIC_API bool is_PGP_message_text(const char *text)
    31 {
    32     if (text == NULL)
    33         return false;
    34 
    35     for (; *text && is_whitespace(*text); text++);
    36 
    37     return strncmp(text, "-----BEGIN PGP MESSAGE-----", 27) == 0;
    38 }
    39 
    40 #define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
    41 #ifdef _WIN32
    42 #define PATH_SEP '\\'
    43 #else
    44 #define PATH_SEP '/'
    45 #endif
    46 
    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.
    50 
    51 static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
    52 {
    53     PEP_STATUS status = PEP_STATUS_OK;
    54     int col;
    55     int r;
    56 	size_t len;
    57 	char* buf = NULL;
    58 
    59 	MMAPString* buffer;
    60 
    61 	buffer = mmap_string_new(NULL);
    62 	if (buffer == NULL)
    63 		goto enomem;
    64 	
    65 	col = 0;
    66 	r = mailmime_write_mem(buffer, &col, mime);
    67 	assert(r == MAILIMF_NO_ERROR);
    68 	if (r == MAILIMF_ERROR_MEMORY)
    69 		goto enomem;
    70 	else if (r != MAILIMF_NO_ERROR)
    71 		goto err_file;
    72 
    73 	// we overallocate by 1 byte, so we have a terminating 0.
    74 	len = buffer->len;
    75 	buf = calloc(len + 1, 1);
    76 	if (buf == NULL)
    77 		goto enomem;
    78 
    79 	memcpy(buf, buffer->str, len);
    80 	mmap_string_free(buffer);
    81 
    82     *mimetext = buf;
    83     return PEP_STATUS_OK;
    84 
    85 err_file:
    86     status = PEP_CANNOT_CREATE_TEMP_FILE;
    87     goto pep_error;
    88 
    89 enomem:
    90     status = PEP_OUT_OF_MEMORY;
    91 
    92 pep_error:
    93 	if (buffer)
    94 		mmap_string_free(buffer);
    95 	if (buf)
    96 		free(buf);
    97     return status;
    98 }
    99 
   100 static bool known_ascii_type(const char* mime_type) {
   101     const char* text_types[] = {"application/pgp-keys",
   102                                 "application/pgp-encrypted"};
   103     const int TEXT_TYPE_ARRAY_SIZE = sizeof(text_types)/sizeof(text_types[0]);
   104     
   105     int i;
   106     
   107     for (i = 0; i < TEXT_TYPE_ARRAY_SIZE; i++) {
   108         if (strcmp(text_types[i], mime_type) == 0)
   109             return true;
   110     }
   111     return false;
   112 }
   113 
   114 
   115 static PEP_STATUS mime_attachment(
   116         bloblist_t *blob,
   117         struct mailmime **result,
   118         bool transport_encode
   119     )
   120 {
   121     PEP_STATUS status = PEP_STATUS_OK;
   122     struct mailmime * mime = NULL;
   123     char * mime_type;
   124     assert(blob);
   125     assert(result);
   126 
   127     *result = NULL;
   128 
   129 // TODO: It seems the pep com server adapter sends an empty string here,
   130 // which leads to a crash later. Thus, we workaround here by treating an
   131 // empty string as NULL. We need to check whether the bug really is here,
   132 // or the pep com server adapter needs to be changed.
   133     if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
   134         mime_type = "application/octet-stream";
   135     else
   136         mime_type = blob->mime_type;
   137 
   138     pEp_rid_list_t* resource = parse_uri(blob->filename);
   139 //    bool already_ascii = known_ascii_type(mime_type);
   140 
   141     bool already_ascii = !(must_chunk_be_encoded(blob->value, blob->size, true));
   142 
   143     mime = get_file_part(resource, mime_type, blob->value, blob->size, 
   144                           (already_ascii ? false : transport_encode));
   145     free_rid_list(resource);
   146     
   147     assert(mime);
   148     if (mime == NULL)
   149         goto enomem;
   150 
   151     *result = mime;
   152     return PEP_STATUS_OK;
   153 
   154 enomem:
   155     status = PEP_OUT_OF_MEMORY;
   156 
   157     if (mime)
   158         mailmime_free(mime);
   159 
   160     return status;
   161 }
   162 
   163 static PEP_STATUS mime_html_text(
   164         const char *plaintext,
   165         const char *htmltext,
   166         bloblist_t *attachments,
   167         struct mailmime **result,
   168         bool transport_encode
   169     )
   170 {
   171     PEP_STATUS status = PEP_STATUS_OK;
   172     struct mailmime * top_level_html_mime = NULL;
   173     struct mailmime * mime = NULL;
   174     struct mailmime * submime = NULL;
   175     int r;
   176 
   177     assert(plaintext);
   178     assert(htmltext);
   179     assert(result);
   180 
   181     *result = NULL;
   182 
   183     mime = part_multiple_new("multipart/alternative");
   184     assert(mime);
   185     if (mime == NULL)
   186         goto enomem;
   187 
   188     pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
   189     
   190     int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
   191     submime = get_text_part(NULL, "text/plain", plaintext, strlen(plaintext),
   192             encoding_type);
   193     free_rid_list(resource);
   194     resource = NULL;
   195     
   196     assert(submime);
   197     if (submime == NULL)
   198         goto enomem;
   199 
   200     r = mailmime_smart_add_part(mime, submime);
   201     assert(r == MAILIMF_NO_ERROR);
   202     if (r == MAILIMF_ERROR_MEMORY) {
   203         goto enomem;
   204     }
   205     else {
   206         // mailmime_smart_add_part() takes ownership of submime
   207         submime = NULL;
   208     }
   209 
   210     bool inlined_attachments = false;
   211     
   212     bloblist_t* traversal_ptr = attachments;
   213     
   214     while (traversal_ptr) {
   215         if (traversal_ptr->disposition == PEP_CONTENT_DISP_INLINE) {
   216             inlined_attachments = true;
   217             break;
   218         }
   219         traversal_ptr = traversal_ptr->next;
   220     }
   221 
   222     if (inlined_attachments) {
   223         /* Noooooo... dirk, why do you do this to me? */
   224         submime = part_multiple_new("multipart/related");
   225         assert(submime);
   226         if (submime == NULL)
   227             goto enomem;
   228 
   229         top_level_html_mime = submime;
   230         
   231         r = mailmime_smart_add_part(mime, top_level_html_mime);
   232         assert(r == MAILIMF_NO_ERROR);
   233         if (r == MAILIMF_ERROR_MEMORY) {
   234             goto enomem;
   235         }
   236         else {
   237             // mailmime_smart_add_part() takes ownership of submime
   238             submime = NULL;
   239         }
   240     }
   241     else {
   242         top_level_html_mime = mime;
   243     }
   244 
   245 //    resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
   246     submime = get_text_part(NULL, "text/html", htmltext, strlen(htmltext),
   247             encoding_type);
   248     free_rid_list(resource);
   249     resource = NULL;
   250     
   251     assert(submime);
   252     if (submime == NULL)
   253         goto enomem;
   254 
   255     r = mailmime_smart_add_part(top_level_html_mime, submime);
   256     assert(r == MAILIMF_NO_ERROR);
   257     if (r == MAILIMF_ERROR_MEMORY)
   258         goto enomem;
   259     else {
   260         // mailmime_smart_add_part() takes ownership of submime
   261         submime = NULL;
   262     }
   263 
   264     bloblist_t *_a;
   265     for (_a = attachments; _a != NULL; _a = _a->next) {
   266         if (_a->disposition != PEP_CONTENT_DISP_INLINE)
   267             continue;
   268         status = mime_attachment(_a, &submime, transport_encode);
   269         if (status != PEP_STATUS_OK)
   270             return PEP_UNKNOWN_ERROR; // FIXME
   271 
   272         r = mailmime_smart_add_part(top_level_html_mime, submime);
   273         assert(r == MAILIMF_NO_ERROR);
   274         if (r == MAILIMF_ERROR_MEMORY) {
   275             goto enomem;
   276         }
   277         else {
   278             // mailmime_smart_add_part() takes ownership of submime
   279             submime = NULL;
   280         }
   281     }
   282 
   283     *result = mime;
   284     return PEP_STATUS_OK;
   285 
   286 enomem:
   287     status = PEP_OUT_OF_MEMORY;
   288 
   289     if (mime)
   290         mailmime_free(mime);
   291 
   292     if (submime)
   293         mailmime_free(submime);
   294 
   295     return status;
   296 }
   297 
   298 
   299 // FIXME: maybe need to add transport_encode field here
   300 static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
   301 {
   302     char *_username = NULL;
   303     struct mailimf_mailbox *mb;
   304 
   305     _username = (ident->username && must_field_value_be_encoded(ident->username))
   306                   ? mailmime_encode_subject_header("utf-8", ident->username, 0) 
   307                   : strdup(ident->username);
   308                   
   309     assert(_username);
   310     if (_username == NULL)
   311         goto enomem;
   312 
   313     mb = mailbox_from_string(_username, ident->address);
   314     if (mb == NULL)
   315         goto enomem;
   316 
   317     free(_username);
   318     _username = NULL;
   319 
   320     return mb;
   321 
   322 enomem:
   323     free(_username);
   324     return NULL;
   325 }
   326 
   327 static struct mailimf_mailbox_list * identity_to_mbl(
   328         const pEp_identity *ident)
   329 {
   330     struct mailimf_mailbox_list *mbl = NULL;
   331     struct mailimf_mailbox *mb = NULL;
   332     clist *list = NULL;
   333     int r;
   334 
   335     assert(ident);
   336 
   337     list = clist_new();
   338     if (list == NULL)
   339         goto enomem;
   340 
   341     mb = identity_to_mailbox(ident);
   342     if (mb == NULL)
   343         goto enomem;
   344 
   345     r = clist_append(list, mb);
   346     if (r)
   347         goto enomem;
   348 
   349     mbl = mailimf_mailbox_list_new(list);
   350     if (mbl == NULL)
   351         goto enomem;
   352 
   353     return mbl;
   354 
   355 enomem:
   356     if (mb)
   357         mailimf_mailbox_free(mb);
   358 
   359     if (list)
   360         clist_free(list);
   361 
   362     return NULL;
   363 }
   364 
   365 static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
   366 {
   367     struct mailimf_address_list *mal = NULL;
   368     struct mailimf_mailbox *mb = NULL;
   369     struct mailimf_address * addr = NULL;
   370     clist *list = NULL;
   371     int r;
   372 
   373     assert(il);
   374 
   375     list = clist_new();
   376     if (list == NULL)
   377         goto enomem;
   378 
   379     identity_list *_il;
   380     for (_il = il; _il && _il->ident; _il = _il->next) {
   381         mb = identity_to_mailbox(_il->ident);
   382         if (mb == NULL)
   383             goto enomem;
   384 
   385         addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
   386         if (addr == NULL)
   387             goto enomem;
   388         mb = NULL;
   389 
   390         r = clist_append(list, addr);
   391         if (r)
   392             goto enomem;
   393         addr = NULL;
   394     }
   395     mal = mailimf_address_list_new(list);
   396     if (mal == NULL)
   397         goto enomem;
   398 
   399     return mal;
   400 
   401 enomem:
   402     if (mb)
   403         mailimf_mailbox_free(mb);
   404 
   405     if (addr)
   406         mailimf_address_free(addr);
   407 
   408     if (list)
   409         clist_free(list);
   410 
   411     return NULL;
   412 }
   413 
   414 static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
   415 {
   416     clist * cl = clist_new();
   417     assert(cl);
   418     if (cl == NULL)
   419         return NULL;
   420 
   421     if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
   422         return cl;
   423         
   424     stringlist_t *_sl;
   425     for (_sl = sl; _sl; _sl = _sl->next) {
   426         int r;
   427         char * value = ((transport_encode && must_field_value_be_encoded(_sl->value)) ?
   428                         mailmime_encode_subject_header("utf-8", _sl->value, 0) :
   429                         strdup(_sl->value));
   430         assert(value);
   431         if (value == NULL) {
   432             clist_free(cl);
   433             return NULL;
   434         }
   435         r = clist_append(cl, value);
   436         assert(r == 0);
   437         if (r) {
   438             free(value);
   439             clist_free(cl);
   440             return NULL;
   441         }
   442     }
   443 
   444     return cl;
   445 }
   446 
   447 static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
   448 {
   449     PEP_STATUS status = PEP_STATUS_OK;
   450     struct mailimf_fields * fields = NULL;
   451     int r;
   452     clist * fields_list = NULL;
   453     unsigned char pepstr[] = PEP_SUBJ_STRING; // unsigned due to UTF-8 byte fun
   454 #ifdef WIN32
   455     char* altstr = "pEp";
   456 #else
   457     char* altstr = (char*)pepstr;
   458 #endif        
   459     char *subject = msg->shortmsg ? msg->shortmsg : altstr;
   460 
   461     assert(msg);
   462     assert(msg->from);
   463     assert(msg->from->address);
   464     assert(result);
   465 
   466     *result = NULL;
   467 
   468     fields_list = clist_new();
   469     assert(fields_list);
   470     if (fields_list == NULL)
   471         goto enomem;
   472 
   473     if (msg->id) {
   474         char *_msgid = strdup(msg->id);
   475         assert(_msgid);
   476         if (_msgid == NULL)
   477             goto enomem;
   478 
   479         r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
   480                 (_new_func_t) mailimf_message_id_new, _msgid);
   481         if (r) {
   482             free(_msgid);
   483             goto enomem;
   484         }
   485     }
   486 
   487     if (msg->sent) {
   488         struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
   489         if (dt == NULL)
   490             goto enomem;
   491 
   492         r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
   493                 (_new_func_t) mailimf_orig_date_new, dt);
   494         if (r) {
   495             mailimf_date_time_free(dt);
   496             goto enomem;
   497         }
   498         dt = NULL;
   499     }
   500 
   501     /* if (msg->from) */ {
   502         struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
   503         if (from == NULL)
   504             goto enomem;
   505 
   506         r = _append_field(fields_list, MAILIMF_FIELD_FROM,
   507                 (_new_func_t) mailimf_from_new, from);
   508         if (r) {
   509             mailimf_mailbox_list_free(from);
   510             goto enomem;
   511         }
   512     }
   513 
   514     if (msg->to) {
   515         struct mailimf_address_list *to = identity_list_to_mal(msg->to);
   516         if (to == NULL)
   517             goto enomem;
   518 
   519         r = _append_field(fields_list, MAILIMF_FIELD_TO,
   520                 (_new_func_t) mailimf_to_new, to);
   521         if (r) {
   522             mailimf_address_list_free(to);
   523             goto enomem;
   524         }
   525     }
   526 
   527     char* _subject = NULL;
   528     if (!must_field_value_be_encoded(subject)) {
   529         _subject = strdup(subject);
   530         assert(_subject);
   531     }
   532     else {
   533         _subject = mailmime_encode_subject_header("utf-8", subject, 1);
   534     }
   535     if (_subject == NULL)
   536         goto enomem;
   537 
   538     r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
   539             (_new_func_t) mailimf_subject_new, _subject);
   540     if (r) {
   541         free(_subject);
   542         goto enomem;
   543     }
   544 
   545     if (msg->cc) {
   546         struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
   547         if (cc == NULL)
   548             goto enomem;
   549 
   550         r = _append_field(fields_list, MAILIMF_FIELD_CC,
   551                 (_new_func_t) mailimf_cc_new, cc);
   552         if (r) {
   553             mailimf_address_list_free(cc);
   554             goto enomem;
   555         }
   556     }
   557     
   558     if (msg->bcc) {
   559         struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
   560         if (bcc == NULL)
   561             goto enomem;
   562 
   563         r = _append_field(fields_list, MAILIMF_FIELD_BCC,
   564                 (_new_func_t) mailimf_bcc_new, bcc);
   565         if (r) {
   566             mailimf_address_list_free(bcc);
   567             goto enomem;
   568         }
   569     }
   570     
   571     if (msg->reply_to) {
   572         struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
   573         if (reply_to == NULL)
   574             goto enomem;
   575 
   576         r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
   577                 (_new_func_t) mailimf_reply_to_new, reply_to);
   578         if (r) {
   579             mailimf_address_list_free(reply_to);
   580             goto enomem;
   581         }
   582     }
   583 
   584     if (msg->in_reply_to) {
   585         clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
   586         if (in_reply_to == NULL)
   587             goto enomem;
   588 
   589         r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
   590                 (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
   591         if (r) {
   592             clist_free(in_reply_to);
   593             goto enomem;
   594         }
   595     }
   596 
   597     if (msg->references) {
   598         clist *references = stringlist_to_clist(msg->references, true);
   599         if (references == NULL)
   600             goto enomem;
   601 
   602         r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
   603                 (_new_func_t) mailimf_references_new, references);
   604         if (r) {
   605             clist_free(references);
   606             goto enomem;
   607         }
   608     }
   609 
   610     if (msg->keywords) {
   611         clist *keywords = stringlist_to_clist(msg->keywords, true);
   612         if (keywords == NULL)
   613             goto enomem;
   614 
   615         r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
   616                 (_new_func_t) mailimf_keywords_new, keywords);
   617         if (r) {
   618             clist_free(keywords);
   619             goto enomem;
   620         }
   621     }
   622 
   623     if (msg->comments) {
   624         char *comments = NULL;
   625         if (!must_field_value_be_encoded(msg->comments)) {
   626             comments = strdup(msg->comments);
   627             assert(comments);
   628         }
   629         else  {
   630             comments = mailmime_encode_subject_header("utf-8", msg->comments, 0);
   631         }
   632         if (comments == NULL)
   633             goto enomem;
   634 
   635         r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
   636                 (_new_func_t) mailimf_comments_new, comments);
   637         if (r) {
   638             free(comments);
   639             goto enomem;
   640         }
   641     }
   642 
   643     if (msg->opt_fields) {
   644         stringpair_list_t *_l;
   645         for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
   646             char *key = _l->value->key;
   647             char *value = _l->value->value;
   648             if (key && value) {
   649                 r = _append_optional_field(fields_list, key, value);
   650 
   651                 if (r)
   652                     goto enomem;
   653             }
   654         }
   655     }
   656 
   657     fields = mailimf_fields_new(fields_list);
   658     assert(fields);
   659     if (fields == NULL)
   660         goto enomem;
   661 
   662     *result = fields;
   663 
   664     return PEP_STATUS_OK;
   665 
   666 enomem:
   667     status = PEP_OUT_OF_MEMORY;
   668 
   669     if (fields_list)
   670         clist_free(fields_list);
   671 
   672     if (fields)
   673         mailimf_fields_free(fields);
   674 
   675     return status;
   676 }
   677 
   678 static bool has_exceptional_extension(char* filename) {
   679     if (!filename)
   680         return false;
   681     int len = strlen(filename);
   682     if (len < 4)
   683         return false;
   684     char* ext_start = filename + (len - 4);
   685     if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
   686         strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
   687         return true;
   688     return false;
   689 }
   690 
   691 static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
   692     pEp_rid_list_t* retval = rid_list;
   693     
   694     /* multiple elements - least common case */
   695     if (rid_list && rid_list->next) {
   696         pEp_rid_list_t* rid_list_curr = rid_list;
   697         retval = rid_list; 
   698         
   699         while (rid_list_curr) {
   700             pEp_resource_id_type rid_type = rid_list_curr->rid_type;
   701             if (rid_type == PEP_RID_CID)
   702                 retval = rid_list_curr;
   703             else if (rid_type == PEP_RID_FILENAME && has_exceptional_extension(rid_list_curr->rid))
   704                 return rid_list_curr;
   705             rid_list_curr = rid_list_curr->next;
   706         }
   707     } 
   708     return retval;
   709 }
   710 
   711 // static void split_inlined_and_attached(bloblist_t** inlined, bloblist_t** attached) {
   712 //     bloblist_t** curr_pp = attached;
   713 //     bloblist_t* curr = *curr_pp;
   714 //     
   715 //     bloblist_t* inline_ret = NULL;
   716 //     bloblist_t** inline_curr_pp = &inline_ret;
   717 //     
   718 //     bloblist_t* att_ret = NULL;
   719 //     bloblist_t** att_curr_pp = &att_ret;
   720 //     
   721 //     while (curr) {
   722 //         if (curr->disposition == PEP_CONTENT_DISP_INLINE) {
   723 //             *inline_curr_pp = curr;
   724 //             inline_curr_pp = &(curr->next);
   725 //         }
   726 //         else {
   727 //             *att_curr_pp = curr;
   728 //             att_curr_pp = &(curr->next);            
   729 //         }
   730 //         *curr_pp = curr->next;
   731 //         curr->next = NULL;
   732 //         curr = *curr_pp;
   733 //     }
   734 //     
   735 //     *inlined = inline_ret;
   736 //     *attached = att_ret;
   737 // }
   738 
   739 
   740 static PEP_STATUS mime_encode_message_plain(
   741         const message *msg,
   742         bool omit_fields,
   743         struct mailmime **result,
   744         bool transport_encode
   745     )
   746 {
   747     struct mailmime * mime = NULL;
   748     struct mailmime * submime = NULL;
   749     int r;
   750     PEP_STATUS status;
   751     //char *subject;
   752     char *plaintext;
   753     char *htmltext;
   754 
   755     assert(msg);
   756     assert(result);
   757     
   758     //subject = (msg->shortmsg) ? msg->shortmsg : "pEp";  // not used, yet.
   759     plaintext = (msg->longmsg) ? msg->longmsg : "";
   760     htmltext = msg->longmsg_formatted;
   761 
   762     if (htmltext && (htmltext[0] != '\0')) {
   763         /* first, we need to strip out the inlined attachments to ensure this
   764            gets set up correctly */
   765            
   766         status = mime_html_text(plaintext, htmltext, msg->attachments, &mime,
   767                                 transport_encode);
   768                 
   769         if (status != PEP_STATUS_OK)
   770             goto pep_error;
   771     }
   772     else {
   773         pEp_rid_list_t* resource = NULL;
   774         if (is_PGP_message_text(plaintext)) {
   775             resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
   776             int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
   777             mime = get_text_part(resource, "application/octet-stream", plaintext,
   778                     strlen(plaintext), encoding_type);
   779         }
   780         else {
   781             resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
   782             int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
   783             mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
   784                     encoding_type);
   785         }
   786         free_rid_list(resource);
   787         
   788         assert(mime);
   789         if (mime == NULL)
   790             goto enomem;
   791     }
   792 
   793     bool normal_attachments = false;
   794     
   795     bloblist_t* traversal_ptr = msg->attachments;
   796     
   797     while (traversal_ptr) {
   798         if (traversal_ptr->disposition != PEP_CONTENT_DISP_INLINE) {
   799             normal_attachments = true;
   800             break;
   801         }
   802         traversal_ptr = traversal_ptr->next;
   803     }
   804 
   805     if (normal_attachments) {
   806         submime = mime;
   807         mime = part_multiple_new("multipart/mixed");
   808         assert(mime);
   809         if (mime == NULL)
   810             goto enomem;
   811 
   812         r = mailmime_smart_add_part(mime, submime);
   813         assert(r == MAILIMF_NO_ERROR);
   814         if (r == MAILIMF_ERROR_MEMORY) {
   815             goto enomem;
   816         }
   817         else {
   818             // mailmime_smart_add_part() takes ownership of submime
   819             submime = NULL;
   820         }
   821 
   822         bloblist_t *_a;
   823         for (_a = msg->attachments; _a != NULL; _a = _a->next) {
   824 
   825             if (_a->disposition == PEP_CONTENT_DISP_INLINE)
   826                 continue;
   827 
   828             status = mime_attachment(_a, &submime, transport_encode);
   829             if (status != PEP_STATUS_OK)
   830                 goto pep_error;
   831 
   832             r = mailmime_smart_add_part(mime, submime);
   833             assert(r == MAILIMF_NO_ERROR);
   834             if (r == MAILIMF_ERROR_MEMORY) {
   835                 goto enomem;
   836             }
   837             else {
   838                 // mailmime_smart_add_part() takes ownership of submime
   839                 submime = NULL;
   840             }
   841         }
   842     }
   843 
   844     *result = mime;
   845     return PEP_STATUS_OK;
   846 
   847 enomem:
   848     status = PEP_OUT_OF_MEMORY;
   849 
   850 pep_error:
   851     if (mime)
   852         mailmime_free(mime);
   853 
   854     if (submime)
   855         mailmime_free(submime);
   856 
   857     return status;
   858 }
   859 
   860 static PEP_STATUS mime_encode_message_PGP_MIME(
   861         const message * msg,
   862         bool omit_fields,
   863         struct mailmime **result
   864     )
   865 {
   866     struct mailmime * mime = NULL;
   867     struct mailmime * submime = NULL;
   868 	struct mailmime_parameter * param;
   869     int r;
   870     PEP_STATUS status;
   871     char *plaintext;
   872     size_t plaintext_size;
   873 
   874     assert(msg->attachments && msg->attachments->next &&
   875             msg->attachments->next->value);
   876 
   877     plaintext = msg->attachments->next->value;
   878     plaintext_size = msg->attachments->next->size;
   879 
   880     mime = part_multiple_new("multipart/encrypted");
   881     assert(mime);
   882     if (mime == NULL)
   883         goto enomem;
   884 
   885     param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
   886     clist_append(mime->mm_content_type->ct_parameters, param);
   887 
   888     submime = get_pgp_encrypted_part();
   889     assert(submime);
   890     if (submime == NULL)
   891         goto enomem;
   892 
   893     r = mailmime_smart_add_part(mime, submime);
   894     assert(r == MAILIMF_NO_ERROR);
   895     if (r == MAILIMF_ERROR_MEMORY) {
   896         goto enomem;
   897     }
   898     else {
   899         // mailmime_smart_add_part() takes ownership of submime
   900         submime = NULL;
   901     }
   902 
   903     pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
   904     submime = get_text_part(resource, "application/octet-stream", plaintext,
   905             plaintext_size, MAILMIME_MECHANISM_7BIT);
   906             
   907     free_rid_list(resource);
   908     
   909     assert(submime);
   910     if (submime == NULL)
   911         goto enomem;
   912 
   913     r = mailmime_smart_add_part(mime, submime);
   914     assert(r == MAILIMF_NO_ERROR);
   915     if (r == MAILIMF_ERROR_MEMORY) {
   916         goto enomem;
   917     }
   918     else {
   919         // mailmime_smart_add_part() takes ownership of submime
   920         submime = NULL;
   921     }
   922 
   923     *result = mime;
   924     return PEP_STATUS_OK;
   925 
   926 enomem:
   927     status = PEP_OUT_OF_MEMORY;
   928 
   929     if (mime)
   930         mailmime_free(mime);
   931 
   932     if (submime)
   933         mailmime_free(submime);
   934 
   935     return status;
   936 }
   937 
   938 DYNAMIC_API PEP_STATUS mime_encode_message(
   939         const message * msg,
   940         bool omit_fields,
   941         char **mimetext
   942     )
   943 {
   944     return _mime_encode_message_internal(msg, omit_fields, mimetext, true);
   945 }
   946 
   947 PEP_STATUS _mime_encode_message_internal(
   948         const message * msg,
   949         bool omit_fields,
   950         char **mimetext,
   951         bool transport_encode
   952     )
   953 {
   954     PEP_STATUS status = PEP_STATUS_OK;
   955     struct mailmime * msg_mime = NULL;
   956     struct mailmime * mime = NULL;
   957     struct mailimf_fields * fields = NULL;
   958     char *buf = NULL;
   959     int r;
   960 
   961     assert(msg);
   962     assert(mimetext);
   963 
   964     if (!(msg && mimetext))
   965         return PEP_ILLEGAL_VALUE;
   966 
   967     *mimetext = NULL;
   968 
   969     switch (msg->enc_format) {
   970         case PEP_enc_none:
   971             status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode);
   972             break;
   973 
   974         case PEP_enc_pieces:
   975             status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode);
   976             break;
   977 
   978         case PEP_enc_S_MIME:
   979             NOT_IMPLEMENTED
   980                 
   981         case PEP_enc_PGP_MIME:
   982             status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
   983             break;
   984 
   985         case PEP_enc_PEP:
   986             NOT_IMPLEMENTED
   987 
   988         default:
   989             NOT_IMPLEMENTED
   990     }
   991 
   992     if (status != PEP_STATUS_OK)
   993         goto pep_error;
   994 
   995     msg_mime = mailmime_new_message_data(NULL);
   996     assert(msg_mime);
   997     if (msg_mime == NULL)
   998         goto enomem;
   999 
  1000     r = mailmime_add_part(msg_mime, mime);
  1001     if (r) {
  1002         mailmime_free(mime);
  1003         goto enomem;
  1004     }
  1005     mime = NULL;
  1006 
  1007     if (!omit_fields) {
  1008         status = build_fields(msg, &fields);
  1009         if (status != PEP_STATUS_OK)
  1010             goto pep_error;
  1011 
  1012         mailmime_set_imf_fields(msg_mime, fields);
  1013     }
  1014 
  1015     status = render_mime(msg_mime, &buf);
  1016     if (status != PEP_STATUS_OK)
  1017         goto pep_error;
  1018 
  1019     mailmime_free(msg_mime);
  1020     *mimetext = buf;
  1021 
  1022     return PEP_STATUS_OK;
  1023 
  1024 enomem:
  1025     status = PEP_OUT_OF_MEMORY;
  1026 
  1027 pep_error:
  1028     if (msg_mime)
  1029         mailmime_free(msg_mime);
  1030     else
  1031         if (mime)
  1032             mailmime_free(mime);
  1033 
  1034     return status;
  1035 }
  1036 
  1037 static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
  1038 {
  1039     char *username = NULL;
  1040 
  1041     assert(mb);
  1042     assert(mb->mb_addr_spec);
  1043 
  1044     if (mb->mb_addr_spec == NULL)
  1045         return NULL;
  1046 
  1047     if (mb->mb_display_name) {
  1048         size_t index = 0;
  1049         const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
  1050                 strlen(mb->mb_display_name), &index, "utf-8", &username);
  1051         if (r)
  1052             goto enomem;
  1053     }
  1054 
  1055     pEp_identity *ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
  1056     if (ident == NULL)
  1057         goto enomem;
  1058     free(username);
  1059 
  1060     return ident;
  1061 
  1062 enomem:
  1063     free(username);
  1064     return NULL;
  1065 }
  1066 
  1067 static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
  1068 {
  1069     struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
  1070     return mailbox_to_identity(mb);
  1071 }
  1072 
  1073 static identity_list * mal_to_identity_list(
  1074         const struct mailimf_address_list *mal
  1075     )
  1076 {
  1077     assert(mal);
  1078     clist *list = mal->ad_list;
  1079 
  1080     identity_list *il = new_identity_list(NULL);
  1081     if (il == NULL)
  1082         goto enomem;
  1083 
  1084     identity_list *_il = il;
  1085     for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
  1086         pEp_identity *ident;
  1087 
  1088         struct mailimf_address *addr = clist_content(cur);
  1089         switch(addr->ad_type) {
  1090             case MAILIMF_ADDRESS_MAILBOX:
  1091                 ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
  1092                 if (ident == NULL)
  1093                     goto enomem;
  1094                 _il = identity_list_add(_il, ident);
  1095                 if (_il == NULL)
  1096                     goto enomem;
  1097                 break;
  1098 
  1099             case MAILIMF_ADDRESS_GROUP:
  1100                 {
  1101                     struct mailimf_mailbox_list * mbl =
  1102                             addr->ad_data.ad_group->grp_mb_list;
  1103                     for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
  1104                             cur2 = clist_next(cur2)) {
  1105                         ident = mailbox_to_identity(clist_content(cur));
  1106                         if (ident == NULL)
  1107                             goto enomem;
  1108                         _il = identity_list_add(_il, ident);
  1109                         if (_il == NULL)
  1110                             goto enomem;
  1111                     }
  1112                 }
  1113                 break;
  1114 
  1115             default:
  1116                 assert(0);
  1117                 goto enomem;
  1118         }
  1119     }
  1120 
  1121     return il;
  1122 
  1123 enomem:
  1124     free_identity_list(il);
  1125     return NULL;
  1126 }
  1127 
  1128 static stringlist_t * clist_to_stringlist(const clist *list)
  1129 {
  1130     char *text = NULL;;
  1131     stringlist_t * sl = new_stringlist(NULL);
  1132     if (sl == NULL)
  1133         return NULL;
  1134 
  1135     stringlist_t *_sl = sl;
  1136     for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
  1137         char *phrase = clist_content(cur);
  1138         size_t index = 0;
  1139         
  1140         const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
  1141                 &index, "utf-8", &text);
  1142         if (r)
  1143             goto enomem;
  1144 
  1145         _sl = stringlist_add(_sl, text);
  1146         if (_sl == NULL)
  1147             goto enomem;
  1148 
  1149         free(text);
  1150         text = NULL;
  1151     }
  1152 
  1153     return sl;
  1154 
  1155 enomem:
  1156     free_stringlist(sl);
  1157     free(text);
  1158 
  1159     return NULL;
  1160 }
  1161 
  1162 static PEP_STATUS read_fields(message *msg, clist *fieldlist)
  1163 {
  1164     PEP_STATUS status = PEP_STATUS_OK;
  1165     struct mailimf_field * _field;
  1166     clistiter *cur;
  1167     size_t index;
  1168     int r;
  1169     stringpair_list_t *opt = msg->opt_fields;
  1170 
  1171     for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
  1172         _field = clist_content(cur);
  1173 
  1174         switch (_field->fld_type) {
  1175             case MAILIMF_FIELD_MESSAGE_ID:
  1176                 {
  1177                     char * text = _field->fld_data.fld_message_id->mid_value;
  1178 
  1179                     free(msg->id);
  1180                     index = 0;
  1181                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1182                             strlen(text), &index, "utf-8", &msg->id);
  1183                     if (r)
  1184                         goto enomem;
  1185                 }
  1186                 break;
  1187 
  1188             case MAILIMF_FIELD_SUBJECT:
  1189                 {
  1190                     char * text = _field->fld_data.fld_subject->sbj_value;
  1191 
  1192                     free(msg->shortmsg);
  1193                     index = 0;
  1194                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1195                             strlen(text), &index, "utf-8", &msg->shortmsg);
  1196                     if (r)
  1197                         goto enomem;
  1198                 }
  1199                 break;
  1200 
  1201             case MAILIMF_FIELD_ORIG_DATE:
  1202                 {
  1203                     struct mailimf_date_time *date =
  1204                         _field->fld_data.fld_orig_date->dt_date_time;
  1205 
  1206                     free_timestamp(msg->sent);
  1207                     msg->sent = etpantime_to_timestamp(date);
  1208                     if (msg->sent == NULL)
  1209                         goto enomem;
  1210                 }
  1211                 break;
  1212 
  1213             case MAILIMF_FIELD_FROM:
  1214                 {
  1215                     struct mailimf_mailbox_list *mbl =
  1216                             _field->fld_data.fld_from->frm_mb_list;
  1217                     pEp_identity *ident;
  1218 
  1219                     ident = mbl_to_identity(mbl);
  1220                     if (ident == NULL)
  1221                         goto pep_error;
  1222 
  1223                     free_identity(msg->from);
  1224                     msg->from = ident;
  1225                 }
  1226                 break;
  1227 
  1228             case MAILIMF_FIELD_TO:
  1229                 {
  1230                     struct mailimf_address_list *mal =
  1231                             _field->fld_data.fld_to->to_addr_list;
  1232                     identity_list *il = mal_to_identity_list(mal);
  1233                     if (il == NULL)
  1234                         goto enomem;
  1235 
  1236                     free_identity_list(msg->to);
  1237                     msg->to = il;
  1238                 }
  1239                 break;
  1240 
  1241             case MAILIMF_FIELD_CC:
  1242                 {
  1243                     struct mailimf_address_list *mal =
  1244                             _field->fld_data.fld_cc->cc_addr_list;
  1245                     identity_list *il = mal_to_identity_list(mal);
  1246                     if (il == NULL)
  1247                         goto enomem;
  1248 
  1249                     free_identity_list(msg->cc);
  1250                     msg->cc = il;
  1251                 }
  1252                 break;
  1253 
  1254             case MAILIMF_FIELD_BCC:
  1255                 {
  1256                     struct mailimf_address_list *mal =
  1257                             _field->fld_data.fld_bcc->bcc_addr_list;
  1258                     identity_list *il = mal_to_identity_list(mal);
  1259                     if (il == NULL)
  1260                         goto enomem;
  1261 
  1262                     free_identity_list(msg->bcc);
  1263                     msg->bcc = il;
  1264                 }
  1265                 break;
  1266 
  1267             case MAILIMF_FIELD_REPLY_TO:
  1268                 {
  1269                     struct mailimf_address_list *mal =
  1270                             _field->fld_data.fld_reply_to->rt_addr_list;
  1271                     identity_list *il = mal_to_identity_list(mal);
  1272                     if (il == NULL)
  1273                         goto enomem;
  1274 
  1275                     free_identity_list(msg->reply_to);
  1276                     msg->reply_to = il;
  1277                 }
  1278                 break;
  1279 
  1280             case MAILIMF_FIELD_IN_REPLY_TO:
  1281                 {
  1282                     clist *list = _field->fld_data.fld_in_reply_to->mid_list;
  1283                     stringlist_t *sl = clist_to_stringlist(list);
  1284                     if (sl == NULL)
  1285                         goto enomem;
  1286 
  1287                     free_stringlist(msg->in_reply_to);
  1288                     msg->in_reply_to = sl;
  1289                 }
  1290                 break;
  1291 
  1292             case MAILIMF_FIELD_REFERENCES:
  1293                 {
  1294                     clist *list = _field->fld_data.fld_references->mid_list;
  1295                     stringlist_t *sl = clist_to_stringlist(list);
  1296                     if (sl == NULL)
  1297                         goto enomem;
  1298 
  1299                     free_stringlist(msg->references);
  1300                     msg->references = sl;
  1301                 }
  1302                 break;
  1303 
  1304             case MAILIMF_FIELD_KEYWORDS:
  1305                 {
  1306                     clist *list = _field->fld_data.fld_keywords->kw_list;
  1307                     stringlist_t *sl = clist_to_stringlist(list);
  1308                     if (sl == NULL)
  1309                         goto enomem;
  1310 
  1311                     free_stringlist(msg->keywords);
  1312                     msg->keywords = sl;
  1313                 }
  1314                 break;
  1315 
  1316             case MAILIMF_FIELD_COMMENTS:
  1317                 {
  1318                     char * text = _field->fld_data.fld_comments->cm_value;
  1319 
  1320                     free(msg->comments);
  1321                     index = 0;
  1322                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1323                             strlen(text), &index, "utf-8", &msg->comments);
  1324                     if (r)
  1325                         goto enomem;
  1326                 }
  1327                 break;
  1328 
  1329             case MAILIMF_FIELD_OPTIONAL_FIELD:
  1330                 {
  1331                     char * name =
  1332                             _field->fld_data.fld_optional_field->fld_name;
  1333                     char * value =
  1334                             _field->fld_data.fld_optional_field->fld_value;
  1335                     char *_value;
  1336 
  1337                     index = 0;
  1338                     r = mailmime_encoded_phrase_parse("utf-8", value,
  1339                             strlen(value), &index, "utf-8", &_value);
  1340                     if (r)
  1341                         goto enomem;
  1342 
  1343                     stringpair_t *pair = new_stringpair(name, _value);
  1344                     if (pair == NULL)
  1345                         goto enomem;
  1346 
  1347                     opt = stringpair_list_add(opt, pair);
  1348                     free(_value);
  1349                     if (opt == NULL)
  1350                         goto enomem;
  1351 
  1352                     if (msg->opt_fields == NULL)
  1353                         msg->opt_fields = opt;
  1354                 }
  1355                 break;
  1356         }
  1357     }
  1358 
  1359     return PEP_STATUS_OK;
  1360 
  1361 enomem:
  1362     status = PEP_OUT_OF_MEMORY;
  1363 
  1364 pep_error:
  1365     return status;
  1366 }
  1367 
  1368 static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
  1369 {
  1370     const char *text;
  1371     char *_longmsg;
  1372     size_t length;
  1373     size_t _size;
  1374     int code;
  1375     int r;
  1376     size_t index;
  1377     char *type = NULL;
  1378     char *charset = NULL;
  1379 
  1380     assert(part);
  1381     assert(longmsg);
  1382 
  1383     *longmsg = NULL;
  1384     if (size)
  1385         *size = 0;
  1386 
  1387     if (part->mm_body == NULL)
  1388         return PEP_ILLEGAL_VALUE;
  1389 
  1390     text = part->mm_body-> dt_data.dt_text.dt_data;
  1391     if (text == NULL)
  1392         return PEP_ILLEGAL_VALUE;
  1393 
  1394     length = part->mm_body->dt_data.dt_text.dt_length;
  1395 
  1396     if (part->mm_body->dt_encoded) {
  1397         code = part->mm_body->dt_encoding;
  1398         index = 0;
  1399         r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
  1400         switch (r) {
  1401             case MAILIMF_NO_ERROR:
  1402                 break;
  1403             case MAILIMF_ERROR_MEMORY:
  1404                 return PEP_OUT_OF_MEMORY;
  1405             default:
  1406                 return PEP_ILLEGAL_VALUE;
  1407         }
  1408     }
  1409     else {
  1410         _size = length + 1;
  1411         _longmsg = strndup(text, length);
  1412         if (_longmsg == NULL)
  1413             return PEP_OUT_OF_MEMORY;
  1414     }
  1415 
  1416     if (part->mm_content_type) {
  1417         if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
  1418             if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
  1419                 char * _text;
  1420                 int r = charconv("utf-8", charset, _longmsg, _size, &_text);
  1421                 switch (r) {
  1422                     case MAILIMF_NO_ERROR:
  1423                         break;
  1424                     case MAILIMF_ERROR_MEMORY:
  1425                         return PEP_OUT_OF_MEMORY;
  1426                     default:
  1427                         return PEP_ILLEGAL_VALUE;
  1428                 }
  1429                 free(_longmsg);
  1430                 _longmsg = _text;
  1431             }
  1432         }
  1433     }
  1434     // FIXME: KG - we now have the text we want.
  1435     // Now we need to strip sigs and process them if they are there..
  1436     
  1437 
  1438     *longmsg = _longmsg;
  1439     if (size)
  1440         *size = _size;
  1441 
  1442     return PEP_STATUS_OK;
  1443 }
  1444 
  1445 static PEP_STATUS interpret_MIME(
  1446         struct mailmime *mime,
  1447         message *msg
  1448     )
  1449 {
  1450     PEP_STATUS status = PEP_STATUS_OK;
  1451 
  1452     assert(mime);
  1453     assert(msg);
  1454 
  1455     struct mailmime_content *content = mime->mm_content_type;
  1456     if (content) {
  1457         if (_is_multipart(content, "alternative")) {
  1458             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1459             if (partlist == NULL)
  1460                 return PEP_ILLEGAL_VALUE;
  1461 
  1462             clistiter *cur;
  1463             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1464                 struct mailmime *part = clist_content(cur);
  1465                 if (part == NULL)
  1466                     return PEP_ILLEGAL_VALUE;
  1467 
  1468                 content = part->mm_content_type;
  1469                 assert(content);
  1470                 if (content == NULL)
  1471                     return PEP_ILLEGAL_VALUE;
  1472 
  1473                 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
  1474                     status = interpret_body(part, &msg->longmsg, NULL);
  1475                     if (status)
  1476                         return status;
  1477                 }
  1478                 else if (_is_text_part(content, "html") &&
  1479                         msg->longmsg_formatted == NULL) {
  1480                     status = interpret_body(part, &msg->longmsg_formatted,
  1481                             NULL);
  1482                     if (status)
  1483                         return status;
  1484                 }
  1485                 else /* add as attachment */ {
  1486                     status = interpret_MIME(part, msg);
  1487                     if (status)
  1488                         return status;
  1489                 }
  1490             }
  1491         }
  1492         else if (_is_multipart(content, "encrypted")) {
  1493             if (msg->longmsg == NULL)
  1494                 msg->longmsg = strdup("");
  1495             assert(msg->longmsg);
  1496             if (!msg->longmsg)
  1497                 return PEP_OUT_OF_MEMORY;
  1498 
  1499             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1500             if (partlist == NULL)
  1501                 return PEP_ILLEGAL_VALUE;
  1502 
  1503             clistiter *cur;
  1504             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1505                 struct mailmime *part= clist_content(cur);
  1506                 if (part == NULL)
  1507                     return PEP_ILLEGAL_VALUE;
  1508 
  1509                 status = interpret_MIME(part, msg);
  1510                 if (status != PEP_STATUS_OK)
  1511                     return status;
  1512             }
  1513         }
  1514         else if (_is_multipart(content, NULL)) {
  1515             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1516             if (partlist == NULL)
  1517                 return PEP_ILLEGAL_VALUE;
  1518 
  1519             clistiter *cur;
  1520             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1521                 struct mailmime *part= clist_content(cur);
  1522                 if (part == NULL)
  1523                     return PEP_ILLEGAL_VALUE;
  1524 
  1525                 status = interpret_MIME(part, msg);
  1526                 if (status != PEP_STATUS_OK)
  1527                     return status;
  1528             }
  1529         }
  1530         else {
  1531             if (_is_text_part(content, "html") &&
  1532                 msg->longmsg_formatted == NULL) {
  1533                 status = interpret_body(mime, &msg->longmsg_formatted,
  1534                                         NULL);
  1535                 if (status)
  1536                     return status;
  1537             }
  1538             else if (_is_text_part(content, NULL) && msg->longmsg == NULL) {
  1539                 status = interpret_body(mime, &msg->longmsg, NULL);
  1540                 if (status)
  1541                     return status;
  1542             }
  1543             else {
  1544                 char *data = NULL;
  1545                 size_t size = 0;
  1546                 char * mime_type;
  1547                 char * charset;
  1548                 char * filename;
  1549                 int r;
  1550 
  1551                 r = _get_content_type(content, &mime_type, &charset);
  1552                 switch (r) {
  1553                     case 0:
  1554                         break;
  1555                     case EINVAL:
  1556                         return PEP_ILLEGAL_VALUE;
  1557                     case ENOMEM:
  1558                         return PEP_OUT_OF_MEMORY;
  1559                     default:
  1560                         return PEP_UNKNOWN_ERROR;
  1561                 }
  1562 
  1563                 assert(mime_type);
  1564 
  1565                 status = interpret_body(mime, &data, &size);
  1566                 if (status)
  1567                     return status;
  1568 
  1569                 pEp_rid_list_t* resource_id_list = _get_resource_id_list(mime);
  1570                 pEp_rid_list_t* chosen_resource_id = choose_resource_id(resource_id_list);
  1571                 
  1572                 //filename = _get_filename_or_cid(mime);
  1573                 char *_filename = NULL;
  1574                 
  1575                 if (chosen_resource_id) {
  1576                     filename = chosen_resource_id->rid;
  1577                     size_t index = 0;
  1578                     /* NOTA BENE */
  1579                     /* The prefix we just added shouldn't be a problem - this is about decoding %XX (RFC 2392) */
  1580                     /* If it becomes one, we have some MESSY fixing to do. :(                                  */
  1581                     r = mailmime_encoded_phrase_parse("utf-8", filename,
  1582                             strlen(filename), &index, "utf-8", &_filename);
  1583                     if (r) {
  1584                         goto enomem;
  1585                     }
  1586                     char* file_prefix = NULL;
  1587                     
  1588                     /* in case there are others later */
  1589                     switch (chosen_resource_id->rid_type) {
  1590                         case PEP_RID_CID:
  1591                             file_prefix = "cid";
  1592                             break;
  1593                         case PEP_RID_FILENAME:
  1594                             file_prefix = "file";
  1595                             break;
  1596                         default:
  1597                             break;
  1598                     }
  1599 
  1600                     
  1601                     if (file_prefix) {
  1602                         filename = build_uri(file_prefix, _filename);
  1603                         free(_filename);
  1604                         _filename = filename;
  1605                     }
  1606                 }
  1607 
  1608                 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
  1609                         mime_type, _filename);
  1610                 free(_filename);
  1611                 free_rid_list(resource_id_list);
  1612                 resource_id_list = NULL;
  1613                 if (_a == NULL)
  1614                     return PEP_OUT_OF_MEMORY;
  1615                 if (msg->attachments == NULL)
  1616                     msg->attachments = _a;
  1617             }
  1618         }
  1619     }
  1620 
  1621     return PEP_STATUS_OK;
  1622 
  1623 enomem:
  1624     return PEP_OUT_OF_MEMORY;
  1625 }
  1626 
  1627 DYNAMIC_API PEP_STATUS mime_decode_message(
  1628         const char *mimetext,
  1629         size_t size,
  1630         message **msg
  1631     )
  1632 {
  1633     PEP_STATUS status = PEP_STATUS_OK;
  1634     struct mailmime * mime = NULL;
  1635     int r;
  1636     message *_msg = NULL;
  1637     size_t index;
  1638 
  1639     assert(mimetext);
  1640     assert(msg);
  1641 
  1642     if (!(mimetext && msg))
  1643         return PEP_ILLEGAL_VALUE;
  1644 
  1645     *msg = NULL;
  1646 
  1647     index = 0;
  1648     r = mailmime_parse(mimetext, size, &index, &mime);
  1649     assert(r == 0);
  1650     assert(mime);
  1651     if (r) {
  1652         if (r == MAILIMF_ERROR_MEMORY)
  1653             goto enomem;
  1654         else
  1655             goto err_mime;
  1656     }
  1657 
  1658     _msg = calloc(1, sizeof(message));
  1659     assert(_msg);
  1660     if (_msg == NULL)
  1661         goto enomem;
  1662 
  1663     clist * _fieldlist = _get_fields(mime);
  1664     if (_fieldlist) {
  1665         status = read_fields(_msg, _fieldlist);
  1666         if (status != PEP_STATUS_OK)
  1667             goto pep_error;
  1668     }
  1669 
  1670     struct mailmime_content *content = _get_content(mime);
  1671 
  1672     if (content) {
  1673         status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
  1674                 _msg);
  1675         if (status != PEP_STATUS_OK)
  1676             goto pep_error;
  1677     }
  1678 
  1679     mailmime_free(mime);
  1680     *msg = _msg;
  1681 
  1682     return status;
  1683 
  1684 err_mime:
  1685     status = PEP_ILLEGAL_VALUE;
  1686     goto pep_error;
  1687 
  1688 enomem:
  1689     status = PEP_OUT_OF_MEMORY;
  1690 
  1691 pep_error:
  1692     free_message(_msg);
  1693 
  1694     if (mime)
  1695         mailmime_free(mime);
  1696 
  1697     return status;
  1698 }