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