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