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