src/etpan_mime.c
author Krista 'DarthMama' Bennett <krista@pep.foundation>
Fri, 24 Apr 2020 19:38:56 +0200
branchpostrelease
changeset 4592 f0e7ec9616c5
parent 4591 fbaa9d61a265
child 4719 b4d7c37ac808
permissions -rw-r--r--
ENGINE-741, ENGINE-742: mime_encode_message and mime_decode_message APIs changed, plus test suite upgrade. JSON Adapter and pEpMIME must adapt to this, as this breaks the former api!
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 #include "etpan_mime.h"
     5 #ifndef mailmime_param_new_with_data
     6 #include <libetpan/mailprivacy_tools.h>
     7 #endif
     8 
     9 #include "pEp_internal.h"
    10 #include "platform.h"
    11 #include "mime.h"
    12 #include "wrappers.h"
    13 #include "resource_id.h"
    14 
    15 #include <string.h>
    16 #include <stdlib.h>
    17 #include <assert.h>
    18 #include <errno.h>
    19 
    20 #define MAX_MESSAGE_ID 128
    21 
    22 static char * generate_boundary(void)
    23 {
    24     char id[MAX_MESSAGE_ID];
    25 
    26     // no cryptographically strong random needed here
    27     const long value1 = random();
    28     const long value2 = random();
    29     const long value3 = random();
    30     const long value4 = random();
    31 
    32     snprintf(id, MAX_MESSAGE_ID, "%.4lx%.4lx%.4lx%.4lx", value1, value2,
    33             value3, value4);
    34     
    35     return strdup(id);
    36 }
    37 
    38 struct mailmime * part_new_empty(
    39         struct mailmime_content * content,
    40         struct mailmime_fields * mime_fields,
    41         stringpair_list_t* param_keyvals,
    42         int force_single
    43     )
    44 {
    45     struct mailmime * build_info;
    46     clist * list = NULL;
    47     int r;
    48     int mime_type;
    49     char * attr_name = NULL;
    50     char * attr_value = NULL;
    51     struct mailmime_parameter * param = NULL;
    52     clist * parameters = NULL;
    53     char *boundary = NULL;
    54 
    55     list = NULL;
    56 
    57     if (force_single) {
    58         mime_type = MAILMIME_SINGLE;
    59     }
    60     else {
    61         switch (content->ct_type->tp_type) {
    62             case MAILMIME_TYPE_DISCRETE_TYPE:
    63                 mime_type = MAILMIME_SINGLE;
    64                 break;
    65 
    66             case MAILMIME_TYPE_COMPOSITE_TYPE:
    67                 switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
    68                     case MAILMIME_COMPOSITE_TYPE_MULTIPART:
    69                         mime_type = MAILMIME_MULTIPLE;
    70                         break;
    71 
    72                     case MAILMIME_COMPOSITE_TYPE_MESSAGE:
    73                         if (strcasecmp(content->ct_subtype, "rfc822") == 0)
    74                             mime_type = MAILMIME_MESSAGE;
    75                         else
    76                             mime_type = MAILMIME_SINGLE;
    77                         break;
    78 
    79                     default:
    80                         goto enomem;
    81                 }
    82                 break;
    83 
    84             default:
    85                 goto enomem;
    86         }
    87     }
    88 
    89     if (mime_type == MAILMIME_MULTIPLE) {
    90         list = clist_new();
    91         assert(list);
    92         if (list == NULL)
    93             goto enomem;
    94 
    95         attr_name = strdup("boundary");
    96         assert(attr_name);
    97         if (attr_name == NULL)
    98             goto enomem;
    99 
   100         boundary = generate_boundary();
   101         assert(boundary);
   102         attr_value = boundary;
   103         if (attr_value == NULL)
   104             goto enomem;
   105 
   106         param = mailmime_parameter_new(attr_name, attr_value);
   107         assert(param);
   108         if (param == NULL)
   109             goto enomem;
   110         attr_name = NULL;
   111         attr_value = NULL;
   112 
   113         if (content->ct_parameters == NULL) {
   114             parameters = clist_new();
   115             assert(parameters);
   116             if (parameters == NULL)
   117                 goto enomem;
   118         }
   119         else {
   120             parameters = content->ct_parameters;
   121         }
   122 
   123         r = clist_append(parameters, param);
   124         if (r)
   125             goto enomem;
   126         param = NULL;
   127 
   128         if (content->ct_parameters == NULL)
   129             content->ct_parameters = parameters;
   130     }
   131     
   132     if (param_keyvals) {
   133         stringpair_list_t* cur;
   134         for (cur = param_keyvals; cur; cur = cur->next) {
   135             attr_name = strdup(cur->value->key);
   136             attr_value = strdup(cur->value->value);
   137             
   138             param = mailmime_parameter_new(attr_name, attr_value);
   139             assert(param);
   140             if (param == NULL)
   141                 goto enomem;
   142                 
   143             attr_name = NULL;
   144             attr_value = NULL;
   145 
   146             if (content->ct_parameters == NULL) {
   147                 parameters = clist_new();
   148                 assert(parameters);
   149                 if (parameters == NULL)
   150                     goto enomem;
   151             }
   152             else {
   153                 parameters = content->ct_parameters;
   154             }
   155 
   156             r = clist_append(parameters, param);
   157             if (r)
   158                 goto enomem;
   159             param = NULL;
   160 
   161             if (content->ct_parameters == NULL)
   162                 content->ct_parameters = parameters;            
   163         }
   164     }
   165 
   166     build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
   167             NULL, NULL, list, NULL, NULL);
   168     if (build_info == NULL)
   169         goto enomem;
   170 
   171     return build_info;
   172 
   173 enomem:
   174     if (list)
   175         clist_free(list);
   176     free(attr_name);
   177     free(attr_value);
   178     if (content->ct_parameters == NULL)
   179         if (parameters)
   180             clist_free(parameters);
   181     if (param)
   182         mailmime_parameter_free(param);
   183     return NULL;
   184 }
   185 
   186 struct mailmime * get_pgp_encrypted_part(void)
   187 {
   188     struct mailmime * mime = NULL;
   189     struct mailmime_fields * mime_fields = NULL;
   190     struct mailmime_content * content = NULL;
   191     int r;
   192 
   193     content = mailmime_content_new_with_str("application/pgp-encrypted");
   194     if (content == NULL)
   195         goto enomem;
   196 
   197     mime_fields = mailmime_fields_new_empty();
   198     if (mime_fields == NULL)
   199         goto enomem;
   200 
   201     mime = part_new_empty(content, mime_fields, NULL, 1);
   202     if (mime == NULL)
   203         goto enomem;
   204     mime_fields = NULL;
   205     content = NULL;
   206 
   207     r = mailmime_set_body_text(mime, "Version: 1\n", 10);
   208     if (r != 0)
   209         goto enomem;
   210 
   211     return mime;
   212 
   213 enomem:
   214     if (content)
   215         mailmime_content_free(content);
   216     if (mime_fields)
   217         mailmime_fields_free(mime_fields);
   218     if (mime)
   219         mailmime_free(mime);
   220 
   221     return NULL;
   222 }
   223 
   224 struct mailmime * get_text_part(
   225         pEp_rid_list_t* resource,
   226         const char * mime_type,
   227         const char * text,
   228         size_t length,
   229         int encoding_type
   230     )
   231 {
   232     char * disposition_name = NULL;
   233     struct mailmime_fields * mime_fields = NULL;
   234     struct mailmime * mime = NULL;
   235     struct mailmime_content * content = NULL;
   236     struct mailmime_parameter * param = NULL;
   237     struct mailmime_disposition * disposition = NULL;
   238     struct mailmime_mechanism * encoding = NULL;
   239     char* content_id = NULL;
   240     int r;
   241                 
   242     if (resource != NULL && resource->rid != NULL) {
   243         switch (resource->rid_type) {
   244             case PEP_RID_CID:
   245                 content_id = strdup(resource->rid);
   246                 break;
   247             case PEP_RID_FILENAME:
   248             default:
   249                 disposition_name = strdup(resource->rid);
   250                 if (disposition_name == NULL)
   251                     goto enomem;
   252                     
   253                 disposition =
   254                         mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
   255                                 disposition_name, NULL, NULL, NULL, (size_t) -1);
   256 
   257                 if (disposition == NULL)
   258                     goto enomem;
   259 
   260                 disposition_name = NULL;                
   261                 break;
   262         }    
   263     }
   264     
   265     if (encoding_type) {
   266         encoding = mailmime_mechanism_new(encoding_type, NULL);
   267         if (encoding == NULL)
   268             goto enomem;
   269     }
   270 
   271     mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
   272             disposition, NULL);
   273     if (mime_fields == NULL)
   274         goto enomem;
   275     encoding = NULL;
   276     disposition = NULL;
   277     content_id = NULL;
   278 
   279     content = mailmime_content_new_with_str(mime_type);
   280     if (content == NULL)
   281         goto enomem;
   282     
   283     if (encoding_type != MAILMIME_MECHANISM_7BIT) {
   284         param = mailmime_param_new_with_data("charset", "utf-8");
   285         r = clist_append(content->ct_parameters, param);
   286         if (r != 0)
   287             goto enomem;
   288     }
   289 
   290     mime = part_new_empty(content, mime_fields, NULL, 1);
   291     if (mime == NULL)
   292         goto enomem;
   293     content = NULL;
   294     mime_fields = NULL;
   295 
   296     if (text) {
   297         r = mailmime_set_body_text(mime, (char *) text, length);
   298         if (r != 0)
   299             goto enomem;
   300     }
   301     
   302     return mime;
   303 
   304 enomem:
   305     free(disposition_name);
   306     if (mime_fields)
   307         mailmime_fields_free(mime_fields);
   308     if (mime)
   309         mailmime_free(mime);
   310     if (content)
   311         mailmime_content_free(content);
   312     if (param)
   313         mailmime_parameter_free(param);
   314     if (disposition)
   315         mailmime_disposition_free(disposition);
   316     if (encoding)
   317         mailmime_mechanism_free(encoding);
   318 
   319     return NULL;
   320 }
   321 
   322 struct mailmime * get_file_part(
   323         pEp_rid_list_t* resource,
   324         const char * mime_type,
   325         char * data,
   326         size_t length,
   327         bool is_nf_message_attachment // non-forwarded msg as att
   328     )
   329 {
   330     char * disposition_name = NULL;
   331     int encoding_type;
   332     struct mailmime_disposition * disposition = NULL;
   333     struct mailmime_mechanism * encoding = NULL;
   334     struct mailmime_content * content = NULL;
   335     struct mailmime * mime = NULL;
   336     struct mailmime_fields * mime_fields = NULL;
   337     char* content_id = NULL;
   338     int r;
   339                 
   340     if (resource != NULL && resource->rid != NULL) {
   341         switch (resource->rid_type) {
   342             case PEP_RID_CID:
   343                 content_id = strdup(resource->rid);
   344                 disposition =
   345                     mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
   346                                                        NULL, NULL, NULL, NULL, (size_t) -1);
   347                     if (disposition == NULL)
   348                         goto enomem;
   349                 break;
   350             case PEP_RID_FILENAME:
   351             default:
   352                 disposition_name = strdup(resource->rid);
   353                 if (disposition_name == NULL)
   354                     goto enomem;
   355                     
   356                 disposition =
   357                         mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
   358                                 disposition_name, NULL, NULL, NULL, (size_t) -1);
   359                                 
   360                 if (disposition == NULL)
   361                     goto enomem;
   362                 disposition_name = NULL;
   363                 
   364                 break;
   365         }    
   366     }
   367     
   368 
   369     content = mailmime_content_new_with_str(mime_type);
   370     if (content == NULL)
   371         goto enomem;
   372 
   373     encoding = NULL;
   374 
   375     bool already_ascii = !(must_chunk_be_encoded(data, length, true));
   376     
   377     if (!is_nf_message_attachment && !already_ascii) {
   378         encoding_type = MAILMIME_MECHANISM_BASE64;
   379         encoding = mailmime_mechanism_new(encoding_type, NULL);
   380         if (encoding == NULL)
   381             goto enomem;
   382     }
   383 
   384     mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
   385             disposition, NULL);
   386     if (mime_fields == NULL)
   387         goto enomem;
   388     encoding = NULL;
   389     disposition = NULL;
   390 
   391     stringpair_list_t* extra_params = NULL;
   392     
   393     if (is_nf_message_attachment)
   394         extra_params = new_stringpair_list(new_stringpair("forwarded", "no"));
   395     
   396     mime = part_new_empty(content, mime_fields, extra_params, 1);
   397     free_stringpair_list(extra_params);
   398     if (mime == NULL)
   399         goto enomem;
   400     content = NULL;
   401     mime_fields = NULL;
   402 
   403     if(length > 0)
   404     {
   405         r = mailmime_set_body_text(mime, data, length);
   406         if (r != 0)
   407             goto enomem;
   408     }
   409 
   410     return mime;
   411 
   412 enomem:
   413     free(disposition_name);
   414     if (disposition)
   415         mailmime_disposition_free(disposition);
   416     if (encoding)
   417         mailmime_mechanism_free(encoding);
   418     if (content)
   419         mailmime_content_free(content);
   420     if (mime_fields)
   421         mailmime_fields_free(mime_fields);
   422     if (mime)
   423         mailmime_free(mime);
   424     
   425     return NULL;
   426 }
   427 
   428 struct mailmime * part_multiple_new(const char *type)
   429 {
   430     struct mailmime_fields *mime_fields = NULL;
   431     struct mailmime_content *content = NULL;
   432     struct mailmime *mp = NULL;
   433     
   434     mime_fields = mailmime_fields_new_empty();
   435     if (mime_fields == NULL)
   436         goto enomem;
   437     
   438     content = mailmime_content_new_with_str(type);
   439     if (content == NULL)
   440         goto enomem;
   441     
   442     mp = part_new_empty(content, mime_fields, NULL, 0);
   443     if (mp == NULL)
   444         goto enomem;
   445     
   446     return mp;
   447     
   448 enomem:
   449     if (content)
   450         mailmime_content_free(content);
   451     if (mime_fields)
   452         mailmime_fields_free(mime_fields);
   453 
   454     return NULL;
   455 }
   456 
   457 struct mailimf_field * _new_field(
   458         int type,
   459         _new_func_t new_func,
   460         void *value
   461     )
   462 {
   463     void *data = new_func(value);
   464     assert(data);
   465     if (data == NULL)
   466         return NULL;
   467 
   468     struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
   469     assert(result);
   470     if (result == NULL) {
   471         free(data);
   472         return NULL;
   473     }
   474 
   475     result->fld_type = type;
   476     result->fld_data.fld_return_path = data;
   477 
   478     return result;
   479 }
   480 
   481 void _free_field(struct mailimf_field *field)
   482 {
   483     if (field)
   484         free(field->fld_data.fld_return_path);
   485     free(field);
   486 }
   487 
   488 int _append_field(
   489         clist *list,
   490         int type,
   491         _new_func_t new_func,
   492         void *value
   493     )
   494 {
   495     int r;
   496     struct mailimf_field * field;
   497 
   498     assert(list);
   499     assert(new_func);
   500     assert(value);
   501 
   502     field = _new_field(type, new_func, value);
   503     if (field == NULL)
   504         return -1;
   505 
   506     r = clist_append(list, field);
   507     if (r)
   508         _free_field(field);
   509 
   510     return r;
   511 }
   512 
   513 // http://media2.giga.de/2014/02/Image-28.jpg
   514 
   515 struct mailimf_date_time * timestamp_to_etpantime(const timestamp *ts)
   516 {
   517     struct mailimf_date_time * result = calloc(1,
   518             sizeof(struct mailimf_date_time));
   519     assert(result);
   520     if (result == NULL)
   521         return NULL;
   522 
   523     assert(ts);
   524 
   525     result->dt_sec = ts->tm_sec;
   526     result->dt_min = ts->tm_min;
   527     result->dt_hour = ts->tm_hour;
   528     result->dt_day = ts->tm_mday;
   529     result->dt_month = ts->tm_mon + 1;
   530     result->dt_year = ts->tm_year + 1900;
   531     result->dt_zone = (int) (ts->tm_gmtoff / 36L);
   532     return result;
   533 }
   534 
   535 timestamp * etpantime_to_timestamp(const struct mailimf_date_time *et)
   536 {
   537     timestamp * result = calloc(1, sizeof(timestamp));
   538     assert(result);
   539     if (result == NULL)
   540         return NULL;
   541 
   542     assert(et);
   543 
   544     result->tm_sec = et->dt_sec;
   545     result->tm_min = et->dt_min;
   546     result->tm_hour = et->dt_hour;
   547     result->tm_mday = et->dt_day;
   548     result->tm_mon = et->dt_month - 1;
   549     result->tm_year = et->dt_year - 1900;
   550     result->tm_gmtoff = 36L * (long) et->dt_zone;
   551     return result;
   552 }
   553 
   554 struct mailimf_mailbox * mailbox_from_string(
   555         const char *name,
   556         const char *address
   557     )
   558 {
   559     struct mailimf_mailbox *mb = NULL;
   560     char *_name = NULL;
   561     char *_address = NULL;
   562 
   563     assert(address);
   564 
   565     _name = name ? strdup(name) : strdup("");
   566     if (_name == NULL)
   567         goto enomem;
   568 
   569     _address = strdup(address);
   570     if (_address == NULL)
   571         goto enomem;
   572 
   573     mb = mailimf_mailbox_new(_name, _address);
   574     assert(mb);
   575     if (mb == NULL)
   576         goto enomem;
   577 
   578     return mb;
   579 
   580 enomem:
   581     free(_name);
   582     free(_address);
   583 
   584     return NULL;
   585 }
   586 
   587 
   588 struct mailimf_field * create_optional_field(
   589         const char *field,
   590         const char *value
   591     )
   592 {
   593     char *_field = NULL;
   594     char *_value = NULL;
   595     struct mailimf_optional_field *optional_field = NULL;
   596 
   597     _field = strdup(field);
   598     if (_field == NULL)
   599         goto enomem;
   600 
   601     if (!must_field_value_be_encoded(value))
   602         _value = strdup(value);
   603     else    
   604         _value = mailmime_encode_subject_header("utf-8", value, 0);
   605     if (_value == NULL)
   606         goto enomem;
   607 
   608     optional_field = mailimf_optional_field_new(_field, _value);
   609     if (optional_field == NULL)
   610         goto enomem;
   611 
   612     struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
   613     assert(result);
   614     if (result == NULL)
   615         goto enomem;
   616 
   617     result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
   618     result->fld_data.fld_optional_field = optional_field;
   619 
   620     return result;
   621 
   622 enomem:
   623     if (optional_field) {
   624         mailimf_optional_field_free(optional_field);
   625     }
   626     else {
   627         free(_field);
   628         free(_value);
   629     }
   630 
   631     return NULL;
   632 }
   633 
   634 int _append_optional_field(
   635         clist *list,
   636         const char *field,
   637         const char *value
   638     )
   639 {
   640     int r;
   641     struct mailimf_field * optional_field =
   642             create_optional_field(field, value);
   643 
   644     if (optional_field == NULL)
   645         return -1;
   646 
   647     r = clist_append(list, optional_field);
   648     if (r)
   649         mailimf_field_free(optional_field);
   650 
   651     return r;
   652 }
   653 
   654 clist * _get_fields(struct mailmime * mime)
   655 {
   656     clist * _fieldlist = NULL;
   657 
   658     assert(mime);
   659 
   660     if (mime->mm_data.mm_message.mm_fields &&
   661             mime->mm_data.mm_message.mm_fields->fld_list) {
   662         _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
   663     }
   664 
   665     return _fieldlist;
   666 }
   667 
   668 struct mailmime_content * _get_content(struct mailmime * mime)
   669 {
   670     struct mailmime_content * content = NULL;
   671 
   672     assert(mime);
   673 
   674     if (mime->mm_data.mm_message.mm_msg_mime)
   675         content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
   676 
   677     return content;
   678 }
   679 
   680 
   681 /* Return a list of identifier_type and resource id (filename, cid, etc) */
   682 pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
   683 {
   684     clist * _fieldlist = NULL;
   685 
   686     assert(mime);
   687 
   688     if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
   689         _fieldlist = mime->mm_mime_fields->fld_list;
   690     else
   691         return NULL;
   692 
   693     clistiter *cur;
   694 
   695     pEp_rid_list_t* rid_list = NULL; 
   696     pEp_rid_list_t** rid_list_curr_p = &rid_list; 
   697         
   698     for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
   699         struct mailmime_field * _field = clist_content(cur);
   700         /* content_id */
   701         if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
   702             pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
   703             new_rid->rid_type = PEP_RID_CID;
   704             new_rid->rid = strdup(_field->fld_data.fld_id);
   705             *rid_list_curr_p = new_rid;
   706             rid_list_curr_p = &new_rid->next;
   707         }
   708         else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
   709             /* filename */
   710             if (_field->fld_data.fld_disposition &&
   711                     _field->fld_data.fld_disposition->dsp_parms) {
   712                 clist * _parmlist =
   713                         _field->fld_data.fld_disposition->dsp_parms;
   714                 clistiter *cur2;
   715                 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
   716                         clist_next(cur2)) {
   717                     struct mailmime_disposition_parm * param =
   718                             clist_content(cur2);
   719                     if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
   720                         pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
   721                         new_rid->rid_type = PEP_RID_FILENAME;
   722                         new_rid->rid = strdup(param->pa_data.pa_filename);
   723                         *rid_list_curr_p = new_rid;
   724                         rid_list_curr_p = &new_rid->next;
   725                     }                
   726                 }
   727             }
   728         }
   729     }
   730     /* Will almost certainly usually be a singleton, but we need to be able to decide */
   731     return rid_list;
   732 }
   733 
   734 
   735 /* FIXME: about to be obsoleted? */
   736 char * _get_filename_or_cid(struct mailmime *mime)
   737 {
   738     clist * _fieldlist = NULL;
   739 
   740     assert(mime);
   741 
   742     if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
   743         _fieldlist = mime->mm_mime_fields->fld_list;
   744     else
   745         return NULL;
   746 
   747     clistiter *cur;
   748     
   749     char* _temp_filename_ptr = NULL;
   750     
   751     for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
   752         struct mailmime_field * _field = clist_content(cur);
   753         if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
   754             /* We prefer CIDs to filenames when both are present */
   755             free(_temp_filename_ptr); /* can be null, it's ok */
   756             return build_uri("cid", _field->fld_data.fld_id); 
   757         }
   758         else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
   759             if (_field->fld_data.fld_disposition &&
   760                     _field->fld_data.fld_disposition->dsp_parms &&
   761                     !_temp_filename_ptr) {
   762                 clist * _parmlist =
   763                         _field->fld_data.fld_disposition->dsp_parms;
   764                 clistiter *cur2;
   765                 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
   766                         clist_next(cur2)) {
   767                     struct mailmime_disposition_parm * param =
   768                             clist_content(cur2);
   769                     if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
   770                         _temp_filename_ptr = build_uri("file", param->pa_data.pa_filename);
   771                         break;
   772                     }                
   773                 }
   774             }
   775         }
   776     }
   777     /* Ok, it wasn't a CID */
   778     return _temp_filename_ptr;
   779 }
   780 
   781 static bool parameter_has_value(
   782         struct mailmime_content *content,       
   783         const char *name,
   784         const char *value
   785     )
   786 {
   787     clistiter *cur;
   788 
   789     assert(name);
   790     assert(value);
   791 
   792     clist * list = content->ct_parameters;
   793     if (list == NULL)
   794         return false;
   795 
   796     for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
   797         struct mailmime_parameter * param = clist_content(cur);
   798         if (param &&
   799                 param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
   800                 param->pa_value && strcasecmp(value, param->pa_value) == 0)
   801             return true;
   802     }
   803 
   804     return false;
   805 }
   806 
   807 bool _is_multipart(struct mailmime_content *content, const char *subtype)
   808 {
   809     assert(content);
   810 
   811     if (content->ct_type && content->ct_type->tp_type ==
   812             MAILMIME_TYPE_COMPOSITE_TYPE &&
   813             content->ct_type->tp_data.tp_composite_type &&
   814             content->ct_type->tp_data.tp_composite_type->ct_type ==
   815             MAILMIME_COMPOSITE_TYPE_MULTIPART) {
   816         if (subtype)
   817             return content->ct_subtype &&
   818                     strcasecmp(content->ct_subtype, subtype) == 0;
   819         else
   820             return true;
   821     }
   822 
   823     return false;
   824 }
   825 
   826 bool _is_PGP_MIME(struct mailmime_content *content)
   827 {
   828     assert(content);
   829 
   830     if (_is_multipart(content, "encrypted") &&
   831             parameter_has_value(content, "protocol",
   832                     "application/pgp-encrypted"))
   833         return true;
   834 
   835     return false;
   836 }
   837 
   838 bool _is_text_part(struct mailmime_content *content, const char *subtype)
   839 {
   840     assert(content);
   841 
   842     if (content->ct_type && content->ct_type->tp_type ==
   843             MAILMIME_TYPE_DISCRETE_TYPE &&
   844             content->ct_type->tp_data.tp_discrete_type &&
   845             content->ct_type->tp_data.tp_discrete_type->dt_type ==
   846             MAILMIME_DISCRETE_TYPE_TEXT) {
   847         if (subtype)
   848             return content->ct_subtype &&
   849                     strcasecmp(content->ct_subtype, subtype) == 0;
   850         else
   851             return true;
   852     }
   853 
   854     return false;
   855 }
   856 
   857 bool _is_message_part(struct mailmime_content *content, const char* subtype) {
   858     assert(content);
   859     if (content->ct_type && content->ct_type->tp_type == MAILMIME_TYPE_COMPOSITE_TYPE &&
   860             content->ct_type->tp_data.tp_composite_type &&
   861             content->ct_type->tp_data.tp_composite_type->ct_type ==
   862             MAILMIME_COMPOSITE_TYPE_MESSAGE) {
   863         if (subtype)
   864             return content->ct_subtype &&
   865                     strcasecmp(content->ct_subtype, subtype) == 0;
   866         else
   867             return true;                
   868     }
   869     
   870     return false;
   871 }
   872 
   873 int _get_content_type(
   874         const struct mailmime_content *content,
   875         char **type,
   876         char **charset
   877     )
   878 {
   879     char *_type = NULL;
   880     char *_charset = NULL;
   881 
   882     assert(content);
   883     assert(type);
   884     assert(charset);
   885 
   886     *type = NULL;
   887     *charset = NULL;
   888 
   889     if (content->ct_subtype == NULL)
   890         return EINVAL;
   891 
   892     if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
   893         size_t len;
   894         const char *_main_type;
   895 
   896         switch  (content->ct_type->tp_data.tp_discrete_type->dt_type) {
   897             case MAILMIME_DISCRETE_TYPE_TEXT:
   898                 _main_type = (content->ct_subtype && 
   899                               strcasecmp(content->ct_subtype, "rfc822") == 0 ?
   900                               "message" : "text");
   901                 break;
   902             case MAILMIME_DISCRETE_TYPE_IMAGE:
   903                 _main_type = "image";
   904                 break;
   905             case MAILMIME_DISCRETE_TYPE_AUDIO:
   906                 _main_type = "audio";
   907                 break;
   908             case MAILMIME_DISCRETE_TYPE_VIDEO:
   909                 _main_type = "video";
   910                 break;
   911             case MAILMIME_DISCRETE_TYPE_APPLICATION:
   912                 _main_type = "application";
   913                 break;
   914             case MAILMIME_DISCRETE_TYPE_EXTENSION:
   915                 _main_type = "extension";
   916                 break;
   917             default:
   918                 return EINVAL;
   919         }
   920 
   921         len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
   922         _type = calloc(1, len);
   923         assert(_type);
   924         if (_type == NULL)
   925             return ENOMEM;
   926 
   927         strncpy(_type, _main_type, len);
   928         len -= strlen(_main_type);
   929         strncat(_type, "/", len--);
   930         strncat(_type, content->ct_subtype, len);
   931 
   932         if (content->ct_parameters) {
   933             clistiter *cur;
   934             for (cur = clist_begin(content->ct_parameters); cur; cur =
   935                     clist_next(cur)) {
   936                 struct mailmime_parameter * param = clist_content(cur);
   937                 if (param && param->pa_name && strcasecmp(param->pa_name,
   938                             "charset") == 0) {
   939                     _charset = param->pa_value;
   940                     break;
   941                 }
   942             }
   943             if (_charset)
   944                 *charset = strdup(_charset);
   945         }
   946 
   947         *type = _type;
   948         return 0;
   949     }
   950 
   951     return EINVAL;
   952 }
   953 
   954 // Only for null-terminated field strings.
   955 // can this field be transported as is without modification?)
   956 // (See rfc2822, section 2.2.3 - libetpan's handling isn't quite what
   957 // we need here.)
   958 bool must_field_value_be_encoded(const char* field_value) {
   959     if (!field_value)
   960         return false;
   961         
   962     return must_chunk_be_encoded((const void*)field_value, strlen(field_value), false);    
   963 }
   964 
   965 bool must_chunk_be_encoded(const void* value, size_t size, bool ignore_fws) {
   966 
   967     const char* begin_ptr = (const char*)value;    
   968 
   969     const char* end_ptr = begin_ptr + size;
   970 
   971     const char* cur_char_ptr = begin_ptr;
   972     while (cur_char_ptr < end_ptr) {
   973         char cur_char = *cur_char_ptr;
   974         if (cur_char > 127 || cur_char < 0)
   975             return true;
   976         // FIXME - do we need to deal with CRCRLF here?
   977         //         I guess in the worst case, it gets encoded, which
   978         //         is *supposed* to be harmless...
   979         if (!ignore_fws) {
   980             if (cur_char == '\r') {
   981                 const char* next = cur_char_ptr + 1;
   982                 const char* nextnext = next + 1;
   983                 if (next >= end_ptr || nextnext >= end_ptr
   984                     || *next != '\n'
   985                     || (*nextnext != ' ' && *nextnext != '\t')) {
   986                     return true;
   987                 }            
   988             }
   989             else if (cur_char == '\n') {
   990                 const char* prev = cur_char_ptr - 1;
   991                 if (prev == begin_ptr || *prev != '\r')
   992                     return true;
   993             }
   994         }
   995         cur_char_ptr++;
   996     }    
   997     return false;
   998 }
   999 
  1000 #define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
  1001 #ifdef _WIN32
  1002 #define PATH_SEP '\\'
  1003 #else
  1004 #define PATH_SEP '/'
  1005 #endif
  1006 
  1007 static PEP_STATUS interpret_MIME(struct mailmime *mime,
  1008                                  message *msg,
  1009                                  bool* has_possible_pEp_msg);
  1010 
  1011 // This function was rewritten to use in-memory buffers instead of
  1012 // temporary files when the pgp/mime support was implemented for
  1013 // outlook, as the existing code did not work well on windows.
  1014 
  1015 static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
  1016 {
  1017     PEP_STATUS status = PEP_STATUS_OK;
  1018     int col;
  1019     int r;
  1020 	size_t len;
  1021 	char* buf = NULL;
  1022 
  1023 	MMAPString* buffer;
  1024 
  1025 	buffer = mmap_string_new(NULL);
  1026 	if (buffer == NULL)
  1027 		goto enomem;
  1028 	
  1029 	col = 0;
  1030 	r = mailmime_write_mem(buffer, &col, mime);
  1031 	assert(r == MAILIMF_NO_ERROR);
  1032 	if (r == MAILIMF_ERROR_MEMORY)
  1033 		goto enomem;
  1034 	else if (r != MAILIMF_NO_ERROR)
  1035 		goto err_file;
  1036 
  1037 	// we overallocate by 1 byte, so we have a terminating 0.
  1038 	len = buffer->len;
  1039 	buf = calloc(len + 1, 1);
  1040 	if (buf == NULL)
  1041 		goto enomem;
  1042 
  1043 	memcpy(buf, buffer->str, len);
  1044 	mmap_string_free(buffer);
  1045 
  1046     *mimetext = buf;
  1047     return PEP_STATUS_OK;
  1048 
  1049 err_file:
  1050     status = PEP_CANNOT_CREATE_TEMP_FILE;
  1051     goto pEp_error;
  1052 
  1053 enomem:
  1054     status = PEP_OUT_OF_MEMORY;
  1055 
  1056 pEp_error:
  1057 	if (buffer)
  1058 		mmap_string_free(buffer);
  1059 	if (buf)
  1060 		free(buf);
  1061     return status;
  1062 }
  1063 
  1064 static PEP_STATUS mime_attachment(
  1065         bloblist_t *blob,
  1066         struct mailmime **result,
  1067         bool is_nf_message_attachment // non-forwarded msg as att
  1068     )
  1069 {
  1070     PEP_STATUS status = PEP_STATUS_OK;
  1071     struct mailmime * mime = NULL;
  1072     char * mime_type;
  1073     assert(blob);
  1074     assert(result);
  1075 
  1076     *result = NULL;
  1077 
  1078 // TODO: It seems the pEp COM server adapter sends an empty string here,
  1079 // which leads to a crash later. Thus, we workaround here by treating an
  1080 // empty string as NULL. We need to check whether the bug really is here,
  1081 // or the pEp COM server adapter needs to be changed.
  1082     if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
  1083         mime_type = "application/octet-stream";
  1084     else
  1085         mime_type = blob->mime_type;
  1086 
  1087     pEp_rid_list_t* resource = parse_uri(blob->filename);
  1088 
  1089     mime = get_file_part(resource, mime_type, blob->value, blob->size, 
  1090                          is_nf_message_attachment);
  1091     free_rid_list(resource);
  1092     
  1093     assert(mime);
  1094     if (mime == NULL)
  1095         goto enomem;
  1096 
  1097     *result = mime;
  1098     return PEP_STATUS_OK;
  1099 
  1100 enomem:
  1101     status = PEP_OUT_OF_MEMORY;
  1102 
  1103     if (mime)
  1104         mailmime_free(mime);
  1105 
  1106     return status;
  1107 }
  1108 
  1109 
  1110 // This ONLY deals with handling the body 
  1111 // content when html parts are present - thus,
  1112 // text/plain and text/html of the body, and 
  1113 // related inline attachments for the html 
  1114 // part. Non-inline attachments are handled 
  1115 // outside this call!!!!
  1116 //
  1117 // N.B. As a result, this will only touch the 
  1118 // "contained message" of pEp 2.x messages 
  1119 // on the initial encoding where it is turned 
  1120 // into attachment data!!
  1121 static PEP_STATUS mime_html_text(
  1122         const char *plaintext,
  1123         const char *htmltext,
  1124         bloblist_t *attachments,
  1125         struct mailmime **result
  1126     )
  1127 {
  1128     PEP_STATUS status = PEP_STATUS_OK;
  1129     struct mailmime * top_level_html_mime = NULL;
  1130     struct mailmime * mime = NULL;
  1131     struct mailmime * submime = NULL;
  1132     int r;
  1133 
  1134     assert(plaintext);
  1135     assert(htmltext);
  1136     assert(result);
  1137 
  1138     *result = NULL;
  1139 
  1140     pEp_rid_list_t* resource = NULL;
  1141         
  1142     bool already_ascii = false;
  1143     int encoding_type = 0;    
  1144     if (*plaintext != '\0') {
  1145         mime = part_multiple_new("multipart/alternative");
  1146         assert(mime);
  1147         if (mime == NULL)
  1148             goto enomem;
  1149             
  1150         // KB: pEpMIME transition comment - if we start getting 
  1151         // underencoding errors here, the change to checking 
  1152         // for ASCII and then encoding - or not - is one place 
  1153         // to start looking.
  1154         int pt_length = strlen(plaintext);
  1155         already_ascii = !(must_chunk_be_encoded(plaintext, pt_length, true));                
  1156         encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  1157                 
  1158         submime = get_text_part(NULL, "text/plain", plaintext, 
  1159                                 pt_length,
  1160                                 encoding_type);
  1161         
  1162         // reset                        
  1163         already_ascii = false;
  1164         encoding_type = 0;
  1165                                     
  1166         free_rid_list(resource);
  1167         resource = NULL;
  1168         
  1169         assert(submime);
  1170         if (submime == NULL)
  1171             goto enomem;
  1172 
  1173         r = mailmime_smart_add_part(mime, submime);
  1174         assert(r == MAILIMF_NO_ERROR);
  1175         if (r == MAILIMF_ERROR_MEMORY) {
  1176             goto enomem;
  1177         }
  1178         else {
  1179             // mailmime_smart_add_part() takes ownership of submime
  1180             submime = NULL;
  1181         }
  1182     }
  1183     
  1184     bool inlined_attachments = false;
  1185     
  1186     bloblist_t* traversal_ptr = attachments;
  1187     
  1188     while (traversal_ptr) {
  1189         if (traversal_ptr->disposition == PEP_CONTENT_DISP_INLINE) {
  1190             inlined_attachments = true;
  1191             break;
  1192         }
  1193         traversal_ptr = traversal_ptr->next;
  1194     }
  1195 
  1196     if (inlined_attachments) {
  1197         /* Noooooo... dirk, why do you do this to me? */
  1198         submime = part_multiple_new("multipart/related");
  1199         assert(submime);
  1200         if (submime == NULL)
  1201             goto enomem;
  1202 
  1203         // This is where all of the html MIME stuff will go
  1204         top_level_html_mime = submime;
  1205         
  1206         if (!mime)
  1207             mime = top_level_html_mime;
  1208         else {    
  1209             r = mailmime_smart_add_part(mime, top_level_html_mime);
  1210             assert(r == MAILIMF_NO_ERROR);
  1211             if (r == MAILIMF_ERROR_MEMORY) {
  1212                 goto enomem;
  1213             }
  1214             else {
  1215                 // mailmime_smart_add_part() takes ownership of submime
  1216                 submime = NULL;
  1217             }
  1218         }    
  1219     }
  1220     else {
  1221         // Otherwise, html MIME stuff gets added to the top node 
  1222         // - may be NULL if there's no multipart!
  1223         top_level_html_mime = mime;
  1224     }
  1225 
  1226 //    resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
  1227     int ht_length = strlen(htmltext);
  1228     already_ascii = !(must_chunk_be_encoded(htmltext, ht_length, true));                
  1229     encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  1230             
  1231     submime = get_text_part(NULL, "text/html", htmltext, 
  1232                             ht_length,
  1233                             encoding_type);
  1234 
  1235     free_rid_list(resource);
  1236     resource = NULL;
  1237     
  1238     assert(submime);
  1239     if (submime == NULL)
  1240         goto enomem;
  1241         
  1242     // IF there are no inlined attachments AND mime is NULL, then 
  1243     // we just have an HTML body here and won't need to 
  1244     // process inlined attachments - submime will actually be 
  1245     // the mime root of from this function, at least.    
  1246 
  1247     if (!top_level_html_mime) {
  1248         mime = submime;
  1249         submime = NULL;
  1250     }
  1251     else {    
  1252         r = mailmime_smart_add_part(top_level_html_mime, submime);
  1253         assert(r == MAILIMF_NO_ERROR);
  1254         if (r == MAILIMF_ERROR_MEMORY)
  1255             goto enomem;
  1256         else {
  1257             // mailmime_smart_add_part() takes ownership of submime
  1258             submime = NULL;
  1259         }
  1260 
  1261         bloblist_t *_a;
  1262 
  1263         // This will never have an embedded pEp message attachment 
  1264         // sent for encoding here, so we don't need to pass down 
  1265         // "(don't) transport encode this" info. If it's here and 
  1266         // it's not an ASCII "text/*" attachment, it'll get encoded
  1267         for (_a = attachments; _a != NULL; _a = _a->next) {
  1268             if (_a->disposition != PEP_CONTENT_DISP_INLINE)
  1269                 continue;
  1270             status = mime_attachment(_a, &submime, false);
  1271             if (status != PEP_STATUS_OK)
  1272                 return PEP_UNKNOWN_ERROR; // FIXME
  1273 
  1274             r = mailmime_smart_add_part(top_level_html_mime, submime);
  1275             assert(r == MAILIMF_NO_ERROR);
  1276             if (r == MAILIMF_ERROR_MEMORY) {
  1277                 goto enomem;
  1278             }
  1279             else {
  1280                 // mailmime_smart_add_part() takes ownership of submime
  1281                 submime = NULL;
  1282             }
  1283         }
  1284     }    
  1285     *result = mime;
  1286     return PEP_STATUS_OK;
  1287 
  1288 enomem:
  1289     status = PEP_OUT_OF_MEMORY;
  1290 
  1291     if (mime)
  1292         mailmime_free(mime);
  1293 
  1294     if (submime)
  1295         mailmime_free(submime);
  1296 
  1297     return status;
  1298 }
  1299 
  1300 
  1301 static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
  1302 {
  1303     char *_username = NULL;
  1304     struct mailimf_mailbox *mb;
  1305 
  1306     if (!ident->username)
  1307         _username = strdup("");
  1308     else
  1309         _username = must_field_value_be_encoded(ident->username) ?
  1310                     mailmime_encode_subject_header("utf-8", ident->username, 0) : 
  1311                     strdup(ident->username);
  1312                   
  1313     assert(_username);
  1314     if (_username == NULL)
  1315         goto enomem;
  1316 
  1317     mb = mailbox_from_string(_username, ident->address);
  1318     if (mb == NULL)
  1319         goto enomem;
  1320 
  1321     free(_username);
  1322     _username = NULL;
  1323 
  1324     return mb;
  1325 
  1326 enomem:
  1327     free(_username);
  1328     return NULL;
  1329 }
  1330 
  1331 static struct mailimf_mailbox_list * identity_to_mbl(
  1332         const pEp_identity *ident)
  1333 {
  1334     struct mailimf_mailbox_list *mbl = NULL;
  1335     struct mailimf_mailbox *mb = NULL;
  1336     clist *list = NULL;
  1337     int r;
  1338 
  1339     assert(ident);
  1340 
  1341     list = clist_new();
  1342     if (list == NULL)
  1343         goto enomem;
  1344 
  1345     mb = identity_to_mailbox(ident);
  1346     if (mb == NULL)
  1347         goto enomem;
  1348 
  1349     r = clist_append(list, mb);
  1350     if (r)
  1351         goto enomem;
  1352 
  1353     mbl = mailimf_mailbox_list_new(list);
  1354     if (mbl == NULL)
  1355         goto enomem;
  1356 
  1357     return mbl;
  1358 
  1359 enomem:
  1360     if (mb)
  1361         mailimf_mailbox_free(mb);
  1362 
  1363     if (list)
  1364         clist_free(list);
  1365 
  1366     return NULL;
  1367 }
  1368 
  1369 static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
  1370 {
  1371     struct mailimf_address_list *mal = NULL;
  1372     struct mailimf_mailbox *mb = NULL;
  1373     struct mailimf_address * addr = NULL;
  1374     clist *list = NULL;
  1375     int r;
  1376 
  1377     assert(il);
  1378 
  1379     list = clist_new();
  1380     if (list == NULL)
  1381         goto enomem;
  1382 
  1383     identity_list *_il;
  1384     for (_il = il; _il && _il->ident; _il = _il->next) {
  1385         mb = identity_to_mailbox(_il->ident);
  1386         if (mb == NULL)
  1387             goto enomem;
  1388 
  1389         addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
  1390         if (addr == NULL)
  1391             goto enomem;
  1392         mb = NULL;
  1393 
  1394         r = clist_append(list, addr);
  1395         if (r)
  1396             goto enomem;
  1397         addr = NULL;
  1398     }
  1399     mal = mailimf_address_list_new(list);
  1400     if (mal == NULL)
  1401         goto enomem;
  1402 
  1403     return mal;
  1404 
  1405 enomem:
  1406     if (mb)
  1407         mailimf_mailbox_free(mb);
  1408 
  1409     if (addr)
  1410         mailimf_address_free(addr);
  1411 
  1412     if (list)
  1413         clist_free(list);
  1414 
  1415     return NULL;
  1416 }
  1417 
  1418 // KB: This seems to be always called with "true",
  1419 //     but there was probably a reason for this. So 
  1420 //     leave it for now.
  1421 static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
  1422 {
  1423     clist * cl = clist_new();
  1424     assert(cl);
  1425     if (cl == NULL)
  1426         return NULL;
  1427 
  1428     if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
  1429         return cl;
  1430         
  1431     stringlist_t *_sl;
  1432     for (_sl = sl; _sl; _sl = _sl->next) {
  1433         int r;
  1434         char * value = ((transport_encode && must_field_value_be_encoded(_sl->value)) ?
  1435                         mailmime_encode_subject_header("utf-8", _sl->value, 0) :
  1436                         strdup(_sl->value));
  1437         assert(value);
  1438         if (value == NULL) {
  1439             clist_free(cl);
  1440             return NULL;
  1441         }
  1442         r = clist_append(cl, value);
  1443         assert(r == 0);
  1444         if (r) {
  1445             free(value);
  1446             clist_free(cl);
  1447             return NULL;
  1448         }
  1449     }
  1450 
  1451     return cl;
  1452 }
  1453 
  1454 static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
  1455 {
  1456     PEP_STATUS status = PEP_STATUS_OK;
  1457     struct mailimf_fields * fields = NULL;
  1458     int r;
  1459     clist * fields_list = NULL;
  1460     unsigned char pEpstr[] = PEP_SUBJ_STRING; // unsigned due to UTF-8 byte fun
  1461 #ifdef WIN32
  1462     char* altstr = "pEp";
  1463 #else
  1464     char* altstr = (char*)pEpstr;
  1465 #endif        
  1466     char *subject = msg->shortmsg && msg->shortmsg[0] ? msg->shortmsg : altstr;
  1467 
  1468     assert(msg);
  1469     assert(result);
  1470 
  1471     *result = NULL;
  1472 
  1473     fields_list = clist_new();
  1474     assert(fields_list);
  1475     if (fields_list == NULL)
  1476         goto enomem;
  1477 
  1478     if (msg->id && msg->id[0]) {
  1479         char *_msgid = strdup(msg->id);
  1480         assert(_msgid);
  1481         if (_msgid == NULL)
  1482             goto enomem;
  1483 
  1484         r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
  1485                 (_new_func_t) mailimf_message_id_new, _msgid);
  1486         if (r) {
  1487             free(_msgid);
  1488             goto enomem;
  1489         }
  1490     }
  1491 
  1492     if (msg->sent) {
  1493         struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
  1494         if (dt == NULL)
  1495             goto enomem;
  1496 
  1497         r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
  1498                 (_new_func_t) mailimf_orig_date_new, dt);
  1499         if (r) {
  1500             mailimf_date_time_free(dt);
  1501             goto enomem;
  1502         }
  1503         dt = NULL;
  1504     }
  1505 
  1506      if (msg->from) {
  1507         struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
  1508         if (from == NULL)
  1509             goto enomem;
  1510 
  1511         r = _append_field(fields_list, MAILIMF_FIELD_FROM,
  1512                 (_new_func_t) mailimf_from_new, from);
  1513         if (r) {
  1514             mailimf_mailbox_list_free(from);
  1515             goto enomem;
  1516         }
  1517     }
  1518 
  1519     if (msg->to && msg->to->ident) {
  1520         struct mailimf_address_list *to = identity_list_to_mal(msg->to);
  1521         if (to == NULL)
  1522             goto enomem;
  1523 
  1524         r = _append_field(fields_list, MAILIMF_FIELD_TO,
  1525                 (_new_func_t) mailimf_to_new, to);
  1526         if (r) {
  1527             mailimf_address_list_free(to);
  1528             goto enomem;
  1529         }
  1530     }
  1531 
  1532     char* _subject = NULL;
  1533     if (!must_field_value_be_encoded(subject)) {
  1534         _subject = strdup(subject);
  1535         assert(_subject);
  1536     }
  1537     else {
  1538         _subject = mailmime_encode_subject_header("utf-8", subject, 1);
  1539     }
  1540     if (_subject == NULL)
  1541         goto enomem;
  1542 
  1543     r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
  1544             (_new_func_t) mailimf_subject_new, _subject);
  1545     if (r) {
  1546         free(_subject);
  1547         goto enomem;
  1548     }
  1549 
  1550     if (msg->cc && msg->cc->ident) {
  1551         struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
  1552         if (cc == NULL)
  1553             goto enomem;
  1554 
  1555         r = _append_field(fields_list, MAILIMF_FIELD_CC,
  1556                 (_new_func_t) mailimf_cc_new, cc);
  1557         if (r) {
  1558             mailimf_address_list_free(cc);
  1559             goto enomem;
  1560         }
  1561     }
  1562     
  1563     if (msg->bcc && msg->bcc->ident) {
  1564         struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
  1565         if (bcc == NULL)
  1566             goto enomem;
  1567 
  1568         r = _append_field(fields_list, MAILIMF_FIELD_BCC,
  1569                 (_new_func_t) mailimf_bcc_new, bcc);
  1570         if (r) {
  1571             mailimf_address_list_free(bcc);
  1572             goto enomem;
  1573         }
  1574     }
  1575     
  1576     if (msg->reply_to && msg->reply_to->ident) {
  1577         struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
  1578         if (reply_to == NULL)
  1579             goto enomem;
  1580 
  1581         r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
  1582                 (_new_func_t) mailimf_reply_to_new, reply_to);
  1583         if (r) {
  1584             mailimf_address_list_free(reply_to);
  1585             goto enomem;
  1586         }
  1587     }
  1588 
  1589     if (msg->in_reply_to && msg->in_reply_to->value) {
  1590         clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
  1591         if (in_reply_to == NULL)
  1592             goto enomem;
  1593 
  1594         r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
  1595                 (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
  1596         if (r) {
  1597             clist_free(in_reply_to);
  1598             goto enomem;
  1599         }
  1600     }
  1601 
  1602     if (msg->references && msg->references->value) {
  1603         clist *references = stringlist_to_clist(msg->references, true);
  1604         if (references == NULL)
  1605             goto enomem;
  1606 
  1607         r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
  1608                 (_new_func_t) mailimf_references_new, references);
  1609         if (r) {
  1610             clist_free(references);
  1611             goto enomem;
  1612         }
  1613     }
  1614 
  1615     if (msg->keywords && msg->keywords->value) {
  1616         clist *keywords = stringlist_to_clist(msg->keywords, true);
  1617         if (keywords == NULL)
  1618             goto enomem;
  1619 
  1620         r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
  1621                 (_new_func_t) mailimf_keywords_new, keywords);
  1622         if (r) {
  1623             clist_free(keywords);
  1624             goto enomem;
  1625         }
  1626     }
  1627 
  1628     if (msg->comments && msg->comments[0]) {
  1629         char *comments = NULL;
  1630         if (!must_field_value_be_encoded(msg->comments)) {
  1631             comments = strdup(msg->comments);
  1632             assert(comments);
  1633         }
  1634         else  {
  1635             comments = mailmime_encode_subject_header("utf-8", msg->comments, 0);
  1636         }
  1637         if (comments == NULL)
  1638             goto enomem;
  1639 
  1640         r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
  1641                 (_new_func_t) mailimf_comments_new, comments);
  1642         if (r) {
  1643             free(comments);
  1644             goto enomem;
  1645         }
  1646     }
  1647 
  1648     if (msg->opt_fields && msg->opt_fields->value) {
  1649         stringpair_list_t *_l;
  1650         for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
  1651             char *key = _l->value->key;
  1652             char *value = _l->value->value;
  1653             if (key && value) {
  1654                 r = _append_optional_field(fields_list, key, value);
  1655 
  1656                 if (r)
  1657                     goto enomem;
  1658             }
  1659         }
  1660     }
  1661 
  1662     fields = mailimf_fields_new(fields_list);
  1663     assert(fields);
  1664     if (fields == NULL)
  1665         goto enomem;
  1666 
  1667     *result = fields;
  1668 
  1669     return PEP_STATUS_OK;
  1670 
  1671 enomem:
  1672     status = PEP_OUT_OF_MEMORY;
  1673 
  1674     if (fields_list)
  1675         clist_free(fields_list);
  1676 
  1677     if (fields)
  1678         mailimf_fields_free(fields);
  1679 
  1680     return status;
  1681 }
  1682 
  1683 static bool has_exceptional_extension(char* filename) {
  1684     if (!filename)
  1685         return false;
  1686     int len = strlen(filename);
  1687     if (len < 4)
  1688         return false;
  1689     char* ext_start = filename + (len - 4);
  1690     if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
  1691         strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
  1692         return true;
  1693     return false;
  1694 }
  1695 
  1696 static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
  1697     pEp_rid_list_t* retval = rid_list;
  1698     
  1699     /* multiple elements - least common case */
  1700     if (rid_list && rid_list->next) {
  1701         pEp_rid_list_t* rid_list_curr = rid_list;
  1702         retval = rid_list; 
  1703         
  1704         while (rid_list_curr) {
  1705             pEp_resource_id_type rid_type = rid_list_curr->rid_type;
  1706             if (rid_type == PEP_RID_CID)
  1707                 retval = rid_list_curr;
  1708             else if (rid_type == PEP_RID_FILENAME && has_exceptional_extension(rid_list_curr->rid))
  1709                 return rid_list_curr;
  1710             rid_list_curr = rid_list_curr->next;
  1711         }
  1712     } 
  1713     return retval;
  1714 }
  1715 
  1716 // static void split_inlined_and_attached(bloblist_t** inlined, bloblist_t** attached) {
  1717 //     bloblist_t** curr_pp = attached;
  1718 //     bloblist_t* curr = *curr_pp;
  1719 //     
  1720 //     bloblist_t* inline_ret = NULL;
  1721 //     bloblist_t** inline_curr_pp = &inline_ret;
  1722 //     
  1723 //     bloblist_t* att_ret = NULL;
  1724 //     bloblist_t** att_curr_pp = &att_ret;
  1725 //     
  1726 //     while (curr) {
  1727 //         if (curr->disposition == PEP_CONTENT_DISP_INLINE) {
  1728 //             *inline_curr_pp = curr;
  1729 //             inline_curr_pp = &(curr->next);
  1730 //         }
  1731 //         else {
  1732 //             *att_curr_pp = curr;
  1733 //             att_curr_pp = &(curr->next);            
  1734 //         }
  1735 //         *curr_pp = curr->next;
  1736 //         curr->next = NULL;
  1737 //         curr = *curr_pp;
  1738 //     }
  1739 //     
  1740 //     *inlined = inline_ret;
  1741 //     *attached = att_ret;
  1742 // }
  1743 
  1744 
  1745 static PEP_STATUS mime_encode_message_plain(
  1746         const message *msg,
  1747         bool omit_fields,
  1748         struct mailmime **result,
  1749         bool has_pEp_msg_attachment
  1750     )
  1751 {
  1752     struct mailmime * mime = NULL;
  1753     struct mailmime * submime = NULL;
  1754     int r;
  1755     PEP_STATUS status;
  1756     //char *subject;
  1757     const char *plaintext;
  1758     char *htmltext;
  1759 
  1760     assert(msg);
  1761     assert(result);
  1762 
  1763     // * Process body content, including html's inlined attachments *
  1764     plaintext = (msg->longmsg) ? msg->longmsg : "";
  1765     htmltext = msg->longmsg_formatted;
  1766 
  1767     if (htmltext && (htmltext[0] != '\0')) {
  1768         /* first, we need to strip out the inlined attachments to ensure this
  1769            gets set up correctly */
  1770            
  1771         // Note: this only, regardless of whether this is being done 
  1772         // for the to-be-embedded message attachment generation or 
  1773         // an encapsulating message which contains this, touches 
  1774         // the body text of this input message. So transport encoding 
  1775         // only refers to the body content here and inlined-attachments, and 
  1776         // is decided WITHIN this function, not as an argument. 
  1777         status = mime_html_text(plaintext, htmltext, msg->attachments, &mime);
  1778                 
  1779         if (status != PEP_STATUS_OK)
  1780             goto pEp_error;
  1781     }
  1782     else { /* body content only consists of a plaintext block */
  1783         pEp_rid_list_t* resource = NULL;
  1784 
  1785         int pt_length = strlen(plaintext);
  1786 
  1787         if (is_PGP_message_text(plaintext)) {
  1788             resource = NULL;
  1789             
  1790             // So... I think we got overencoding here once, which would be a bug 
  1791             // in libetpan, unless it had to do with whitespace. If removing
  1792             // transport encoding as a calculation here somehow leads to overencoding,
  1793             // either we or libetpan are doing something bad.
  1794 //            int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
  1795             mime = get_text_part(resource, "application/octet-stream", plaintext,
  1796                                  pt_length, MAILMIME_MECHANISM_7BIT);
  1797         }
  1798         else {
  1799             resource = NULL;
  1800             bool already_ascii = !(must_chunk_be_encoded(plaintext, pt_length, true));                
  1801             int encoding_type = (already_ascii ? MAILMIME_MECHANISM_7BIT : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  1802             mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
  1803                     encoding_type);
  1804         }
  1805         free_rid_list(resource);
  1806         
  1807         assert(mime);
  1808         if (mime == NULL)
  1809             goto enomem;
  1810     }
  1811 
  1812     /* Body content processed, now process normal attachments */
  1813     
  1814     bool normal_attachments = false;
  1815     
  1816     bloblist_t* traversal_ptr = msg->attachments;
  1817     
  1818     // If there were any inline attachments, they should have 
  1819     // been stripped out in mime_html_text and dealt with. 
  1820     // I'm not entirely sure what the alternative case 
  1821     // is here. But basically, if there are any non-inlined 
  1822     // attachments to deal with, this is designed to 
  1823     // make sure we process them. So flag it for 
  1824     // "hey, Bob, you got some regular attachments here"
  1825     // so Bob (obviously, the MIME engine is called Bob)
  1826     // can do the right thing in the next block.
  1827     while (traversal_ptr) {
  1828         if (traversal_ptr->disposition != PEP_CONTENT_DISP_INLINE) {
  1829             normal_attachments = true;
  1830             break;
  1831         }
  1832         traversal_ptr = traversal_ptr->next;
  1833     }
  1834 
  1835     if (normal_attachments) {
  1836         submime = mime;
  1837         mime = part_multiple_new("multipart/mixed");
  1838         assert(mime);
  1839         if (mime == NULL)
  1840             goto enomem;
  1841 
  1842         r = mailmime_smart_add_part(mime, submime);
  1843         assert(r == MAILIMF_NO_ERROR);
  1844         if (r == MAILIMF_ERROR_MEMORY) {
  1845             goto enomem;
  1846         }
  1847         else {
  1848             // mailmime_smart_add_part() takes ownership of submime
  1849             submime = NULL;
  1850         }
  1851 
  1852         bloblist_t *_a;
  1853         bool first_one = true;
  1854         
  1855         // Go through the non-inline attachments and add em.
  1856         for (_a = msg->attachments; _a != NULL; _a = _a->next) {
  1857 
  1858             if (_a->disposition == PEP_CONTENT_DISP_INLINE)
  1859                 continue;
  1860 
  1861             // solely for readability.
  1862             bool is_pEp_msg_attachment = (first_one && has_pEp_msg_attachment);
  1863 
  1864             status = mime_attachment(_a, &submime, 
  1865                                      is_pEp_msg_attachment);                         
  1866 
  1867             if (status != PEP_STATUS_OK)
  1868                 goto pEp_error;
  1869             
  1870             first_one = false;    
  1871 
  1872             r = mailmime_smart_add_part(mime, submime);
  1873             assert(r == MAILIMF_NO_ERROR);
  1874             if (r == MAILIMF_ERROR_MEMORY) {
  1875                 goto enomem;
  1876             }
  1877             else {
  1878                 // mailmime_smart_add_part() takes ownership of submime
  1879                 submime = NULL;
  1880             }
  1881         }
  1882     }
  1883 
  1884     *result = mime;
  1885     return PEP_STATUS_OK;
  1886 
  1887 enomem:
  1888     status = PEP_OUT_OF_MEMORY;
  1889 
  1890 pEp_error:
  1891     if (mime)
  1892         mailmime_free(mime);
  1893 
  1894     if (submime)
  1895         mailmime_free(submime);
  1896 
  1897     return status;
  1898 }
  1899 
  1900 static PEP_STATUS mime_encode_message_PGP_MIME(
  1901         const message * msg,
  1902         bool omit_fields,
  1903         struct mailmime **result
  1904     )
  1905 {
  1906     struct mailmime * mime = NULL;
  1907     struct mailmime * submime = NULL;
  1908 	struct mailmime_parameter * param;
  1909     int r;
  1910     PEP_STATUS status;
  1911     char *plaintext;
  1912     size_t plaintext_size;
  1913 
  1914     assert(msg->attachments && msg->attachments->next &&
  1915             msg->attachments->next->value);
  1916 
  1917     plaintext = msg->attachments->next->value;
  1918     plaintext_size = msg->attachments->next->size;
  1919 
  1920     mime = part_multiple_new("multipart/encrypted");
  1921     assert(mime);
  1922     if (mime == NULL)
  1923         goto enomem;
  1924 
  1925     param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
  1926     clist_append(mime->mm_content_type->ct_parameters, param);
  1927 
  1928     submime = get_pgp_encrypted_part();
  1929     assert(submime);
  1930     if (submime == NULL)
  1931         goto enomem;
  1932 
  1933     r = mailmime_smart_add_part(mime, submime);
  1934     assert(r == MAILIMF_NO_ERROR);
  1935     if (r == MAILIMF_ERROR_MEMORY) {
  1936         goto enomem;
  1937     }
  1938     else {
  1939         // mailmime_smart_add_part() takes ownership of submime
  1940         submime = NULL;
  1941     }
  1942 
  1943     pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
  1944     submime = get_text_part(resource, "application/octet-stream", plaintext,
  1945             plaintext_size, MAILMIME_MECHANISM_7BIT);
  1946             
  1947     free_rid_list(resource);
  1948     
  1949     assert(submime);
  1950     if (submime == NULL)
  1951         goto enomem;
  1952 
  1953     r = mailmime_smart_add_part(mime, submime);
  1954     assert(r == MAILIMF_NO_ERROR);
  1955     if (r == MAILIMF_ERROR_MEMORY) {
  1956         goto enomem;
  1957     }
  1958     else {
  1959         // mailmime_smart_add_part() takes ownership of submime
  1960         submime = NULL;
  1961     }
  1962 
  1963     *result = mime;
  1964     return PEP_STATUS_OK;
  1965 
  1966 enomem:
  1967     status = PEP_OUT_OF_MEMORY;
  1968 
  1969     if (mime)
  1970         mailmime_free(mime);
  1971 
  1972     if (submime)
  1973         mailmime_free(submime);
  1974 
  1975     return status;
  1976 }
  1977 
  1978 DYNAMIC_API PEP_STATUS mime_encode_message(
  1979         const message * msg,
  1980         bool omit_fields,
  1981         char **mimetext,
  1982         bool has_pEp_msg_attachment
  1983     )
  1984 {
  1985     PEP_STATUS status = PEP_STATUS_OK;
  1986     struct mailmime * msg_mime = NULL;
  1987     struct mailmime * mime = NULL;
  1988     struct mailimf_fields * fields = NULL;
  1989     char *buf = NULL;
  1990     int r;
  1991 
  1992     assert(msg);
  1993     assert(mimetext);
  1994 
  1995     if (!(msg && mimetext))
  1996         return PEP_ILLEGAL_VALUE;
  1997 
  1998     *mimetext = NULL;
  1999 
  2000     switch (msg->enc_format) {
  2001         case PEP_enc_none:
  2002             status = mime_encode_message_plain(msg, omit_fields, &mime, has_pEp_msg_attachment);
  2003             break;
  2004 
  2005         // I'm presuming we should hardcore ignoring has_pEp_msg_attachment here...
  2006         case PEP_enc_inline:
  2007             status = mime_encode_message_plain(msg, omit_fields, &mime, false);
  2008             break;
  2009 
  2010         case PEP_enc_S_MIME:
  2011             NOT_IMPLEMENTED
  2012                 
  2013         case PEP_enc_PGP_MIME:
  2014             status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
  2015             break;
  2016 
  2017         case PEP_enc_PEP:
  2018             // today's pEp message format is PGP/MIME from the outside
  2019             status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
  2020             break;
  2021 
  2022         default:
  2023             NOT_IMPLEMENTED
  2024     }
  2025 
  2026     if (status != PEP_STATUS_OK)
  2027         goto pEp_error;
  2028 
  2029     msg_mime = mailmime_new_message_data(NULL);
  2030     assert(msg_mime);
  2031     if (msg_mime == NULL)
  2032         goto enomem;
  2033 
  2034     r = mailmime_add_part(msg_mime, mime);
  2035     if (r) {
  2036         mailmime_free(mime);
  2037         goto enomem;
  2038     }
  2039     mime = NULL;
  2040 
  2041     if (!omit_fields) {
  2042         status = build_fields(msg, &fields);
  2043         if (status != PEP_STATUS_OK)
  2044             goto pEp_error;
  2045 
  2046         mailmime_set_imf_fields(msg_mime, fields);
  2047     }
  2048 
  2049     status = render_mime(msg_mime, &buf);
  2050     if (status != PEP_STATUS_OK)
  2051         goto pEp_error;
  2052 
  2053     mailmime_free(msg_mime);
  2054     *mimetext = buf;
  2055 
  2056     return PEP_STATUS_OK;
  2057 
  2058 enomem:
  2059     status = PEP_OUT_OF_MEMORY;
  2060 
  2061 pEp_error:
  2062     if (msg_mime)
  2063         mailmime_free(msg_mime);
  2064     else
  2065         if (mime)
  2066             mailmime_free(mime);
  2067 
  2068     return status;
  2069 }
  2070 
  2071 static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
  2072 {
  2073     char *username = NULL;
  2074 
  2075     assert(mb);
  2076     assert(mb->mb_addr_spec);
  2077 
  2078     if (mb->mb_addr_spec == NULL)
  2079         return NULL;
  2080 
  2081     if (mb->mb_display_name) {
  2082         size_t index = 0;
  2083         const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
  2084                 strlen(mb->mb_display_name), &index, "utf-8", &username);
  2085         if (r)
  2086             goto enomem;
  2087     }
  2088 
  2089     pEp_identity *ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
  2090     if (ident == NULL)
  2091         goto enomem;
  2092     free(username);
  2093 
  2094     return ident;
  2095 
  2096 enomem:
  2097     free(username);
  2098     return NULL;
  2099 }
  2100 
  2101 static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
  2102 {
  2103     struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
  2104     return mailbox_to_identity(mb);
  2105 }
  2106 
  2107 static identity_list * mal_to_identity_list(
  2108         const struct mailimf_address_list *mal
  2109     )
  2110 {
  2111     identity_list *il = new_identity_list(NULL);
  2112     if (il == NULL)
  2113         goto enomem;
  2114 
  2115     // if we have nothing to translate then return an empty list
  2116     if (!mal)
  2117         return il;
  2118 
  2119     clist *list = mal->ad_list;
  2120 
  2121     identity_list *_il = il;
  2122     for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
  2123         pEp_identity *ident;
  2124 
  2125         struct mailimf_address *addr = clist_content(cur);
  2126         switch(addr->ad_type) {
  2127             case MAILIMF_ADDRESS_MAILBOX:
  2128                 ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
  2129                 if (ident == NULL)
  2130                     goto enomem;
  2131                 _il = identity_list_add(_il, ident);
  2132                 if (_il == NULL)
  2133                     goto enomem;
  2134                 break;
  2135 
  2136             case MAILIMF_ADDRESS_GROUP:
  2137                 {
  2138                     struct mailimf_mailbox_list * mbl =
  2139                             addr->ad_data.ad_group->grp_mb_list;
  2140                     for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
  2141                             cur2 = clist_next(cur2)) {
  2142                         ident = mailbox_to_identity(clist_content(cur));
  2143                         if (ident == NULL)
  2144                             goto enomem;
  2145                         _il = identity_list_add(_il, ident);
  2146                         if (_il == NULL)
  2147                             goto enomem;
  2148                     }
  2149                 }
  2150                 break;
  2151 
  2152             default:
  2153                 assert(0);
  2154                 goto enomem;
  2155         }
  2156     }
  2157 
  2158     return il;
  2159 
  2160 enomem:
  2161     free_identity_list(il);
  2162     return NULL;
  2163 }
  2164 
  2165 static stringlist_t * clist_to_stringlist(const clist *list)
  2166 {
  2167     char *text = NULL;;
  2168     stringlist_t * sl = new_stringlist(NULL);
  2169     if (sl == NULL)
  2170         return NULL;
  2171 
  2172     stringlist_t *_sl = sl;
  2173     for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
  2174         char *phrase = clist_content(cur);
  2175         size_t index = 0;
  2176         
  2177         const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
  2178                 &index, "utf-8", &text);
  2179         if (r)
  2180             goto enomem;
  2181 
  2182         _sl = stringlist_add(_sl, text);
  2183         if (_sl == NULL)
  2184             goto enomem;
  2185 
  2186         free(text);
  2187         text = NULL;
  2188     }
  2189 
  2190     return sl;
  2191 
  2192 enomem:
  2193     free_stringlist(sl);
  2194     free(text);
  2195 
  2196     return NULL;
  2197 }
  2198 
  2199 static PEP_STATUS read_fields(message *msg, clist *fieldlist)
  2200 {
  2201     PEP_STATUS status = PEP_STATUS_OK;
  2202     struct mailimf_field * _field;
  2203     clistiter *cur;
  2204     size_t index;
  2205     int r;
  2206     
  2207     stringpair_list_t *opt = msg->opt_fields;
  2208 
  2209     if (!fieldlist)
  2210         return PEP_STATUS_OK;
  2211         
  2212     for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
  2213         _field = clist_content(cur);
  2214 
  2215         switch (_field->fld_type) {
  2216             case MAILIMF_FIELD_MESSAGE_ID:
  2217                 {
  2218                     char * text = _field->fld_data.fld_message_id->mid_value;
  2219 
  2220                     free(msg->id);
  2221                     index = 0;
  2222                     r = mailmime_encoded_phrase_parse("utf-8", text,
  2223                             strlen(text), &index, "utf-8", &msg->id);
  2224                     if (r)
  2225                         goto enomem;
  2226                 }
  2227                 break;
  2228 
  2229             case MAILIMF_FIELD_SUBJECT:
  2230                 {
  2231                     char * text = _field->fld_data.fld_subject->sbj_value;
  2232 
  2233                     free(msg->shortmsg);
  2234                     index = 0;
  2235                     r = mailmime_encoded_phrase_parse("utf-8", text,
  2236                             strlen(text), &index, "utf-8", &msg->shortmsg);
  2237                     if (r)
  2238                         goto enomem;
  2239                 }
  2240                 break;
  2241 
  2242             case MAILIMF_FIELD_ORIG_DATE:
  2243                 {
  2244                     struct mailimf_date_time *date =
  2245                         _field->fld_data.fld_orig_date->dt_date_time;
  2246 
  2247                     free_timestamp(msg->sent);
  2248                     msg->sent = etpantime_to_timestamp(date);
  2249                     if (msg->sent == NULL)
  2250                         goto enomem;
  2251                 }
  2252                 break;
  2253 
  2254             case MAILIMF_FIELD_FROM:
  2255                 {
  2256                     struct mailimf_mailbox_list *mbl =
  2257                             _field->fld_data.fld_from->frm_mb_list;
  2258                     pEp_identity *ident;
  2259 
  2260                     ident = mbl_to_identity(mbl);
  2261                     if (ident == NULL)
  2262                         goto pEp_error;
  2263 
  2264                     free_identity(msg->from);
  2265                     msg->from = ident;
  2266                 }
  2267                 break;
  2268 
  2269             case MAILIMF_FIELD_TO:
  2270                 {
  2271                     struct mailimf_address_list *mal =
  2272                             _field->fld_data.fld_to->to_addr_list;
  2273                     identity_list *il = mal_to_identity_list(mal);
  2274                     if (il == NULL)
  2275                         goto enomem;
  2276 
  2277                     free_identity_list(msg->to);
  2278                     msg->to = il;
  2279                 }
  2280                 break;
  2281 
  2282             case MAILIMF_FIELD_CC:
  2283                 {
  2284                     struct mailimf_address_list *mal =
  2285                             _field->fld_data.fld_cc->cc_addr_list;
  2286                     identity_list *il = mal_to_identity_list(mal);
  2287                     if (il == NULL)
  2288                         goto enomem;
  2289 
  2290                     free_identity_list(msg->cc);
  2291                     msg->cc = il;
  2292                 }
  2293                 break;
  2294 
  2295             case MAILIMF_FIELD_BCC:
  2296                 {
  2297                     struct mailimf_address_list *mal =
  2298                             _field->fld_data.fld_bcc->bcc_addr_list;
  2299                     identity_list *il = mal_to_identity_list(mal);
  2300                     if (il == NULL)
  2301                         goto enomem;
  2302 
  2303                     free_identity_list(msg->bcc);
  2304                     msg->bcc = il;
  2305                 }
  2306                 break;
  2307 
  2308             case MAILIMF_FIELD_REPLY_TO:
  2309                 {
  2310                     struct mailimf_address_list *mal =
  2311                             _field->fld_data.fld_reply_to->rt_addr_list;
  2312                     identity_list *il = mal_to_identity_list(mal);
  2313                     if (il == NULL)
  2314                         goto enomem;
  2315 
  2316                     free_identity_list(msg->reply_to);
  2317                     msg->reply_to = il;
  2318                 }
  2319                 break;
  2320 
  2321             case MAILIMF_FIELD_IN_REPLY_TO:
  2322                 {
  2323                     clist *list = _field->fld_data.fld_in_reply_to->mid_list;
  2324                     stringlist_t *sl = clist_to_stringlist(list);
  2325                     if (sl == NULL)
  2326                         goto enomem;
  2327 
  2328                     free_stringlist(msg->in_reply_to);
  2329                     msg->in_reply_to = sl;
  2330                 }
  2331                 break;
  2332 
  2333             case MAILIMF_FIELD_REFERENCES:
  2334                 {
  2335                     clist *list = _field->fld_data.fld_references->mid_list;
  2336                     stringlist_t *sl = clist_to_stringlist(list);
  2337                     if (sl == NULL)
  2338                         goto enomem;
  2339 
  2340                     free_stringlist(msg->references);
  2341                     msg->references = sl;
  2342                 }
  2343                 break;
  2344 
  2345             case MAILIMF_FIELD_KEYWORDS:
  2346                 {
  2347                     clist *list = _field->fld_data.fld_keywords->kw_list;
  2348                     stringlist_t *sl = clist_to_stringlist(list);
  2349                     if (sl == NULL)
  2350                         goto enomem;
  2351 
  2352                     free_stringlist(msg->keywords);
  2353                     msg->keywords = sl;
  2354                 }
  2355                 break;
  2356 
  2357             case MAILIMF_FIELD_COMMENTS:
  2358                 {
  2359                     char * text = _field->fld_data.fld_comments->cm_value;
  2360 
  2361                     free(msg->comments);
  2362                     index = 0;
  2363                     r = mailmime_encoded_phrase_parse("utf-8", text,
  2364                             strlen(text), &index, "utf-8", &msg->comments);
  2365                     if (r)
  2366                         goto enomem;
  2367                 }
  2368                 break;
  2369 
  2370             case MAILIMF_FIELD_OPTIONAL_FIELD:
  2371                 {
  2372                     char * name =
  2373                             _field->fld_data.fld_optional_field->fld_name;
  2374                     char * value =
  2375                             _field->fld_data.fld_optional_field->fld_value;
  2376                     char *_value;
  2377 
  2378                     index = 0;
  2379                     r = mailmime_encoded_phrase_parse("utf-8", value,
  2380                             strlen(value), &index, "utf-8", &_value);
  2381                     if (r)
  2382                         goto enomem;
  2383 
  2384                     stringpair_t *pair = new_stringpair(name, _value);
  2385                     if (pair == NULL)
  2386                         goto enomem;
  2387 
  2388                     opt = stringpair_list_add(opt, pair);
  2389                     free(_value);
  2390                     if (opt == NULL)
  2391                         goto enomem;
  2392 
  2393                     if (msg->opt_fields == NULL)
  2394                         msg->opt_fields = opt;
  2395                 }
  2396                 break;
  2397         }
  2398     }
  2399     
  2400     return PEP_STATUS_OK;
  2401 
  2402 enomem:
  2403     status = PEP_OUT_OF_MEMORY;
  2404 
  2405 pEp_error:
  2406     return status;
  2407 }
  2408 
  2409 static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
  2410 {
  2411     const char *text;
  2412     char *_longmsg;
  2413     size_t length;
  2414     size_t _size;
  2415     size_t index;
  2416     char *type = NULL;
  2417     char *charset = NULL;
  2418 
  2419     assert(part);
  2420     assert(longmsg);
  2421 
  2422     *longmsg = NULL;
  2423     if (size)
  2424         *size = 0;
  2425 
  2426     if (part->mm_body == NULL)
  2427         return PEP_ILLEGAL_VALUE;
  2428 
  2429     text = part->mm_body-> dt_data.dt_text.dt_data;
  2430     if (text == NULL)
  2431         return PEP_ILLEGAL_VALUE;
  2432 
  2433     length = part->mm_body->dt_data.dt_text.dt_length;
  2434 
  2435     if (part->mm_body->dt_encoded) {
  2436         int code = part->mm_body->dt_encoding;
  2437         index = 0;
  2438         int r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
  2439         switch (r) {
  2440             case MAILIMF_NO_ERROR:
  2441                 break;
  2442             case MAILIMF_ERROR_MEMORY:
  2443                 return PEP_OUT_OF_MEMORY;
  2444             default:
  2445                 return PEP_ILLEGAL_VALUE;
  2446         }
  2447     }
  2448     else {
  2449         _size = length + 1;
  2450         _longmsg = strndup(text, length);
  2451         if (_longmsg == NULL)
  2452             return PEP_OUT_OF_MEMORY;
  2453     }
  2454 
  2455     if (part->mm_content_type) {
  2456         if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
  2457             if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
  2458                 char * _text;
  2459                 int r = charconv("utf-8", charset, _longmsg, _size, &_text);
  2460                 switch (r) {
  2461                     case MAILIMF_NO_ERROR:
  2462                         break;
  2463                     case MAILIMF_ERROR_MEMORY:
  2464                         return PEP_OUT_OF_MEMORY;
  2465                     default:
  2466                         return PEP_ILLEGAL_VALUE;
  2467                 }
  2468                 free(_longmsg);
  2469                 _longmsg = _text;
  2470             }
  2471         }
  2472     }
  2473     // FIXME: KG - we now have the text we want.
  2474     // Now we need to strip sigs and process them if they are there..
  2475     
  2476 
  2477     *longmsg = _longmsg;
  2478     if (size)
  2479         *size = _size;
  2480 
  2481     return PEP_STATUS_OK;
  2482 }
  2483 
  2484 // THIS IS A BEST-EFFORT ONLY FUNCTION, AND WE ARE NOT DOING MORE THAN THE
  2485 // SUBJECT FOR NOW.
  2486 static PEP_STATUS interpret_protected_headers(
  2487         struct mailmime* mime, 
  2488         message* msg
  2489     )
  2490 {
  2491     // N.B. this is *very much* enigmail output specific, and right now,
  2492     // we only care about subject replacement.
  2493     const char* header_string = "Content-Type: text/rfc822-headers; protected-headers=\"v1\"\nContent-Disposition: inline\n\n";
  2494     size_t content_length = mime->mm_length;
  2495     size_t header_strlen = strlen(header_string);
  2496     if (header_strlen < content_length) {
  2497         const char* headerblock = mime->mm_mime_start;
  2498         size_t subject_len = 0;
  2499         headerblock = strstr(headerblock, header_string);
  2500         if (headerblock) {
  2501             const char* subj_start = "Subject: ";
  2502             headerblock = strstr(headerblock, subj_start);
  2503             if (headerblock) {
  2504                 size_t subj_len = strlen(subj_start);
  2505                 headerblock += subj_len;
  2506                 char* end_pt = strstr(headerblock, "\n");
  2507                 if (end_pt) {
  2508                     if (end_pt != mime->mm_mime_start && *(end_pt - 1) == '\r')
  2509                         end_pt--;
  2510                     subject_len = end_pt - headerblock;
  2511                     char* new_subj = (char*)calloc(subject_len + 1, 1);
  2512                     if (new_subj) {
  2513                         strlcpy(new_subj, headerblock, subject_len + 1);
  2514                         free(msg->shortmsg);
  2515                         msg->shortmsg = new_subj;
  2516                     }    
  2517                 } // if there's no endpoint, there's something wrong here so we ignore all
  2518                   // This is best effort.
  2519             }
  2520         }
  2521     }
  2522     return PEP_STATUS_OK;
  2523 }
  2524 
  2525 // ONLY for main part!!!
  2526 static PEP_STATUS process_multipart_related(struct mailmime *mime,
  2527                                             message *msg) {
  2528     PEP_STATUS status = PEP_STATUS_OK;
  2529 
  2530     assert(mime);
  2531     assert(msg);
  2532 
  2533     clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;                                                
  2534 
  2535     if (partlist == NULL)
  2536         return PEP_ILLEGAL_VALUE;
  2537 
  2538     clistiter *cur = clist_begin(partlist);
  2539     struct mailmime *part = clist_content(cur);
  2540     
  2541     if (part == NULL)
  2542         return PEP_ILLEGAL_VALUE;
  2543 
  2544     struct mailmime_content *content = part->mm_content_type;    
  2545     assert(content);
  2546     
  2547     if (content == NULL)
  2548         return PEP_ILLEGAL_VALUE;
  2549 
  2550     if (_is_text_part(content, "html")) {
  2551         status = interpret_body(part, &msg->longmsg_formatted,
  2552                 NULL);
  2553         if (status)
  2554             return status;
  2555     }
  2556     else {
  2557         // ???
  2558         // This is what we would have done before, so... no
  2559         // worse than the status quo. But FIXME!
  2560         status = interpret_MIME(part, msg, NULL);
  2561         if (status)
  2562             return status;
  2563     }
  2564     
  2565     for (cur = clist_next(cur); cur; cur = clist_next(cur)) {
  2566         part = clist_content(cur);
  2567         if (part == NULL)
  2568             return PEP_ILLEGAL_VALUE;
  2569 
  2570         content = part->mm_content_type;
  2571         assert(content);
  2572         if (content == NULL)
  2573             return PEP_ILLEGAL_VALUE;
  2574 
  2575         status = interpret_MIME(part, msg, NULL);
  2576         if (status)
  2577             return status;
  2578     }
  2579     return status;
  2580 }
  2581 
  2582 static bool _is_marked_as_attachment(struct mailmime_fields *fields)
  2583 {
  2584     if (!(fields && fields->fld_list))
  2585         return false;
  2586 
  2587     clistiter *cur;
  2588     for (cur = clist_begin(fields->fld_list); cur != NULL ; cur = clist_next(cur)) {
  2589         struct mailmime_field * field = clist_content(cur);
  2590         if (!(field && field->fld_type == MAILMIME_FIELD_DISPOSITION &&
  2591                     field->fld_data.fld_disposition &&
  2592                     field->fld_data.fld_disposition->dsp_type))
  2593             continue;
  2594         if (field->fld_data.fld_disposition->dsp_type->dsp_type ==
  2595                 MAILMIME_DISPOSITION_TYPE_ATTACHMENT)
  2596             return true;
  2597     }
  2598 
  2599     return false;
  2600 }
  2601 
  2602 static PEP_STATUS interpret_MIME(
  2603         struct mailmime *mime,
  2604         message *msg,
  2605         bool* has_possible_pEp_msg
  2606     )
  2607 {
  2608     PEP_STATUS status = PEP_STATUS_OK;
  2609 
  2610     assert(mime);
  2611     assert(msg);
  2612 
  2613     struct mailmime_fields *fields = mime->mm_mime_fields;
  2614     struct mailmime_content *content = mime->mm_content_type;
  2615     if (content) {
  2616         if (_is_multipart(content, "alternative")) {
  2617             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  2618             if (partlist == NULL)
  2619                 return PEP_ILLEGAL_VALUE;
  2620 
  2621             clistiter *cur;
  2622             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  2623                 struct mailmime *part = clist_content(cur);
  2624                 if (part == NULL)
  2625                     return PEP_ILLEGAL_VALUE;
  2626 
  2627                 content = part->mm_content_type;
  2628                 assert(content);
  2629                 if (content == NULL)
  2630                     return PEP_ILLEGAL_VALUE;
  2631 
  2632                 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
  2633                     status = interpret_body(part, &msg->longmsg, NULL);
  2634                     if (status)
  2635                         return status;
  2636                 }
  2637                 else if (_is_text_part(content, "rfc822-headers")) {
  2638                     status = interpret_protected_headers(part, msg);
  2639                     if (status)
  2640                         return status;
  2641                 }
  2642                 else if (_is_text_part(content, "html") &&
  2643                         msg->longmsg_formatted == NULL) {
  2644                     status = interpret_body(part, &msg->longmsg_formatted,
  2645                             NULL);
  2646                     if (status)
  2647                         return status;
  2648                 }
  2649                 else if (_is_multipart(content, "related") && 
  2650                     msg->longmsg_formatted == NULL) {
  2651                     status = process_multipart_related(part, msg);
  2652                     if (status)
  2653                         return status;
  2654                 }
  2655                 else /* add as attachment */ {
  2656                     status = interpret_MIME(part, msg, NULL);
  2657                     if (status)
  2658                         return status;
  2659                 }
  2660             }
  2661         }
  2662         else if (_is_multipart(content, "encrypted")) {
  2663             if (msg->longmsg == NULL)
  2664                 msg->longmsg = strdup("");
  2665             assert(msg->longmsg);
  2666             if (!msg->longmsg)
  2667                 return PEP_OUT_OF_MEMORY;
  2668 
  2669             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  2670             if (partlist == NULL)
  2671                 return PEP_ILLEGAL_VALUE;
  2672 
  2673             clistiter *cur;
  2674             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  2675                 struct mailmime *part= clist_content(cur);
  2676                 if (part == NULL)
  2677                     return PEP_ILLEGAL_VALUE;
  2678 
  2679                 status = interpret_MIME(part, msg, NULL);
  2680                 if (status != PEP_STATUS_OK)
  2681                     return status;
  2682             }
  2683         }
  2684         else if (_is_multipart(content, NULL)) {
  2685             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  2686             if (partlist == NULL)
  2687                 return PEP_ILLEGAL_VALUE;
  2688 
  2689             clistiter *cur;
  2690             // only add has_possible_pEp_msg on 2nd part!
  2691             int _att_count = 0;
  2692             for (cur = clist_begin(partlist); cur; cur = clist_next(cur), _att_count++) {
  2693                 struct mailmime *part= clist_content(cur);
  2694                 if (part == NULL)
  2695                     return PEP_ILLEGAL_VALUE;
  2696                 status = interpret_MIME(part, msg, _att_count == 1 ? has_possible_pEp_msg : NULL);
  2697                 if (status != PEP_STATUS_OK)
  2698                     return status;
  2699             }
  2700         }
  2701         else {
  2702             if (_is_text_part(content, "html") &&
  2703                     !_is_marked_as_attachment(fields) &&
  2704                     msg->longmsg_formatted == NULL &&
  2705                     msg->longmsg == NULL) {
  2706                 status = interpret_body(mime, &msg->longmsg_formatted,
  2707                                         NULL);
  2708                 if (status)
  2709                     return status;
  2710             }
  2711             else if (_is_text_part(content, "rfc822-headers")) {
  2712                 status = interpret_protected_headers(mime, msg);
  2713                 if (status)
  2714                     return status;
  2715             }
  2716             else if (_is_text_part(content, "plain") && 
  2717                     !_is_marked_as_attachment(fields) &&
  2718                     msg->longmsg == NULL && msg->longmsg_formatted == NULL) {
  2719                 status = interpret_body(mime, &msg->longmsg, NULL);
  2720                 if (status)
  2721                     return status;
  2722             }            
  2723             else if (_is_text_part(content, NULL) && 
  2724                     !_is_marked_as_attachment(fields) &&
  2725                     !_is_text_part(content, "plain") &&
  2726                     msg->longmsg == NULL) {
  2727                 status = interpret_body(mime, &msg->longmsg, NULL);
  2728                 if (status)
  2729                     return status;
  2730             }
  2731             else {
  2732                 // Fixme - we need a control on recursion level here - KG: maybe NOT. We only go to depth 1.
  2733                 if (has_possible_pEp_msg != NULL) {
  2734                     bool is_msg = (_is_message_part(content, "rfc822") || _is_text_part(content, "rfc822"));
  2735                     if (is_msg) {
  2736                         if (content->ct_parameters) {
  2737                             clistiter *cur;
  2738                             for (cur = clist_begin(content->ct_parameters); cur; cur =
  2739                                  clist_next(cur)) {
  2740                                 struct mailmime_parameter * param = clist_content(cur);
  2741                                 if (param && param->pa_name && strcasecmp(param->pa_name, "forwarded") == 0) {
  2742                                     if (param->pa_value && strcasecmp(param->pa_value, "no") == 0) {
  2743                                         *has_possible_pEp_msg = true;
  2744                                         break;
  2745                                     }
  2746                                 }
  2747                             }
  2748                         }
  2749                     }
  2750                 }
  2751                 char *data = NULL;
  2752                 size_t size = 0;
  2753                 char * mime_type;
  2754                 char * charset;
  2755                 char * filename;
  2756                 int r;
  2757 
  2758                 r = _get_content_type(content, &mime_type, &charset);
  2759                 switch (r) {
  2760                     case 0:
  2761                         break;
  2762                     case EINVAL:
  2763                         return PEP_ILLEGAL_VALUE;
  2764                     case ENOMEM:
  2765                         return PEP_OUT_OF_MEMORY;
  2766                     default:
  2767                         return PEP_UNKNOWN_ERROR;
  2768                 }
  2769 
  2770                 assert(mime_type);
  2771 
  2772                 status = interpret_body(mime, &data, &size);
  2773                 if (status)
  2774                     return status;
  2775 
  2776                 pEp_rid_list_t* resource_id_list = _get_resource_id_list(mime);
  2777                 pEp_rid_list_t* chosen_resource_id = choose_resource_id(resource_id_list);
  2778                 
  2779                 //filename = _get_filename_or_cid(mime);
  2780                 char *_filename = NULL;
  2781                 
  2782                 if (chosen_resource_id) {
  2783                     filename = chosen_resource_id->rid;
  2784                     size_t index = 0;
  2785                     /* NOTA BENE */
  2786                     /* The prefix we just added shouldn't be a problem - this is about decoding %XX (RFC 2392) */
  2787                     /* If it becomes one, we have some MESSY fixing to do. :(                                  */
  2788                     r = mailmime_encoded_phrase_parse("utf-8", filename,
  2789                             strlen(filename), &index, "utf-8", &_filename);
  2790                     if (r) {
  2791                         goto enomem;
  2792                     }
  2793                     char* file_prefix = NULL;
  2794                     
  2795                     /* in case there are others later */
  2796                     switch (chosen_resource_id->rid_type) {
  2797                         case PEP_RID_CID:
  2798                             file_prefix = "cid";
  2799                             break;
  2800                         case PEP_RID_FILENAME:
  2801                             file_prefix = "file";
  2802                             break;
  2803                         default:
  2804                             break;
  2805                     }
  2806 
  2807                     
  2808                     if (file_prefix) {
  2809                         filename = build_uri(file_prefix, _filename);
  2810                         free(_filename);
  2811                         _filename = filename;
  2812                     }
  2813                 }
  2814 
  2815                 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
  2816                         mime_type, _filename);
  2817                 free(_filename);
  2818                 free_rid_list(resource_id_list);
  2819                 resource_id_list = NULL;
  2820                 if (_a == NULL)
  2821                     return PEP_OUT_OF_MEMORY;
  2822                 if (msg->attachments == NULL)
  2823                     msg->attachments = _a;
  2824             }
  2825         }
  2826     }
  2827 
  2828     return PEP_STATUS_OK;
  2829 
  2830 enomem:
  2831     return PEP_OUT_OF_MEMORY;
  2832 }
  2833 
  2834 DYNAMIC_API PEP_STATUS mime_decode_message(
  2835         const char *mimetext,
  2836         size_t size,
  2837         message **msg,
  2838         bool* has_possible_pEp_msg
  2839     )
  2840 {
  2841     PEP_STATUS status = PEP_STATUS_OK;
  2842     struct mailmime * mime = NULL;
  2843     int r;
  2844     message *_msg = NULL;
  2845     size_t index;
  2846 
  2847     assert(mimetext);
  2848     assert(msg);
  2849 
  2850     if (!(mimetext && msg))
  2851         return PEP_ILLEGAL_VALUE;
  2852 
  2853     *msg = NULL;
  2854 
  2855     index = 0;
  2856     r = mailmime_parse(mimetext, size, &index, &mime);
  2857     assert(r == 0);
  2858     assert(mime);
  2859     if (r) {
  2860         if (r == MAILIMF_ERROR_MEMORY)
  2861             goto enomem;
  2862         else
  2863             goto err_mime;
  2864     }
  2865 
  2866     _msg = calloc(1, sizeof(message));
  2867     assert(_msg);
  2868     if (_msg == NULL)
  2869         goto enomem;
  2870 
  2871     clist * _fieldlist = _get_fields(mime);
  2872     if (_fieldlist) {
  2873         status = read_fields(_msg, _fieldlist);
  2874         if (status != PEP_STATUS_OK)
  2875             goto pEp_error;
  2876     }
  2877 
  2878     struct mailmime_content *content = _get_content(mime);
  2879 
  2880     if (content) {
  2881         status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
  2882                 _msg, has_possible_pEp_msg);
  2883         if (status != PEP_STATUS_OK)
  2884             goto pEp_error;
  2885     }
  2886 
  2887     mailmime_free(mime);
  2888     *msg = _msg;
  2889 
  2890     return status;
  2891 
  2892 err_mime:
  2893     status = PEP_ILLEGAL_VALUE;
  2894     goto pEp_error;
  2895 
  2896 enomem:
  2897     status = PEP_OUT_OF_MEMORY;
  2898 
  2899 pEp_error:
  2900     free_message(_msg);
  2901 
  2902     if (mime)
  2903         mailmime_free(mime);
  2904 
  2905     return status;
  2906 }