src/mime.c
author us@chu.huenfield.org
Tue, 25 Dec 2018 14:46:45 +0100
branchsync
changeset 3209 c15b4ca2b52a
parent 3137 93877eafa715
child 3270 d8aea79654c3
permissions -rw-r--r--
Replace use of Sequoia's backend with a custom key store.

- Sequoia's key store doesn't meet pep's needs (in particular, the
ability to search on a key's user id) and trying to shoehorn pep's
needs onto Sequoia's key store abstractions is just introducing
overhead with no appreciable gain in functionality.

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