src/mime.c
author Krista Bennett <krista@pep-project.org>
Tue, 14 Aug 2018 13:45:34 +0200
branchENGINE-451
changeset 2826 07c080d73a63
parent 2700 cd9a4efecb62
child 2834 7a35e7ea6138
child 2895 fcc598cc5e2f
permissions -rw-r--r--
ENGINE-451: abandoning branch - config files to be dealt with using gpgme (and hotfix will be external to engine
     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 // THIS IS A BEST-EFFORT ONLY FUNCTION, AND WE ARE NOT DOING MORE THAN THE
  1437 // SUBJECT FOR NOW.
  1438 static PEP_STATUS interpret_protected_headers(
  1439         struct mailmime* mime, 
  1440         message* msg
  1441     )
  1442 {
  1443     // N.B. this is *very much* enigmail output specific, and right now,
  1444     // we only care about subject replacement.
  1445     const char* header_string = "Content-Type: text/rfc822-headers; protected-headers=\"v1\"\nContent-Disposition: inline\n\n";
  1446     size_t content_length = mime->mm_length;
  1447     size_t header_strlen = strlen(header_string);
  1448     if (header_strlen < content_length) {
  1449         const char* headerblock = mime->mm_mime_start;
  1450         size_t subject_len = 0;
  1451         headerblock = strstr(headerblock, header_string);
  1452         if (headerblock) {
  1453             const char* subj_start = "Subject: ";
  1454             size_t subj_len = strlen(subj_start);
  1455             headerblock = strstr(headerblock, subj_start);
  1456             if (headerblock) {
  1457                 headerblock += subj_len;
  1458                 char* end_pt = strstr(headerblock, "\n");
  1459                 if (end_pt) {
  1460                     if (end_pt != mime->mm_mime_start && *(end_pt - 1) == '\r')
  1461                         end_pt--;
  1462                     subject_len = end_pt - headerblock;
  1463                     char* new_subj = (char*)calloc(subject_len + 1, 1);
  1464                     if (new_subj) {
  1465                         strlcpy(new_subj, headerblock, subject_len + 1);
  1466                         free(msg->shortmsg);
  1467                         msg->shortmsg = new_subj;
  1468                     }    
  1469                 } // if there's no endpoint, there's something wrong here so we ignore all
  1470                   // This is best effort.
  1471             }
  1472         }
  1473     }
  1474     return PEP_STATUS_OK;
  1475 }
  1476 
  1477 static PEP_STATUS interpret_MIME(
  1478         struct mailmime *mime,
  1479         message *msg
  1480     )
  1481 {
  1482     PEP_STATUS status = PEP_STATUS_OK;
  1483 
  1484     assert(mime);
  1485     assert(msg);
  1486 
  1487     struct mailmime_content *content = mime->mm_content_type;
  1488     if (content) {
  1489         if (_is_multipart(content, "alternative")) {
  1490             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1491             if (partlist == NULL)
  1492                 return PEP_ILLEGAL_VALUE;
  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                 content = part->mm_content_type;
  1501                 assert(content);
  1502                 if (content == NULL)
  1503                     return PEP_ILLEGAL_VALUE;
  1504 
  1505                 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
  1506                     status = interpret_body(part, &msg->longmsg, NULL);
  1507                     if (status)
  1508                         return status;
  1509                 }
  1510                 else if (_is_text_part(content, "rfc822-headers")) {
  1511                     status = interpret_protected_headers(part, msg);
  1512                     if (status)
  1513                         return status;
  1514                 }
  1515                 else if (_is_text_part(content, "html") &&
  1516                         msg->longmsg_formatted == NULL) {
  1517                     status = interpret_body(part, &msg->longmsg_formatted,
  1518                             NULL);
  1519                     if (status)
  1520                         return status;
  1521                 }
  1522                 else /* add as attachment */ {
  1523                     status = interpret_MIME(part, msg);
  1524                     if (status)
  1525                         return status;
  1526                 }
  1527             }
  1528         }
  1529         else if (_is_multipart(content, "encrypted")) {
  1530             if (msg->longmsg == NULL)
  1531                 msg->longmsg = strdup("");
  1532             assert(msg->longmsg);
  1533             if (!msg->longmsg)
  1534                 return PEP_OUT_OF_MEMORY;
  1535 
  1536             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1537             if (partlist == NULL)
  1538                 return PEP_ILLEGAL_VALUE;
  1539 
  1540             clistiter *cur;
  1541             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1542                 struct mailmime *part= clist_content(cur);
  1543                 if (part == NULL)
  1544                     return PEP_ILLEGAL_VALUE;
  1545 
  1546                 status = interpret_MIME(part, msg);
  1547                 if (status != PEP_STATUS_OK)
  1548                     return status;
  1549             }
  1550         }
  1551         else if (_is_multipart(content, NULL)) {
  1552             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1553             if (partlist == NULL)
  1554                 return PEP_ILLEGAL_VALUE;
  1555 
  1556             clistiter *cur;
  1557             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1558                 struct mailmime *part= clist_content(cur);
  1559                 if (part == NULL)
  1560                     return PEP_ILLEGAL_VALUE;
  1561                 status = interpret_MIME(part, msg);
  1562                 if (status != PEP_STATUS_OK)
  1563                     return status;
  1564             }
  1565         }
  1566         else {
  1567             if (_is_text_part(content, "html") &&
  1568                 msg->longmsg_formatted == NULL) {
  1569                 status = interpret_body(mime, &msg->longmsg_formatted,
  1570                                         NULL);
  1571                 if (status)
  1572                     return status;
  1573             }
  1574             else if (_is_text_part(content, "rfc822-headers")) {
  1575                 status = interpret_protected_headers(mime, msg);
  1576                 if (status)
  1577                     return status;
  1578             }
  1579             else if (_is_text_part(content, NULL) && msg->longmsg == NULL) {
  1580                 status = interpret_body(mime, &msg->longmsg, NULL);
  1581                 if (status)
  1582                     return status;
  1583             }
  1584             else {
  1585                 char *data = NULL;
  1586                 size_t size = 0;
  1587                 char * mime_type;
  1588                 char * charset;
  1589                 char * filename;
  1590                 int r;
  1591 
  1592                 r = _get_content_type(content, &mime_type, &charset);
  1593                 switch (r) {
  1594                     case 0:
  1595                         break;
  1596                     case EINVAL:
  1597                         return PEP_ILLEGAL_VALUE;
  1598                     case ENOMEM:
  1599                         return PEP_OUT_OF_MEMORY;
  1600                     default:
  1601                         return PEP_UNKNOWN_ERROR;
  1602                 }
  1603 
  1604                 assert(mime_type);
  1605 
  1606                 status = interpret_body(mime, &data, &size);
  1607                 if (status)
  1608                     return status;
  1609 
  1610                 pEp_rid_list_t* resource_id_list = _get_resource_id_list(mime);
  1611                 pEp_rid_list_t* chosen_resource_id = choose_resource_id(resource_id_list);
  1612                 
  1613                 //filename = _get_filename_or_cid(mime);
  1614                 char *_filename = NULL;
  1615                 
  1616                 if (chosen_resource_id) {
  1617                     filename = chosen_resource_id->rid;
  1618                     size_t index = 0;
  1619                     /* NOTA BENE */
  1620                     /* The prefix we just added shouldn't be a problem - this is about decoding %XX (RFC 2392) */
  1621                     /* If it becomes one, we have some MESSY fixing to do. :(                                  */
  1622                     r = mailmime_encoded_phrase_parse("utf-8", filename,
  1623                             strlen(filename), &index, "utf-8", &_filename);
  1624                     if (r) {
  1625                         goto enomem;
  1626                     }
  1627                     char* file_prefix = NULL;
  1628                     
  1629                     /* in case there are others later */
  1630                     switch (chosen_resource_id->rid_type) {
  1631                         case PEP_RID_CID:
  1632                             file_prefix = "cid";
  1633                             break;
  1634                         case PEP_RID_FILENAME:
  1635                             file_prefix = "file";
  1636                             break;
  1637                         default:
  1638                             break;
  1639                     }
  1640 
  1641                     
  1642                     if (file_prefix) {
  1643                         filename = build_uri(file_prefix, _filename);
  1644                         free(_filename);
  1645                         _filename = filename;
  1646                     }
  1647                 }
  1648 
  1649                 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
  1650                         mime_type, _filename);
  1651                 free(_filename);
  1652                 free_rid_list(resource_id_list);
  1653                 resource_id_list = NULL;
  1654                 if (_a == NULL)
  1655                     return PEP_OUT_OF_MEMORY;
  1656                 if (msg->attachments == NULL)
  1657                     msg->attachments = _a;
  1658             }
  1659         }
  1660     }
  1661 
  1662     return PEP_STATUS_OK;
  1663 
  1664 enomem:
  1665     return PEP_OUT_OF_MEMORY;
  1666 }
  1667 
  1668 DYNAMIC_API PEP_STATUS mime_decode_message(
  1669         const char *mimetext,
  1670         size_t size,
  1671         message **msg
  1672     )
  1673 {
  1674     PEP_STATUS status = PEP_STATUS_OK;
  1675     struct mailmime * mime = NULL;
  1676     int r;
  1677     message *_msg = NULL;
  1678     size_t index;
  1679 
  1680     assert(mimetext);
  1681     assert(msg);
  1682 
  1683     if (!(mimetext && msg))
  1684         return PEP_ILLEGAL_VALUE;
  1685 
  1686     *msg = NULL;
  1687 
  1688     index = 0;
  1689     r = mailmime_parse(mimetext, size, &index, &mime);
  1690     assert(r == 0);
  1691     assert(mime);
  1692     if (r) {
  1693         if (r == MAILIMF_ERROR_MEMORY)
  1694             goto enomem;
  1695         else
  1696             goto err_mime;
  1697     }
  1698 
  1699     _msg = calloc(1, sizeof(message));
  1700     assert(_msg);
  1701     if (_msg == NULL)
  1702         goto enomem;
  1703 
  1704     clist * _fieldlist = _get_fields(mime);
  1705     if (_fieldlist) {
  1706         status = read_fields(_msg, _fieldlist);
  1707         if (status != PEP_STATUS_OK)
  1708             goto pep_error;
  1709     }
  1710 
  1711     struct mailmime_content *content = _get_content(mime);
  1712 
  1713     if (content) {
  1714         status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
  1715                 _msg);
  1716         if (status != PEP_STATUS_OK)
  1717             goto pep_error;
  1718     }
  1719 
  1720     mailmime_free(mime);
  1721     *msg = _msg;
  1722 
  1723     return status;
  1724 
  1725 err_mime:
  1726     status = PEP_ILLEGAL_VALUE;
  1727     goto pep_error;
  1728 
  1729 enomem:
  1730     status = PEP_OUT_OF_MEMORY;
  1731 
  1732 pep_error:
  1733     free_message(_msg);
  1734 
  1735     if (mime)
  1736         mailmime_free(mime);
  1737 
  1738     return status;
  1739 }