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