src/message_api.c
author Volker Birk <vb@pep.foundation>
Wed, 29 Aug 2018 17:10:23 +0200
branchsync
changeset 2899 63b619aef131
parent 2889 683eba0e3d81
child 2955 3b2500a15709
child 2982 0049a0bc457b
permissions -rw-r--r--
somewhat bigger
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 #include "pEp_internal.h"
     5 #include "message_api.h"
     6 
     7 #include "platform.h"
     8 #include "mime.h"
     9 #include "blacklist.h"
    10 #include "KeySync_fsm.h"
    11 
    12 #include <assert.h>
    13 #include <string.h>
    14 #include <stdlib.h>
    15 #include <math.h>
    16 
    17 
    18 // These are globals used in generating message IDs and should only be
    19 // computed once, as they're either really constants or OS-dependent
    20 
    21 int _pEp_rand_max_bits;
    22 double _pEp_log2_36;
    23 
    24 static bool is_a_pEpmessage(const message *msg)
    25 {
    26     for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
    27         if (strcasecmp(i->value->key, "X-pEp-Version") == 0)
    28             return true;
    29     }
    30     return false;
    31 }
    32 
    33 static bool is_wrapper(message* src)
    34 {
    35     bool retval = false;
    36     
    37     if (src) {
    38         unsigned char pEpstr[] = PEP_SUBJ_STRING;
    39         if (is_a_pEpmessage(src) || (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0 ||
    40             _unsigned_signed_strcmp(pEpstr, src->shortmsg, PEP_SUBJ_BYTELEN) == 0) ||
    41             (strcmp(src->shortmsg, "p=p") == 0)) {
    42             char* plaintext = src->longmsg;
    43             if (plaintext) {
    44                 const char *line_end = strchr(plaintext, '\n');
    45 
    46                 if (line_end != NULL) {
    47                     size_t n = line_end - plaintext;
    48                     
    49                     char* copycat = calloc(n + 1, 1);
    50                     
    51                     if (copycat) {
    52                         strlcpy(copycat, plaintext, n+1);
    53                         
    54                         if (strstr(copycat, PEP_MSG_WRAP_KEY) && strstr(copycat, "OUTER"))
    55                             retval = true;
    56                         
    57                         free(copycat);
    58                     }
    59                 }
    60             }
    61         }
    62     }
    63     return retval;
    64 }
    65 
    66 
    67 /*
    68  * static stringpair_t* search_optfields(const message* msg, const char* key) {
    69  *     if (msg && key) {
    70  *         stringpair_list_t* opt_fields = msg->opt_fields;
    71  *         
    72  *         const stringpair_list_t* curr;
    73  *         
    74  *         for (curr = opt_fields; curr && curr->value; curr = curr->next) {
    75  *             if (curr->value->key) {
    76  *                 if (strcasecmp(curr->value->key, key) == 0)
    77  *                     return curr->value;
    78  *             }
    79  *         } 
    80  *     }
    81  *     return NULL;
    82  * }
    83  */
    84 
    85 static char * keylist_to_string(const stringlist_t *keylist)
    86 {
    87     if (keylist) {
    88         size_t size = stringlist_length(keylist);
    89 
    90         const stringlist_t *_kl;
    91         for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
    92             size += strlen(_kl->value);
    93         }
    94 
    95         char *result = calloc(size, 1);
    96         if (result == NULL)
    97             return NULL;
    98 
    99         char *_r = result;
   100         for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
   101             _r = stpcpy(_r, _kl->value);
   102             if (_kl->next && _kl->next->value)
   103                 _r = stpcpy(_r, ",");
   104         }
   105 
   106         return result;
   107     }
   108     else {
   109         return NULL;
   110     }
   111 }
   112 
   113 static const char * rating_to_string(PEP_rating rating)
   114 {
   115     switch (rating) {
   116     case PEP_rating_cannot_decrypt:
   117         return "cannot_decrypt";
   118     case PEP_rating_have_no_key:
   119         return "have_no_key";
   120     case PEP_rating_unencrypted:
   121         return "unencrypted";
   122     case PEP_rating_unencrypted_for_some:
   123         return "unencrypted_for_some";
   124     case PEP_rating_unreliable:
   125         return "unreliable";
   126     case PEP_rating_reliable:
   127         return "reliable";
   128     case PEP_rating_trusted:
   129         return "trusted";
   130     case PEP_rating_trusted_and_anonymized:
   131         return "trusted_and_anonymized";
   132     case PEP_rating_fully_anonymous:
   133         return "fully_anonymous";
   134     case PEP_rating_mistrust:
   135         return "mistrust";
   136     case PEP_rating_b0rken:
   137         return "b0rken";
   138     case PEP_rating_under_attack:
   139         return "under_attack";
   140     default:
   141         return "undefined";
   142     }
   143 }
   144 
   145 bool _memnmemn(const char* needle, 
   146                 size_t needle_size,
   147                 const char* haystack, 
   148                 size_t haystack_size) 
   149 {
   150     if (needle_size > haystack_size) {
   151         return false;
   152     }
   153     else if (needle_size == 0) {
   154         return true;
   155     }
   156                         
   157     bool found = true;
   158     const char* haystack_ptr = haystack;
   159     unsigned int i = 0;
   160     size_t remaining_hay = haystack_size;
   161     for (i = 0; i < haystack_size && (remaining_hay >= needle_size); i++, haystack_ptr++) {
   162         found = false;
   163         const char* needle_ptr = needle;
   164         if (*haystack_ptr == *needle) {
   165             const char* haystack_tmp = haystack_ptr;
   166             unsigned int j;
   167             found = true;
   168             for (j = 0; j < needle_size; j++) {
   169                 if (*needle_ptr++ != *haystack_tmp++) {
   170                     found = false;
   171                     break;
   172                 }
   173             }
   174             if (found)
   175                 break;
   176         }
   177         remaining_hay--;
   178     }
   179     return found;
   180 }
   181 
   182 void add_opt_field(message *msg, const char *name, const char *value)
   183 {
   184     assert(msg && name && value);
   185 
   186     if (msg && name && value) {
   187         stringpair_t *pair = new_stringpair(name, value);
   188         if (pair == NULL)
   189             return;
   190 
   191         stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
   192         if (field == NULL)
   193         {
   194             free_stringpair(pair);
   195             return;
   196         }
   197 
   198         if (msg->opt_fields == NULL)
   199             msg->opt_fields = field;
   200     }
   201 }
   202 
   203 void replace_opt_field(message *msg, 
   204                        const char *name, 
   205                        const char *value,
   206                        bool clobber)
   207 {
   208     assert(msg && name && value);
   209     
   210     if (msg && name && value) {
   211         stringpair_list_t* opt_fields = msg->opt_fields;
   212         stringpair_t* pair = NULL;
   213         
   214         if (opt_fields) {
   215             while (opt_fields) {
   216                 pair = opt_fields->value;
   217                 if (pair && (strcmp(name, pair->key) == 0))
   218                     break;
   219                     
   220                 pair = NULL;
   221                 opt_fields = opt_fields->next;
   222             }
   223         }
   224         
   225         if (pair) {
   226             if (clobber) {
   227                 free(pair->value);
   228                 pair->value = strdup(value);
   229             }
   230         }
   231         else {
   232             add_opt_field(msg, name, value);
   233         }
   234     }
   235 }
   236 
   237 static void decorate_message(
   238     message *msg,
   239     PEP_rating rating,
   240     stringlist_t *keylist,
   241     bool add_version,
   242     bool clobber
   243     )
   244 {
   245     assert(msg);
   246 
   247     if (add_version)
   248         replace_opt_field(msg, "X-pEp-Version", PEP_VERSION, clobber);
   249 
   250     if (rating != PEP_rating_undefined)
   251         replace_opt_field(msg, "X-EncStatus", rating_to_string(rating), clobber);
   252 
   253     if (keylist) {
   254         char *_keylist = keylist_to_string(keylist);
   255         replace_opt_field(msg, "X-KeyList", _keylist, clobber);
   256         free(_keylist);
   257     }
   258 }
   259 
   260 static char* _get_resource_ptr_noown(char* uri) {
   261     char* uri_delim = strstr(uri, "://");
   262     if (!uri_delim)
   263         return uri;
   264     else
   265         return uri + 3;
   266 }
   267 
   268 // static bool is_file_uri(char* str) {
   269 //     return(strncmp(str, "file://", 7) == 0);
   270 // }
   271 
   272 static bool is_cid_uri(const char* str) {
   273     return(strncmp(str, "cid://", 6) == 0);
   274 }
   275 
   276 static bool string_equality(const char *s1, const char *s2)
   277 {
   278     if (s1 == NULL || s2 == NULL)
   279         return false;
   280 
   281     assert(s1 && s2);
   282 
   283     return strcmp(s1, s2) == 0;
   284 }
   285 
   286 static bool is_mime_type(const bloblist_t *bl, const char *mt)
   287 {
   288     assert(mt);
   289 
   290     return bl && string_equality(bl->mime_type, mt);
   291 }
   292 
   293 //
   294 // This function presumes the file ending is a proper substring of the
   295 // filename (i.e. if bl->filename is "a.pgp" and fe is ".pgp", it will
   296 // return true, but if bl->filename is ".pgp" and fe is ".pgp", it will
   297 // return false. This is desired behaviour.
   298 //
   299 static bool is_fileending(const bloblist_t *bl, const char *fe)
   300 {
   301     assert(fe);
   302 
   303     if (bl == NULL || bl->filename == NULL || fe == NULL || is_cid_uri(bl->filename))
   304         return false;
   305 
   306     assert(bl && bl->filename);
   307 
   308     size_t fe_len = strlen(fe);
   309     size_t fn_len = strlen(bl->filename);
   310 
   311     if (fn_len <= fe_len)
   312         return false;
   313 
   314     assert(fn_len > fe_len);
   315 
   316     return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
   317 }
   318 
   319 char * encapsulate_message_wrap_info(const char *msg_wrap_info, const char *longmsg)
   320 {
   321     assert(msg_wrap_info);
   322     
   323     if (!msg_wrap_info) {
   324         if (!longmsg)
   325             return NULL;
   326         else {
   327             char *result = strdup(longmsg);
   328             assert(result);
   329             return result;            
   330         }    
   331     }
   332     
   333     if (longmsg == NULL)
   334         longmsg = "";
   335         
   336     const char * const newlines = "\n\n";
   337     const size_t NL_LEN = 2;
   338         
   339     const size_t bufsize = PEP_MSG_WRAP_KEY_LEN + strlen(msg_wrap_info) + NL_LEN + strlen(longmsg) + 1;
   340     char * ptext = calloc(bufsize, 1);
   341     assert(ptext);
   342     if (ptext == NULL)
   343         return NULL;
   344 
   345     strlcpy(ptext, PEP_MSG_WRAP_KEY, bufsize);
   346     strlcat(ptext, msg_wrap_info, bufsize);
   347     strlcat(ptext, newlines, bufsize);
   348     strlcat(ptext, longmsg, bufsize);
   349 
   350     return ptext;
   351 }
   352 
   353 static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
   354 {
   355     assert(shortmsg);
   356     
   357     unsigned char pEpstr[] = PEP_SUBJ_STRING;
   358     assert(strcmp(shortmsg, "pEp") != 0 && _unsigned_signed_strcmp(pEpstr, shortmsg, PEP_SUBJ_BYTELEN) != 0); 
   359     
   360     if (!shortmsg || strcmp(shortmsg, "pEp") == 0 || 
   361                      _unsigned_signed_strcmp(pEpstr, shortmsg, PEP_SUBJ_BYTELEN) == 0) {
   362         if (!longmsg) {
   363             return NULL;
   364         }
   365         else {
   366             char *result = strdup(longmsg);
   367             assert(result);
   368             return result;
   369         }
   370     }
   371 
   372     if (longmsg == NULL)
   373         longmsg = "";
   374 
   375     const char * const newlines = "\n\n";
   376     const size_t NL_LEN = 2;
   377 
   378     const size_t bufsize = PEP_SUBJ_KEY_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
   379     char * ptext = calloc(bufsize, 1);
   380     assert(ptext);
   381     if (ptext == NULL)
   382         return NULL;
   383 
   384     strlcpy(ptext, PEP_SUBJ_KEY, bufsize);
   385     strlcat(ptext, shortmsg, bufsize);
   386     strlcat(ptext, newlines, bufsize);
   387     strlcat(ptext, longmsg, bufsize);
   388 
   389     return ptext;
   390 }
   391 
   392 static PEP_STATUS replace_subject(message* msg) {
   393     unsigned char pEpstr[] = PEP_SUBJ_STRING;
   394     if (msg->shortmsg && *(msg->shortmsg) != '\0') {
   395         char* longmsg = combine_short_and_long(msg->shortmsg, msg->longmsg);
   396         if (!longmsg)
   397             return PEP_OUT_OF_MEMORY;
   398         else {
   399             free(msg->longmsg);
   400             msg->longmsg = longmsg;
   401         }
   402     }
   403     free(msg->shortmsg);
   404 #ifdef WIN32
   405     msg->shortmsg = strdup("pEp");
   406 #else
   407     msg->shortmsg = strdup((char*)pEpstr);
   408 #endif    
   409     
   410     if (!msg->shortmsg)
   411         return PEP_OUT_OF_MEMORY;
   412     
   413     return PEP_STATUS_OK;
   414 }
   415 
   416 unsigned long long get_bitmask(int num_bits) {
   417     if (num_bits <= 0)
   418         return 0;
   419         
   420     unsigned long long bitmask = 0;
   421     int i;
   422     for (i = 1; i < num_bits; i++) {
   423         bitmask = bitmask << 1;
   424         bitmask |= 1;
   425     }
   426     return bitmask;
   427 }
   428 
   429 static char* get_base_36_rep(unsigned long long value, int num_sig_bits) {
   430         
   431     int bufsize = ((int) ceil((double) num_sig_bits / _pEp_log2_36)) + 1;
   432     
   433     // based on
   434     // https://en.wikipedia.org/wiki/Base36#C_implementation
   435     // ok, we supposedly have a 64-bit kinda sorta random blob
   436     const char base_36_symbols[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   437 
   438     char* retbuf = calloc(bufsize, 1); 
   439 
   440     int i = bufsize - 1; // (end index)
   441 
   442     while (i > 0) {
   443         retbuf[--i] = base_36_symbols[value % 36];
   444         value /= 36;
   445     }
   446 
   447     return retbuf;
   448 }
   449 
   450 
   451 static char* message_id_prand_part(void) {
   452     // RAND modulus
   453     int num_bits = _pEp_rand_max_bits;
   454 
   455     if (num_bits < 0)
   456         return NULL;
   457         
   458     const int DESIRED_BITS = 64;
   459 
   460     num_bits = MIN(num_bits, DESIRED_BITS);
   461     
   462     int i;
   463     
   464     // at least 64 bits
   465     unsigned long long bitmask = get_bitmask(num_bits);
   466     
   467     unsigned long long output_value = 0;
   468     
   469     i = DESIRED_BITS;
   470     
   471     int bitshift = 0;
   472     
   473     while (i > 0) {
   474         int randval = rand();
   475         unsigned long long temp_val = randval & bitmask;
   476 
   477         output_value |= temp_val;
   478 
   479         i -= MIN(num_bits, i); 
   480         
   481         bitshift = MIN(num_bits, i);
   482         output_value <<= bitshift;        
   483         bitmask = get_bitmask(bitshift);
   484     }
   485 
   486     return get_base_36_rep(output_value, DESIRED_BITS);
   487 }
   488 
   489 static PEP_STATUS generate_message_id(message* msg) {
   490 
   491     if (!msg || !msg->from || !msg->from->address)
   492         return PEP_ILLEGAL_VALUE;
   493 
   494     char* time_prefix = NULL;
   495     char* random_id = NULL;
   496     char* retval = NULL;
   497     
   498     size_t buf_len = 2; // NUL + @
   499     
   500     char* from_addr = msg->from->address;
   501     char* domain_ptr = strstr(from_addr, "@");
   502     if (!domain_ptr || *(domain_ptr + 1) == '\0')
   503         domain_ptr = "localhost";
   504     else
   505         domain_ptr++;
   506 
   507     buf_len += strlen(domain_ptr);
   508     
   509     if (msg->id)
   510         free(msg->id);
   511 
   512     msg->id = NULL;
   513     
   514     time_t curr_time = time(NULL);
   515     
   516     time_prefix = get_base_36_rep(curr_time, (int) ceil(log2((double) curr_time)));
   517 
   518     if (!time_prefix)
   519         goto enomem;
   520     
   521     buf_len += strlen(time_prefix);
   522 
   523     random_id = message_id_prand_part();
   524 
   525     if (!random_id)
   526         goto enomem;
   527     
   528         
   529     buf_len += strlen(random_id);
   530     
   531     // make a new uuid - depending on rand() impl, time precision, etc,
   532     // we may still not be unique. We'd better make sure. So. 
   533     char new_uuid[37];
   534     pEpUUID uuid;
   535     uuid_generate_random(uuid);
   536     uuid_unparse_upper(uuid, new_uuid);
   537 
   538     buf_len += strlen(new_uuid);
   539 
   540     buf_len += 6; // "pEp" and 3 '.' chars
   541 
   542     retval = calloc(buf_len, 1);
   543     
   544     if (!retval)
   545         goto enomem;
   546     
   547     strlcpy(retval, "pEp.", buf_len);
   548     strlcat(retval, time_prefix, buf_len);
   549     strlcat(retval, ".", buf_len);
   550     strlcat(retval, random_id, buf_len);
   551     strlcat(retval, ".", buf_len);
   552     strlcat(retval, new_uuid, buf_len);        
   553     strlcat(retval, "@", buf_len);    
   554     strlcat(retval, domain_ptr, buf_len);    
   555 
   556     msg->id = retval;
   557     
   558     free(time_prefix);
   559     free(random_id);
   560     
   561     return PEP_STATUS_OK;
   562         
   563 enomem:
   564     free(time_prefix);
   565     free(random_id);
   566     return PEP_OUT_OF_MEMORY;
   567 }
   568 
   569 /* 
   570    WARNING: For the moment, this only works for the first line of decrypted
   571    plaintext because we don't need more. IF WE DO, THIS MUST BE EXPANDED, or
   572    we need a delineated section to parse separately
   573    
   574    Does case-insensitive compare of keys, so sending in a lower-cased
   575    string constant saves a bit of computation
   576  */
   577 static PEP_STATUS get_data_from_encapsulated_line(const char* plaintext, const char* key, 
   578                                                   const size_t keylen, char** data, 
   579                                                   char** modified_msg) {
   580     char* _data = NULL;
   581     char* _modified = NULL;
   582     
   583     if (strncasecmp(plaintext, key, keylen) == 0) {
   584         const char *line_end = strchr(plaintext, '\n');
   585 
   586         if (line_end == NULL) {
   587             _data = strdup(plaintext + keylen);
   588             assert(_data);
   589             if (_data == NULL)
   590                 return PEP_OUT_OF_MEMORY;
   591         }
   592         else {
   593             size_t n = line_end - plaintext;
   594 
   595             if (*(line_end - 1) == '\r')
   596                 _data = strndup(plaintext + keylen, n - (keylen + 1));
   597             else
   598                 _data = strndup(plaintext + keylen, n - keylen);
   599             assert(_data);
   600             if (_data == NULL)
   601                 return PEP_OUT_OF_MEMORY;
   602 
   603             while (*(plaintext + n) && (*(plaintext + n) == '\n' || *(plaintext + n) == '\r'))
   604                 ++n;
   605 
   606             if (*(plaintext + n)) {
   607                 _modified = strdup(plaintext + n);
   608                 assert(_modified);
   609                 if (_modified == NULL)
   610                     return PEP_OUT_OF_MEMORY;
   611             }
   612         }
   613     }
   614     *data = _data;
   615     *modified_msg = _modified;
   616     return PEP_STATUS_OK;
   617 }
   618 
   619 
   620 static int separate_short_and_long(const char *src, char **shortmsg, char** msg_wrap_info, char **longmsg)
   621 {
   622     char *_shortmsg = NULL;
   623     char *_msg_wrap_info = NULL;
   624     char *_longmsg = NULL;
   625 
   626     assert(src);
   627     assert(shortmsg);
   628     assert(msg_wrap_info);
   629     assert(longmsg);
   630 
   631     if (src == NULL || shortmsg == NULL || msg_wrap_info == NULL || longmsg == NULL)
   632         return -1;
   633 
   634     *shortmsg = NULL;
   635     *longmsg = NULL;
   636     *msg_wrap_info = NULL;
   637 
   638     // We generated the input here. If we ever need more than one header value to be
   639     // encapsulated and hidden in the encrypted text, we will have to modify this.
   640     // As is, we're either doing this with a version 1.0 client, in which case
   641     // the only encapsulated header value is subject, or 2.0+, in which the
   642     // message wrap info is the only encapsulated header value. If we need this
   643     // to be more complex, we're going to have to do something more elegant
   644     // and efficient.    
   645     PEP_STATUS status = get_data_from_encapsulated_line(src, PEP_SUBJ_KEY_LC, 
   646                                                         PEP_SUBJ_KEY_LEN, 
   647                                                         &_shortmsg, &_longmsg);
   648                                                         
   649     if (_shortmsg) {
   650         if (status == PEP_STATUS_OK)
   651             *shortmsg = _shortmsg;
   652         else
   653             goto enomem;
   654     }
   655     else {
   656         status = get_data_from_encapsulated_line(src, PEP_MSG_WRAP_KEY_LC, 
   657                                                  PEP_MSG_WRAP_KEY_LEN, 
   658                                                  &_msg_wrap_info, &_longmsg);
   659         if (_msg_wrap_info) {
   660             if (status == PEP_STATUS_OK)
   661                 *msg_wrap_info = _msg_wrap_info;
   662             else
   663                 goto enomem;
   664         }
   665     }
   666     
   667     // If there was no secret data hiding in the first line...
   668     if (!_shortmsg && !_msg_wrap_info) {
   669         _longmsg = strdup(src);
   670         assert(_longmsg);
   671         if (_longmsg == NULL)
   672             goto enomem;
   673     }
   674     
   675     *longmsg = _longmsg;
   676 
   677     return 0;
   678 
   679 enomem:
   680     free(_shortmsg);
   681     free(_msg_wrap_info);
   682     free(_longmsg);
   683 
   684     return -1;
   685 }
   686 
   687 static PEP_STATUS copy_fields(message *dst, const message *src)
   688 {
   689     assert(dst);
   690     assert(src);
   691 
   692     if(!(dst && src))
   693         return PEP_ILLEGAL_VALUE;
   694 
   695     free_timestamp(dst->sent);
   696     dst->sent = NULL;
   697     if (src->sent) {
   698         dst->sent = timestamp_dup(src->sent);
   699         if (dst->sent == NULL)
   700             return PEP_OUT_OF_MEMORY;
   701     }
   702 
   703     free_timestamp(dst->recv);
   704     dst->recv = NULL;
   705     if (src->recv) {
   706         dst->recv = timestamp_dup(src->recv);
   707         if (dst->recv == NULL)
   708             return PEP_OUT_OF_MEMORY;
   709     }
   710 
   711     free_identity(dst->from);
   712     dst->from = NULL;
   713     if (src->from) {
   714         dst->from = identity_dup(src->from);
   715         if (dst->from == NULL)
   716             return PEP_OUT_OF_MEMORY;
   717     }
   718 
   719     free_identity_list(dst->to);
   720     dst->to = NULL;
   721     if (src->to && src->to->ident) {
   722         dst->to = identity_list_dup(src->to);
   723         if (dst->to == NULL)
   724             return PEP_OUT_OF_MEMORY;
   725     }
   726 
   727     free_identity(dst->recv_by);
   728     dst->recv_by = NULL;
   729     if (src->recv_by) {
   730         dst->recv_by = identity_dup(src->recv_by);
   731         if (dst->recv_by == NULL)
   732             return PEP_OUT_OF_MEMORY;
   733     }
   734 
   735     free_identity_list(dst->cc);
   736     dst->cc = NULL;
   737     if (src->cc && src->cc->ident) {
   738         dst->cc = identity_list_dup(src->cc);
   739         if (dst->cc == NULL)
   740             return PEP_OUT_OF_MEMORY;
   741     }
   742 
   743     free_identity_list(dst->bcc);
   744     dst->bcc = NULL;
   745     if (src->bcc && src->bcc->ident) {
   746         dst->bcc = identity_list_dup(src->bcc);
   747         if (dst->bcc == NULL)
   748             return PEP_OUT_OF_MEMORY;
   749     }
   750 
   751     free_identity_list(dst->reply_to);
   752     dst->reply_to = NULL;
   753     if (src->reply_to && src->reply_to->ident) {
   754         dst->reply_to = identity_list_dup(src->reply_to);
   755         if (dst->reply_to == NULL)
   756             return PEP_OUT_OF_MEMORY;
   757     }
   758 
   759     free_stringlist(dst->in_reply_to);
   760     dst->in_reply_to = NULL;
   761     if (src->in_reply_to && src->in_reply_to->value) {
   762         dst->in_reply_to = stringlist_dup(src->in_reply_to);
   763         if (dst->in_reply_to == NULL)
   764             return PEP_OUT_OF_MEMORY;
   765     }
   766 
   767     free_stringlist(dst->references);
   768     dst->references = NULL;
   769     if (src->references) {
   770         dst->references = stringlist_dup(src->references);
   771         if (dst->references == NULL)
   772             return PEP_OUT_OF_MEMORY;
   773     }
   774 
   775     free_stringlist(dst->keywords);
   776     dst->keywords = NULL;
   777     if (src->keywords && src->keywords->value) {
   778         dst->keywords = stringlist_dup(src->keywords);
   779         if (dst->keywords == NULL)
   780             return PEP_OUT_OF_MEMORY;
   781     }
   782 
   783     free(dst->comments);
   784     dst->comments = NULL;
   785     if (src->comments) {
   786         dst->comments = strdup(src->comments);
   787         assert(dst->comments);
   788         if (dst->comments == NULL)
   789             return PEP_OUT_OF_MEMORY;
   790     }
   791 
   792     free_stringpair_list(dst->opt_fields);
   793     dst->opt_fields = NULL;
   794     if (src->opt_fields) {
   795         dst->opt_fields = stringpair_list_dup(src->opt_fields);
   796         if (dst->opt_fields == NULL)
   797             return PEP_OUT_OF_MEMORY;
   798     }
   799 
   800     return PEP_STATUS_OK;
   801 }
   802 
   803 // FIXME: error mem leakage
   804 static message* extract_minimal_envelope(const message* src, 
   805                                          PEP_msg_direction direct) {
   806                                                  
   807     message* envelope = new_message(direct);
   808     if (!envelope)
   809         return NULL;
   810         
   811     envelope->shortmsg = _pEp_subj_copy();
   812     if (!envelope->shortmsg)
   813         goto enomem;
   814 
   815     if (src->from) {
   816         envelope->from = identity_dup(src->from);
   817         if (!envelope->from)
   818             goto enomem;
   819     }
   820 
   821     if (src->to) {
   822         envelope->to = identity_list_dup(src->to);
   823         if (!envelope->to)
   824             goto enomem;
   825     }
   826 
   827     if (src->cc) {
   828         envelope->cc = identity_list_dup(src->cc);
   829         if (!envelope->cc)
   830             goto enomem;
   831     }
   832 
   833     if (src->bcc) {
   834         envelope->bcc = identity_list_dup(src->bcc);
   835         if (!envelope->bcc)
   836             goto enomem;
   837     }
   838 
   839     // For Outlook Force-Encryption
   840     // const char* pull_keys[] = {"pEp-auto-consume",
   841     //                            "pEp-force-protection",
   842     //                            "X-pEp-Never-Unsecure"};
   843     // int pull_keys_len = 3; // UPDATE WHEN MORE ADDED ABOVE
   844     // 
   845     // int i = 0;
   846     // stringpair_t* opt_add = NULL;    
   847     // for( ; i < pull_keys_len; i++) {        
   848     //     opt_add = search_optfields(src, pull_keys[i]);
   849     //     stringpair_list_t* add_ptr = NULL;
   850     //     if (opt_add) {
   851     //         add_ptr = stringpair_list_add(src->opt_fields, stringpair_dup(opt_add));
   852     //         if (!add_ptr)
   853     //             goto enomem;
   854     //     }
   855     //     opt_add = NULL;
   856     //     add_ptr = NULL;
   857     // }
   858         
   859     envelope->enc_format = src->enc_format;        
   860     
   861     return envelope;
   862     
   863 enomem:
   864     free(envelope);
   865     return NULL;
   866 }
   867 
   868 static message * clone_to_empty_message(const message * src)
   869 {
   870     PEP_STATUS status;
   871     message * msg = NULL;
   872 
   873     assert(src);
   874     if (src == NULL)
   875         return NULL;
   876 
   877     msg = calloc(1, sizeof(message));
   878     assert(msg);
   879     if (msg == NULL)
   880         goto enomem;
   881 
   882     msg->dir = src->dir;
   883 
   884     status = copy_fields(msg, src);
   885     if (status != PEP_STATUS_OK)
   886         goto enomem;
   887 
   888     return msg;
   889 
   890 enomem:
   891     free_message(msg);
   892     return NULL;
   893 }
   894 
   895 static message* wrap_message_as_attachment(message* envelope, 
   896     message* attachment, bool keep_orig_subject) {
   897     
   898     if (!attachment)
   899         return NULL;
   900     
   901     message* _envelope = envelope;
   902 
   903     PEP_STATUS status = PEP_STATUS_OK;
   904 
   905     replace_opt_field(attachment, "X-pEp-Version", PEP_VERSION, true);
   906         
   907     if (!_envelope) {
   908         _envelope = extract_minimal_envelope(attachment, PEP_dir_outgoing);
   909         status = generate_message_id(_envelope);
   910         
   911         if (status != PEP_STATUS_OK)
   912             goto enomem;
   913         
   914         attachment->longmsg = encapsulate_message_wrap_info("INNER", attachment->longmsg);
   915         _envelope->longmsg = encapsulate_message_wrap_info("OUTER", _envelope->longmsg);
   916     }
   917     else {
   918         _envelope->longmsg = encapsulate_message_wrap_info("TRANSPORT", _envelope->longmsg);
   919     }
   920     
   921     if (!attachment->id || attachment->id[0] == '\0') {
   922         free(attachment->id);
   923         if (!_envelope->id) {
   924             status = generate_message_id(_envelope);
   925         
   926             if (status != PEP_STATUS_OK)
   927                 goto enomem;
   928         }
   929             
   930         attachment->id = strdup(_envelope->id);
   931     }
   932     
   933     char* message_text = NULL;
   934 
   935     /* prevent introduction of pEp in inner message */
   936 
   937     if (!attachment->shortmsg) {
   938         attachment->shortmsg = strdup("");
   939         if (!attachment->shortmsg)
   940             goto enomem;
   941     }
   942             
   943     /* Turn message into a MIME-blob */
   944     status = _mime_encode_message_internal(attachment, false, &message_text, true);
   945         
   946     if (status != PEP_STATUS_OK)
   947         goto enomem;
   948     
   949     size_t message_len = strlen(message_text);
   950     
   951     bloblist_t* message_blob = new_bloblist(message_text, message_len,
   952                                             "message/rfc822", NULL);
   953     
   954     _envelope->attachments = message_blob;
   955     if (keep_orig_subject && attachment->shortmsg)
   956         _envelope->shortmsg = strdup(attachment->shortmsg);
   957     return _envelope;
   958     
   959 enomem:
   960     if (!envelope) {
   961         free_message(_envelope);
   962     }
   963     return NULL;    
   964 }
   965 
   966 static PEP_STATUS update_identity_recip_list(PEP_SESSION session,
   967                                              identity_list* list) {
   968 
   969     PEP_STATUS status = PEP_STATUS_OK;
   970 
   971     if (!session)
   972         return PEP_UNKNOWN_ERROR;
   973     
   974     identity_list* id_list_ptr = NULL;
   975         
   976     for (id_list_ptr = list; id_list_ptr; id_list_ptr = id_list_ptr->next) {
   977         pEp_identity* curr_identity = id_list_ptr->ident;
   978         if (curr_identity) {
   979             if (!is_me(session, curr_identity)) {
   980                 char* name_bak = curr_identity->username;
   981                 curr_identity->username = NULL;
   982                 status = update_identity(session, curr_identity);
   983                 if (name_bak && 
   984                     (EMPTYSTR(curr_identity->username) || strcmp(name_bak, curr_identity->username) != 0)) {
   985                     free(curr_identity->username);
   986                     curr_identity->username = name_bak;
   987                 }                        
   988             }
   989             else
   990                 status = myself(session, curr_identity);
   991         if (status == PEP_ILLEGAL_VALUE || status == PEP_OUT_OF_MEMORY)
   992             return status;
   993         }
   994     }
   995     
   996     return PEP_STATUS_OK;                                  
   997 }
   998 
   999 static PEP_STATUS encrypt_PGP_MIME(
  1000     PEP_SESSION session,
  1001     const message *src,
  1002     stringlist_t *keys,
  1003     message *dst,
  1004     PEP_encrypt_flags_t flags
  1005     )
  1006 {
  1007     PEP_STATUS status = PEP_STATUS_OK;
  1008     bool free_ptext = false;
  1009     char *ptext = NULL;
  1010     char *ctext = NULL;
  1011     char *mimetext = NULL;
  1012     size_t csize;
  1013     assert(dst->longmsg == NULL);
  1014     dst->enc_format = PEP_enc_PGP_MIME;
  1015 
  1016     if (src->shortmsg)
  1017         dst->shortmsg = strdup(src->shortmsg);
  1018         
  1019     message *_src = calloc(1, sizeof(message));
  1020     assert(_src);
  1021     if (_src == NULL)
  1022         goto enomem;
  1023 //    _src->longmsg = ptext;
  1024     _src->longmsg = src->longmsg;
  1025     _src->longmsg_formatted = src->longmsg_formatted;
  1026     _src->attachments = src->attachments;
  1027     _src->enc_format = PEP_enc_none;
  1028     bool mime_encode = !is_wrapper(_src);
  1029     status = _mime_encode_message_internal(_src, true, &mimetext, mime_encode);
  1030     assert(status == PEP_STATUS_OK);
  1031     if (status != PEP_STATUS_OK)
  1032         goto pEp_error;
  1033 
  1034     if (free_ptext){
  1035         free(ptext);
  1036         free_ptext=0;
  1037     }
  1038     free(_src);
  1039     _src = NULL;
  1040     assert(mimetext);
  1041     if (mimetext == NULL)
  1042         goto pEp_error;
  1043 
  1044     if (flags & PEP_encrypt_flag_force_unsigned)
  1045         status = encrypt_only(session, keys, mimetext, strlen(mimetext),
  1046             &ctext, &csize);
  1047     else
  1048         status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
  1049             &ctext, &csize);
  1050     free(mimetext);
  1051     if (ctext == NULL)
  1052         goto pEp_error;
  1053 
  1054     dst->longmsg = strdup("this message was encrypted with p≡p "
  1055         "https://pEp-project.org");
  1056     assert(dst->longmsg);
  1057     if (dst->longmsg == NULL)
  1058         goto enomem;
  1059 
  1060     char *v = strdup("Version: 1");
  1061     assert(v);
  1062     if (v == NULL)
  1063         goto enomem;
  1064 
  1065     bloblist_t *_a = new_bloblist(v, strlen(v), "application/pgp-encrypted", NULL);
  1066     if (_a == NULL)
  1067         goto enomem;
  1068     dst->attachments = _a;
  1069 
  1070     _a = bloblist_add(_a, ctext, csize, "application/octet-stream",
  1071         "file://msg.asc");
  1072     if (_a == NULL)
  1073         goto enomem;
  1074 
  1075     return PEP_STATUS_OK;
  1076 
  1077 enomem:
  1078     status = PEP_OUT_OF_MEMORY;
  1079 
  1080 pEp_error:
  1081     if (free_ptext)
  1082         free(ptext);
  1083     free(_src);
  1084     free(ctext);
  1085     return status;
  1086 }
  1087 
  1088 
  1089 static PEP_rating _rating(PEP_comm_type ct, PEP_rating rating)
  1090 {
  1091     if (ct == PEP_ct_unknown)
  1092         return PEP_rating_undefined;
  1093 
  1094     else if (ct == PEP_ct_key_not_found)
  1095         return PEP_rating_have_no_key;
  1096 
  1097     else if (ct == PEP_ct_compromised)
  1098         return PEP_rating_under_attack;
  1099 
  1100     else if (ct == PEP_ct_mistrusted)
  1101         return PEP_rating_mistrust;
  1102 
  1103     if (rating == PEP_rating_unencrypted_for_some)
  1104         return PEP_rating_unencrypted_for_some;
  1105 
  1106     if (ct == PEP_ct_no_encryption || ct == PEP_ct_no_encrypted_channel ||
  1107             ct == PEP_ct_my_key_not_included) {
  1108         if (rating > PEP_rating_unencrypted_for_some)
  1109             return PEP_rating_unencrypted_for_some;
  1110         else
  1111             return PEP_rating_unencrypted;
  1112     }
  1113 
  1114     if (rating == PEP_rating_unencrypted)
  1115         return PEP_rating_unencrypted_for_some;
  1116 
  1117     if (ct >= PEP_ct_confirmed_enc_anon)
  1118         return PEP_rating_trusted_and_anonymized;
  1119 
  1120     else if (ct >= PEP_ct_strong_encryption)
  1121         return PEP_rating_trusted;
  1122 
  1123     else if (ct >= PEP_ct_strong_but_unconfirmed && ct < PEP_ct_confirmed)
  1124         return PEP_rating_reliable;
  1125 
  1126     else
  1127         return PEP_rating_unreliable;
  1128 }
  1129 
  1130 static bool is_encrypted_attachment(const bloblist_t *blob)
  1131 {
  1132     assert(blob);
  1133 
  1134     if (blob == NULL || blob->filename == NULL || is_cid_uri(blob->filename))
  1135         return false;
  1136 
  1137     char *ext = strrchr(blob->filename, '.');
  1138     if (ext == NULL)
  1139         return false;
  1140 
  1141     if (strcmp(blob->mime_type, "application/octet-stream") == 0) {
  1142         if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0)
  1143             return true;
  1144     }
  1145     if (strcmp(ext, ".asc") == 0 && blob->size > 0) {            
  1146         const char* pubk_needle = "BEGIN PGP PUBLIC KEY";
  1147         size_t pubk_needle_size = strlen(pubk_needle);
  1148         const char* privk_needle = "BEGIN PGP PRIVATE KEY";
  1149         size_t privk_needle_size = strlen(privk_needle);
  1150 
  1151         if (!(_memnmemn(pubk_needle, pubk_needle_size, blob->value, blob->size)) &&
  1152             !(_memnmemn(privk_needle, privk_needle_size, blob->value, blob->size)))
  1153             return true;
  1154     }
  1155 
  1156     return false;
  1157 }
  1158 
  1159 static bool is_encrypted_html_attachment(const bloblist_t *blob)
  1160 {
  1161     assert(blob);
  1162     assert(blob->filename);
  1163     if (blob == NULL || blob->filename == NULL || is_cid_uri(blob->filename))
  1164         return false;
  1165 
  1166     const char* bare_filename_ptr = _get_resource_ptr_noown(blob->filename);
  1167     if (strncmp(bare_filename_ptr, "PGPexch.htm.", 12) == 0) {
  1168         if (strcmp(bare_filename_ptr + 11, ".pgp") == 0 ||
  1169             strcmp(bare_filename_ptr + 11, ".asc") == 0)
  1170             return true;
  1171     }
  1172 
  1173     return false;
  1174 }
  1175 
  1176 static char * without_double_ending(const char *filename)
  1177 {
  1178     assert(filename);
  1179     if (filename == NULL || is_cid_uri(filename))
  1180         return NULL;
  1181 
  1182     char *ext = strrchr(filename, '.');
  1183     if (ext == NULL)
  1184         return NULL;
  1185 
  1186     char *result = strndup(filename, ext - filename);
  1187     assert(result);
  1188     return result;
  1189 }
  1190 
  1191 static PEP_rating decrypt_rating(PEP_STATUS status)
  1192 {
  1193     switch (status) {
  1194     case PEP_UNENCRYPTED:
  1195     case PEP_VERIFIED:
  1196     case PEP_VERIFY_NO_KEY:
  1197     case PEP_VERIFIED_AND_TRUSTED:
  1198         return PEP_rating_unencrypted;
  1199 
  1200     case PEP_DECRYPTED:
  1201     case PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH:
  1202         return PEP_rating_unreliable;
  1203 
  1204     case PEP_DECRYPTED_AND_VERIFIED:
  1205         return PEP_rating_reliable;
  1206 
  1207     case PEP_DECRYPT_NO_KEY:
  1208         return PEP_rating_have_no_key;
  1209 
  1210     case PEP_DECRYPT_WRONG_FORMAT:
  1211     case PEP_CANNOT_DECRYPT_UNKNOWN:
  1212         return PEP_rating_cannot_decrypt;
  1213 
  1214     default:
  1215         return PEP_rating_undefined;
  1216     }
  1217 }
  1218 
  1219 static PEP_rating key_rating(PEP_SESSION session, const char *fpr)
  1220 {
  1221 
  1222     assert(session);
  1223     assert(fpr);
  1224 
  1225     if (session == NULL || fpr == NULL)
  1226         return PEP_rating_undefined;
  1227 
  1228 
  1229     PEP_comm_type bare_comm_type = PEP_ct_unknown;
  1230     PEP_comm_type resulting_comm_type = PEP_ct_unknown;
  1231     PEP_STATUS status = get_key_rating(session, fpr, &bare_comm_type);
  1232     if (status != PEP_STATUS_OK)
  1233         return PEP_rating_undefined;
  1234 
  1235     PEP_comm_type least_comm_type = PEP_ct_unknown;
  1236     least_trust(session, fpr, &least_comm_type);
  1237 
  1238     if (least_comm_type == PEP_ct_unknown) {
  1239         resulting_comm_type = bare_comm_type;
  1240     } else if (least_comm_type < PEP_ct_strong_but_unconfirmed ||
  1241                bare_comm_type < PEP_ct_strong_but_unconfirmed) {
  1242         // take minimum if anything bad
  1243         resulting_comm_type = least_comm_type < bare_comm_type ? 
  1244                               least_comm_type : 
  1245                               bare_comm_type;
  1246     } else {
  1247         resulting_comm_type = least_comm_type;
  1248     }
  1249     return _rating(resulting_comm_type, PEP_rating_undefined);
  1250 }
  1251 
  1252 static PEP_rating worst_rating(PEP_rating rating1, PEP_rating rating2) {
  1253     return ((rating1 < rating2) ? rating1 : rating2);
  1254 }
  1255 
  1256 static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist, char* sender_fpr, PEP_rating sender_rating)
  1257 {
  1258     PEP_rating rating = sender_rating;
  1259 
  1260     assert(keylist && keylist->value);
  1261     if (keylist == NULL || keylist->value == NULL)
  1262         return PEP_rating_undefined;
  1263 
  1264     stringlist_t *_kl;
  1265     for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
  1266 
  1267         // Ignore own fpr
  1268         if(_same_fpr(sender_fpr, strlen(sender_fpr), _kl->value, strlen(_kl->value)))
  1269             continue;
  1270 
  1271         PEP_rating _rating_ = key_rating(session, _kl->value);
  1272          
  1273         if (_rating_ <= PEP_rating_mistrust)
  1274             return _rating_;
  1275             
  1276         if (_rating_ == PEP_rating_unencrypted)
  1277         {
  1278             if (rating > PEP_rating_unencrypted_for_some)
  1279                 rating = worst_rating(rating, PEP_rating_unencrypted_for_some);
  1280         }
  1281         else
  1282         {
  1283             rating = worst_rating(rating, _rating_);
  1284         }
  1285     }
  1286 
  1287     return rating;
  1288 }
  1289 
  1290 // Internal function WARNING:
  1291 // Only call this on an ident that might have its FPR set from retrieval!
  1292 // (or on one without an fpr)
  1293 // We do not want myself() setting the fpr here.
  1294 static PEP_comm_type _get_comm_type(
  1295     PEP_SESSION session,
  1296     PEP_comm_type max_comm_type,
  1297     pEp_identity *ident
  1298     )
  1299 {
  1300     PEP_STATUS status = PEP_STATUS_OK;
  1301 
  1302     if (max_comm_type == PEP_ct_compromised)
  1303         return PEP_ct_compromised;
  1304 
  1305     if (max_comm_type == PEP_ct_mistrusted)
  1306         return PEP_ct_mistrusted;
  1307 
  1308     if (!is_me(session, ident))
  1309         status = update_identity(session, ident);
  1310     else
  1311         status = myself(session, ident);
  1312 
  1313     if (status == PEP_STATUS_OK) {
  1314         if (ident->comm_type == PEP_ct_compromised)
  1315             return PEP_ct_compromised;
  1316         else if (ident->comm_type == PEP_ct_mistrusted)
  1317             return PEP_ct_mistrusted;
  1318         else
  1319             return MIN(max_comm_type, ident->comm_type);
  1320     }
  1321     else {
  1322         return PEP_ct_unknown;
  1323     }
  1324 }
  1325 
  1326 static void free_bl_entry(bloblist_t *bl)
  1327 {
  1328     if (bl) {
  1329         free(bl->value);
  1330         free(bl->mime_type);
  1331         free(bl->filename);
  1332         free(bl);
  1333     }
  1334 }
  1335 
  1336 static bool is_key(const bloblist_t *bl)
  1337 {
  1338     return (// workaround for Apple Mail bugs
  1339             (is_mime_type(bl, "application/x-apple-msg-attachment") &&
  1340              is_fileending(bl, ".asc")) ||
  1341             // as binary, by file name
  1342             ((bl->mime_type == NULL ||
  1343               is_mime_type(bl, "application/octet-stream")) &&
  1344              (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
  1345                     is_fileending(bl, ".key") || is_fileending(bl, ".asc"))) ||
  1346             // explicit mime type
  1347             is_mime_type(bl, "application/pgp-keys") ||
  1348             // as text, by file name
  1349             (is_mime_type(bl, "text/plain") &&
  1350              (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
  1351                     is_fileending(bl, ".key") || is_fileending(bl, ".asc")))
  1352            );
  1353 }
  1354 
  1355 static void remove_attached_keys(message *msg)
  1356 {
  1357     if (msg) {
  1358         bloblist_t *last = NULL;
  1359         for (bloblist_t *bl = msg->attachments; bl && bl->value; ) {
  1360             bloblist_t *next = bl->next;
  1361 
  1362             if (is_key(bl)) {
  1363                 if (last) {
  1364                     last->next = next;
  1365                 }
  1366                 else {
  1367                     msg->attachments = next;
  1368                 }
  1369                 free_bl_entry(bl);
  1370             }
  1371             else {
  1372                 last = bl;
  1373             }
  1374             bl = next;
  1375         }
  1376     }
  1377 }
  1378 
  1379 bool import_attached_keys(
  1380         PEP_SESSION session,
  1381         const message *msg,
  1382         identity_list **private_idents
  1383     )
  1384 {
  1385     assert(session);
  1386     assert(msg);
  1387 
  1388     if (session == NULL || msg == NULL)
  1389         return false;
  1390 
  1391     bool remove = false;
  1392 
  1393     int i = 0;
  1394     for (bloblist_t *bl = msg->attachments; i < MAX_KEYS_TO_IMPORT && bl && bl->value;
  1395             bl = bl->next, i++)
  1396     {
  1397         if (bl && bl->value && bl->size && bl->size < MAX_KEY_SIZE
  1398                 && is_key(bl))
  1399         {
  1400             char* blob_value = bl->value;
  1401             size_t blob_size = bl->size;
  1402             bool free_blobval = false;
  1403             
  1404             if (is_encrypted_attachment(bl)) {
  1405                     
  1406                 char* bl_ptext = NULL;
  1407                 size_t bl_psize = 0;
  1408                 stringlist_t* bl_keylist = NULL;
  1409                 PEP_STATUS _status = decrypt_and_verify(session, 
  1410                                                         blob_value, blob_size,
  1411                                                         NULL, 0,
  1412                                                         &bl_ptext, &bl_psize, 
  1413                                                         &bl_keylist);
  1414                 free_stringlist(bl_keylist); // we don't care about key encryption as long as we decrypt
  1415                 if (_status == PEP_DECRYPTED || _status == PEP_DECRYPTED_AND_VERIFIED) {
  1416                     free_blobval = true;
  1417                     blob_value = bl_ptext;
  1418                     blob_size = bl_psize;
  1419                 }
  1420                 else {
  1421                     // This is an encrypted attachment we can do nothing with.
  1422                     // We shouldn't delete it or import it, because we can't
  1423                     // do the latter.
  1424                     free(bl_ptext);
  1425                     continue;
  1426                 }
  1427             }
  1428             identity_list *local_private_idents = NULL;
  1429             import_key(session, blob_value, blob_size, &local_private_idents);
  1430             remove = true;
  1431             if (private_idents && *private_idents == NULL && local_private_idents != NULL)
  1432                 *private_idents = local_private_idents;
  1433             else
  1434                 free_identity_list(local_private_idents);
  1435             if (free_blobval)
  1436                 free(blob_value);
  1437         }
  1438     }
  1439     return remove;
  1440 }
  1441 
  1442 
  1443 PEP_STATUS _attach_key(PEP_SESSION session, const char* fpr, message *msg)
  1444 {
  1445     char *keydata = NULL;
  1446     size_t size;
  1447 
  1448     PEP_STATUS status = export_key(session, fpr, &keydata, &size);
  1449     assert(status == PEP_STATUS_OK);
  1450     if (status != PEP_STATUS_OK)
  1451         return status;
  1452     assert(size);
  1453 
  1454      bloblist_t *bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
  1455                       "file://pEpkey.asc");
  1456 
  1457     if (msg->attachments == NULL && bl)
  1458         msg->attachments = bl;
  1459 
  1460     return PEP_STATUS_OK;
  1461 }
  1462 
  1463 #define ONE_WEEK (7*24*3600)
  1464 
  1465 void attach_own_key(PEP_SESSION session, message *msg)
  1466 {
  1467     assert(session);
  1468     assert(msg);
  1469 
  1470     if (msg->dir == PEP_dir_incoming)
  1471         return;
  1472 
  1473     assert(msg->from && msg->from->fpr);
  1474     if (msg->from == NULL || msg->from->fpr == NULL)
  1475         return;
  1476 
  1477     if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
  1478         return;
  1479 
  1480     char *revoked_fpr = NULL;
  1481     uint64_t revocation_date = 0;
  1482 
  1483     if(get_revoked(session, msg->from->fpr,
  1484                    &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
  1485        revoked_fpr != NULL)
  1486     {
  1487         time_t now = time(NULL);
  1488 
  1489         if (now < (time_t)revocation_date + ONE_WEEK)
  1490         {
  1491             _attach_key(session, revoked_fpr, msg);
  1492         }
  1493     }
  1494     free(revoked_fpr);
  1495 }
  1496 
  1497 PEP_cryptotech determine_encryption_format(message *msg)
  1498 {
  1499     assert(msg);
  1500 
  1501     if (is_PGP_message_text(msg->longmsg)) {
  1502         msg->enc_format = PEP_enc_pieces;
  1503         return PEP_crypt_OpenPGP;
  1504     }
  1505     else if (msg->attachments && msg->attachments->next &&
  1506             is_mime_type(msg->attachments, "application/pgp-encrypted") &&
  1507             is_PGP_message_text(msg->attachments->next->value)
  1508         ) {
  1509         msg->enc_format = PEP_enc_PGP_MIME;
  1510         return PEP_crypt_OpenPGP;
  1511     }
  1512     else if (msg->attachments && msg->attachments->next &&
  1513             is_mime_type(msg->attachments->next, "application/pgp-encrypted") &&
  1514             is_PGP_message_text(msg->attachments->value)
  1515         ) {
  1516         msg->enc_format = PEP_enc_PGP_MIME_Outlook1;
  1517         return PEP_crypt_OpenPGP;
  1518     }
  1519     else {
  1520         msg->enc_format = PEP_enc_none;
  1521         return PEP_crypt_none;
  1522     }
  1523 }
  1524 
  1525 static void _cleanup_src(message* src, bool remove_attached_key) {
  1526     assert(src);
  1527     
  1528     if (!src)
  1529         return;
  1530         
  1531     char* longmsg = NULL;
  1532     char* shortmsg = NULL;
  1533     char* msg_wrap_info = NULL;
  1534     separate_short_and_long(src->longmsg, &shortmsg, &msg_wrap_info,
  1535                             &longmsg);
  1536     if (longmsg) {                    
  1537         free(src->longmsg);
  1538         free(shortmsg);
  1539         free(msg_wrap_info);
  1540         src->longmsg = longmsg;
  1541     }
  1542     if (remove_attached_key) {
  1543         // End of the attachment list
  1544         if (src->attachments) {
  1545             bloblist_t* tmp = src->attachments;
  1546             while (tmp->next && tmp->next->next) {
  1547                 tmp = tmp->next;
  1548             }
  1549             free_bloblist(tmp->next);
  1550             tmp->next = NULL;
  1551         }    
  1552     }                   
  1553 }
  1554 
  1555 DYNAMIC_API PEP_STATUS encrypt_message(
  1556         PEP_SESSION session,
  1557         message *src,
  1558         stringlist_t * extra,
  1559         message **dst,
  1560         PEP_enc_format enc_format,
  1561         PEP_encrypt_flags_t flags
  1562     )
  1563 {
  1564     PEP_STATUS status = PEP_STATUS_OK;
  1565     message * msg = NULL;
  1566     stringlist_t * keys = NULL;
  1567     message* _src = src;
  1568 
  1569     bool added_key_to_real_src = false;
  1570     
  1571     assert(session);
  1572     assert(src);
  1573     assert(dst);
  1574 
  1575     if (!(session && src && dst))
  1576         return PEP_ILLEGAL_VALUE;
  1577 
  1578     if (src->dir == PEP_dir_incoming)
  1579         return PEP_ILLEGAL_VALUE;
  1580 
  1581     determine_encryption_format(src);
  1582     // TODO: change this for multi-encryption in message format 2.0
  1583     if (src->enc_format != PEP_enc_none)
  1584         return PEP_ILLEGAL_VALUE;
  1585 
  1586     bool force_v_1 = flags & PEP_encrypt_flag_force_version_1;
  1587     
  1588     *dst = NULL;
  1589 
  1590     if (src->from && (!src->from->user_id || src->from->user_id[0] == '\0')) {
  1591         char* own_id = NULL;
  1592         status = get_default_own_userid(session, &own_id);
  1593         if (own_id) {
  1594             free(src->from->user_id);
  1595             src->from->user_id = own_id; // ownership transfer
  1596         }
  1597     }
  1598     
  1599     status = myself(session, src->from);
  1600     if (status != PEP_STATUS_OK)
  1601         goto pEp_error;
  1602 
  1603     keys = new_stringlist(src->from->fpr);
  1604     if (keys == NULL)
  1605         goto enomem;
  1606 
  1607     stringlist_t *_k = keys;
  1608 
  1609     if (extra) {
  1610         _k = stringlist_append(_k, extra);
  1611         if (_k == NULL)
  1612             goto enomem;
  1613     }
  1614 
  1615     bool dest_keys_found = true;
  1616     bool has_pEp_user = false;
  1617     
  1618     PEP_comm_type max_comm_type = PEP_ct_pEp;
  1619 
  1620     identity_list * _il;
  1621 
  1622 
  1623     if (enc_format != PEP_enc_none && (_il = src->bcc) && _il->ident)
  1624     {
  1625         // BCC limited support:
  1626         //     - App splits mails with BCC in multiple mails.
  1627         //     - Each email is encrypted separately
  1628 
  1629         if(_il->next || (src->to && src->to->ident) || (src->cc && src->cc->ident))
  1630         {
  1631             // Only one Bcc with no other recipient allowed for now
  1632             return PEP_ILLEGAL_VALUE;
  1633         }
  1634 
  1635         PEP_STATUS _status = PEP_STATUS_OK;
  1636         if (!is_me(session, _il->ident)) {
  1637             _status = update_identity(session, _il->ident);
  1638             if (_status == PEP_CANNOT_FIND_IDENTITY) {
  1639                 _il->ident->comm_type = PEP_ct_key_not_found;
  1640                 _status = PEP_STATUS_OK;
  1641             }
  1642             bool is_blacklisted = false;
  1643             if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
  1644                 _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
  1645                 if (_status != PEP_STATUS_OK) {
  1646                     // DB error
  1647                     status = PEP_UNENCRYPTED;
  1648                     goto pEp_error;
  1649                 }
  1650                 if (is_blacklisted) {
  1651                     bool user_default, ident_default, address_default; 
  1652                     _status = get_valid_pubkey(session, _il->ident,
  1653                                                &ident_default, &user_default,
  1654                                                &address_default,
  1655                                                true);
  1656                     if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
  1657                         _il->ident->comm_type = PEP_ct_key_not_found;
  1658                         _status = PEP_STATUS_OK;                        
  1659                     }
  1660                 }    
  1661             }
  1662             if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
  1663                 is_pEp_user(session, _il->ident, &has_pEp_user);
  1664         }
  1665         else
  1666             _status = myself(session, _il->ident);
  1667         if (_status != PEP_STATUS_OK) {
  1668             status = PEP_UNENCRYPTED;
  1669             goto pEp_error;
  1670         }
  1671 
  1672         if (_il->ident->fpr && _il->ident->fpr[0]) {
  1673             _k = stringlist_add(_k, _il->ident->fpr);
  1674             if (_k == NULL)
  1675                 goto enomem;
  1676             max_comm_type = _get_comm_type(session, max_comm_type,
  1677                                            _il->ident);
  1678         }
  1679         else {
  1680             dest_keys_found = false;
  1681             status = PEP_KEY_NOT_FOUND;
  1682         }
  1683     }
  1684     else
  1685     {
  1686         for (_il = src->to; _il && _il->ident; _il = _il->next) {
  1687             PEP_STATUS _status = PEP_STATUS_OK;
  1688             if (!is_me(session, _il->ident)) {
  1689                 _status = update_identity(session, _il->ident);
  1690                 if (_status == PEP_CANNOT_FIND_IDENTITY) {
  1691                     _il->ident->comm_type = PEP_ct_key_not_found;
  1692                     _status = PEP_STATUS_OK;
  1693                 }
  1694                 bool is_blacklisted = false;
  1695                 if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
  1696                     _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
  1697                     if (_status != PEP_STATUS_OK) {
  1698                         // DB error
  1699                         status = PEP_UNENCRYPTED;
  1700                         goto pEp_error;
  1701                     }
  1702                     if (is_blacklisted) {
  1703                         bool user_default, ident_default, address_default; 
  1704                         _status = get_valid_pubkey(session, _il->ident,
  1705                                                    &ident_default, &user_default,
  1706                                                    &address_default,
  1707                                                    true);
  1708                         if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
  1709                             _il->ident->comm_type = PEP_ct_key_not_found;
  1710                             _status = PEP_STATUS_OK;                        
  1711                         }
  1712                     }    
  1713                 }
  1714                 if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
  1715                     is_pEp_user(session, _il->ident, &has_pEp_user);
  1716             }
  1717             else
  1718                 _status = myself(session, _il->ident);
  1719             if (_status != PEP_STATUS_OK) {
  1720                 status = PEP_UNENCRYPTED;
  1721                 goto pEp_error;
  1722             }
  1723 
  1724             if (_il->ident->fpr && _il->ident->fpr[0]) {
  1725                 _k = stringlist_add(_k, _il->ident->fpr);
  1726                 if (_k == NULL)
  1727                     goto enomem;
  1728                 max_comm_type = _get_comm_type(session, max_comm_type,
  1729                                                _il->ident);
  1730             }
  1731             else {
  1732                 dest_keys_found = false;
  1733                 status = PEP_KEY_NOT_FOUND;
  1734             }
  1735         }
  1736 
  1737         for (_il = src->cc; _il && _il->ident; _il = _il->next) {
  1738             PEP_STATUS _status = PEP_STATUS_OK;
  1739             if (!is_me(session, _il->ident)) {
  1740                 _status = update_identity(session, _il->ident);
  1741                 if (_status == PEP_CANNOT_FIND_IDENTITY) {
  1742                     _il->ident->comm_type = PEP_ct_key_not_found;
  1743                     _status = PEP_STATUS_OK;
  1744                 }
  1745                 bool is_blacklisted = false;
  1746                 if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
  1747                     _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
  1748                     if (_status != PEP_STATUS_OK) {
  1749                         // DB error
  1750                         status = PEP_UNENCRYPTED;
  1751                         goto pEp_error;
  1752                     }
  1753                     if (is_blacklisted) {
  1754                         bool user_default, ident_default, address_default; 
  1755                         _status = get_valid_pubkey(session, _il->ident,
  1756                                                    &ident_default, &user_default,
  1757                                                    &address_default,
  1758                                                    true);
  1759                         if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
  1760                             _il->ident->comm_type = PEP_ct_key_not_found;
  1761                             _status = PEP_STATUS_OK;                        
  1762                         }
  1763                     }    
  1764                 }
  1765                 if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
  1766                     is_pEp_user(session, _il->ident, &has_pEp_user);
  1767             }
  1768             else
  1769                 _status = myself(session, _il->ident);
  1770             if (_status != PEP_STATUS_OK)
  1771             {
  1772                 status = PEP_UNENCRYPTED;
  1773                 goto pEp_error;
  1774             }
  1775 
  1776             if (_il->ident->fpr && _il->ident->fpr[0]) {
  1777                 _k = stringlist_add(_k, _il->ident->fpr);
  1778                 if (_k == NULL)
  1779                     goto enomem;
  1780                 max_comm_type = _get_comm_type(session, max_comm_type,
  1781                                                _il->ident);
  1782             }
  1783             else {
  1784                 dest_keys_found = false;
  1785             }
  1786         }
  1787     }
  1788         
  1789     if (enc_format == PEP_enc_none || !dest_keys_found ||
  1790         stringlist_length(keys)  == 0 ||
  1791         _rating(max_comm_type,
  1792                 PEP_rating_undefined) < PEP_rating_reliable)
  1793     {
  1794         free_stringlist(keys);
  1795         if ((has_pEp_user || !session->passive_mode) && 
  1796             !(flags & PEP_encrypt_flag_force_no_attached_key)) {
  1797             attach_own_key(session, src);
  1798             added_key_to_real_src = true;
  1799         }
  1800         decorate_message(src, PEP_rating_undefined, NULL, true, true);
  1801         return PEP_UNENCRYPTED;
  1802     }
  1803     else {
  1804         // FIXME - we need to deal with transport types (via flag)
  1805         if ((!force_v_1) && ((max_comm_type | PEP_ct_confirmed) == PEP_ct_pEp)) {
  1806             _src = wrap_message_as_attachment(NULL, src, false);
  1807             if (!_src)
  1808                 goto pEp_error;
  1809         }
  1810         else {
  1811             // hide subject
  1812             if (!session->unencrypted_subject) {
  1813                 status = replace_subject(_src);
  1814                 if (status == PEP_OUT_OF_MEMORY)
  1815                     goto enomem;
  1816             }
  1817             if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  1818                 added_key_to_real_src = true;            
  1819         }
  1820         if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  1821             attach_own_key(session, _src);
  1822 
  1823         msg = clone_to_empty_message(_src);
  1824         if (msg == NULL)
  1825             goto enomem;
  1826 
  1827         switch (enc_format) {
  1828             case PEP_enc_PGP_MIME:
  1829             case PEP_enc_PEP: // BUG: should be implemented extra
  1830                 status = encrypt_PGP_MIME(session, _src, keys, msg, flags);
  1831                 break;
  1832 
  1833             /* case PEP_enc_PEP:
  1834                 // TODO: implement
  1835                 NOT_IMPLEMENTED */
  1836 
  1837             default:
  1838                 assert(0);
  1839                 status = PEP_ILLEGAL_VALUE;
  1840                 goto pEp_error;
  1841         }
  1842 
  1843         if (status == PEP_OUT_OF_MEMORY)
  1844             goto enomem;
  1845 
  1846         if (status != PEP_STATUS_OK)
  1847             goto pEp_error;
  1848     }
  1849 
  1850     free_stringlist(keys);
  1851 
  1852     if (msg && msg->shortmsg == NULL) {
  1853         msg->shortmsg = strdup("");
  1854         assert(msg->shortmsg);
  1855         if (msg->shortmsg == NULL)
  1856             goto enomem;
  1857     }
  1858 
  1859     if (msg) {
  1860         decorate_message(msg, PEP_rating_undefined, NULL, true, true);
  1861         if (_src->id) {
  1862             msg->id = strdup(_src->id);
  1863             assert(msg->id);
  1864             if (msg->id == NULL)
  1865                 goto enomem;
  1866         }
  1867     }
  1868 
  1869     *dst = msg;
  1870     
  1871     // ??? FIXME: Check to be sure we don't have references btw _src and msg. 
  1872     // I don't think we do.
  1873     if (_src && _src != src)
  1874         free_message(_src);
  1875     
  1876     _cleanup_src(src, added_key_to_real_src);
  1877         
  1878     return status;
  1879 
  1880 enomem:
  1881     status = PEP_OUT_OF_MEMORY;
  1882 
  1883 pEp_error:
  1884     free_stringlist(keys);
  1885     free_message(msg);
  1886     if (_src && _src != src)
  1887         free_message(_src);
  1888 
  1889     _cleanup_src(src, added_key_to_real_src);
  1890 
  1891     return status;
  1892 }
  1893 
  1894 DYNAMIC_API PEP_STATUS encrypt_message_and_add_priv_key(
  1895         PEP_SESSION session,
  1896         message *src,
  1897         message **dst,
  1898         const char* to_fpr,
  1899         PEP_enc_format enc_format,
  1900         PEP_encrypt_flags_t flags
  1901     )
  1902 {
  1903     assert(session);
  1904     assert(src);
  1905     assert(dst);
  1906     assert(to_fpr);
  1907         
  1908     if (!session || !src || !dst || !to_fpr)
  1909         return PEP_ILLEGAL_VALUE;
  1910         
  1911     if (enc_format == PEP_enc_none)
  1912         return PEP_ILLEGAL_VALUE;
  1913     
  1914     if (src->cc || src->bcc)
  1915         return PEP_ILLEGAL_VALUE;
  1916         
  1917     if (!src->to || src->to->next)
  1918         return PEP_ILLEGAL_VALUE;
  1919         
  1920     if (!src->from->address || !src->to->ident || !src->to->ident->address)
  1921         return PEP_ILLEGAL_VALUE;
  1922             
  1923     if (strcasecmp(src->from->address, src->to->ident->address) != 0)
  1924         return PEP_ILLEGAL_VALUE;
  1925     
  1926     stringlist_t* keys = NULL;
  1927 
  1928     char* own_id = NULL;
  1929     char* default_id = NULL;
  1930     
  1931     pEp_identity* own_identity = NULL;
  1932     char* own_private_fpr = NULL;
  1933 
  1934     char* priv_key_data = NULL;
  1935     
  1936     PEP_STATUS status = get_default_own_userid(session, &own_id);
  1937     
  1938     if (!own_id)
  1939         return PEP_UNKNOWN_ERROR; // Probably a DB error at this point
  1940         
  1941     if (src->from->user_id) {
  1942         if (strcmp(src->from->user_id, own_id) != 0) {
  1943             status = get_userid_alias_default(session, src->from->user_id, &default_id);
  1944             if (status != PEP_STATUS_OK || !default_id || strcmp(default_id, own_id) != 0) {
  1945                 status = PEP_ILLEGAL_VALUE;
  1946                 goto pEp_free;
  1947             }
  1948         }        
  1949     }
  1950     
  1951     // Ok, we are at least marginally sure the initial stuff is ok.
  1952         
  1953     // Let's get our own, normal identity
  1954     own_identity = identity_dup(src->from);
  1955     status = myself(session, own_identity);
  1956 
  1957     if (status != PEP_STATUS_OK)
  1958         goto pEp_free;
  1959 
  1960     // Ok, now we know the address is an own address. All good. Then...
  1961     own_private_fpr = own_identity->fpr;
  1962     own_identity->fpr = strdup(to_fpr);
  1963     
  1964     status = get_trust(session, own_identity);
  1965     
  1966     if (status != PEP_STATUS_OK) {
  1967         if (status == PEP_CANNOT_FIND_IDENTITY)
  1968             status = PEP_ILLEGAL_VALUE;
  1969         goto pEp_free;
  1970     }
  1971         
  1972     if ((own_identity->comm_type & PEP_ct_confirmed) != PEP_ct_confirmed) {
  1973         status = PEP_ILLEGAL_VALUE;
  1974         goto pEp_free;
  1975     }
  1976                 
  1977     // Ok, so all the things are now allowed.
  1978     // So let's get our own private key and roll with it.
  1979     size_t priv_key_size = 0;
  1980     
  1981     status = export_secret_key(session, own_private_fpr, &priv_key_data, 
  1982                                 &priv_key_size);
  1983 
  1984     if (status != PEP_STATUS_OK)
  1985         goto pEp_free;
  1986     
  1987     if (!priv_key_data) {
  1988         status = PEP_CANNOT_EXPORT_KEY;
  1989         goto pEp_free;
  1990     }
  1991     
  1992     // Ok, fine... let's encrypt yon blob
  1993     keys = new_stringlist(own_private_fpr);
  1994     if (!keys) {
  1995         status = PEP_OUT_OF_MEMORY;
  1996         goto pEp_free;
  1997     }
  1998     
  1999     stringlist_add(keys, to_fpr);
  2000     
  2001     char* encrypted_key_text = NULL;
  2002     size_t encrypted_key_size = 0;
  2003     
  2004     if (flags & PEP_encrypt_flag_force_unsigned)
  2005         status = encrypt_only(session, keys, priv_key_data, priv_key_size,
  2006                               &encrypted_key_text, &encrypted_key_size);
  2007     else
  2008         status = encrypt_and_sign(session, keys, priv_key_data, priv_key_size,
  2009                                   &encrypted_key_text, &encrypted_key_size);
  2010     
  2011     if (!encrypted_key_text) {
  2012         status = PEP_UNKNOWN_ERROR;
  2013         goto pEp_free;
  2014     }
  2015 
  2016     // We will have to delete this before returning, as we allocated it.
  2017     bloblist_t* created_bl = NULL;
  2018     bloblist_t* created_predecessor = NULL;
  2019     
  2020     bloblist_t* old_head = NULL;
  2021     
  2022     if (!src->attachments || src->attachments->value == NULL) {
  2023         if (src->attachments && src->attachments->value == NULL) {
  2024             old_head = src->attachments;
  2025             src->attachments = NULL;
  2026         }
  2027         src->attachments = new_bloblist(encrypted_key_text, encrypted_key_size,
  2028                                         "application/octet-stream", 
  2029                                         "file://pEpkey.asc.pgp");
  2030         created_bl = src->attachments;
  2031     } 
  2032     else {
  2033         bloblist_t* tmp = src->attachments;
  2034         while (tmp && tmp->next) {
  2035             tmp = tmp->next;
  2036         }
  2037         created_predecessor = tmp;                                    
  2038         created_bl = bloblist_add(tmp, 
  2039                                   encrypted_key_text, encrypted_key_size,
  2040                                   "application/octet-stream", 
  2041                                    "file://pEpkey.asc.pgp");
  2042     }
  2043     
  2044     if (!created_bl) {
  2045         status = PEP_OUT_OF_MEMORY;
  2046         goto pEp_free;
  2047     }
  2048             
  2049     // Ok, it's in there. Let's do this.        
  2050     status = encrypt_message(session, src, keys, dst, enc_format, flags);
  2051     
  2052     // Delete what we added to src
  2053     free_bloblist(created_bl);
  2054     if (created_predecessor)
  2055         created_predecessor->next = NULL;
  2056     else {
  2057         if (old_head)
  2058             src->attachments = old_head;
  2059         else
  2060             src->attachments = NULL;    
  2061     }
  2062     
  2063 pEp_free:
  2064     free(own_id);
  2065     free(default_id);
  2066     free(own_private_fpr);
  2067     free(priv_key_data);
  2068     free_identity(own_identity);
  2069     free_stringlist(keys);
  2070     return status;
  2071 }
  2072 
  2073 
  2074 DYNAMIC_API PEP_STATUS encrypt_message_for_self(
  2075         PEP_SESSION session,
  2076         pEp_identity* target_id,
  2077         message *src,
  2078         stringlist_t* extra,
  2079         message **dst,
  2080         PEP_enc_format enc_format,
  2081         PEP_encrypt_flags_t flags
  2082     )
  2083 {
  2084     PEP_STATUS status = PEP_STATUS_OK;
  2085     message * msg = NULL;
  2086     stringlist_t * keys = NULL;
  2087     message* _src = src;
  2088 
  2089     assert(session);
  2090     assert(src);
  2091     assert(dst);
  2092     assert(enc_format != PEP_enc_none);
  2093 
  2094     if (!(session && src && dst && enc_format != PEP_enc_none))
  2095         return PEP_ILLEGAL_VALUE;
  2096 
  2097     // if (src->dir == PEP_dir_incoming)
  2098     //     return PEP_ILLEGAL_VALUE;
  2099 
  2100     determine_encryption_format(src);
  2101     if (src->enc_format != PEP_enc_none)
  2102         return PEP_ILLEGAL_VALUE;
  2103 
  2104     if (target_id && (!target_id->user_id || target_id->user_id[0] == '\0')) {
  2105         char* own_id = NULL;
  2106         status = get_default_own_userid(session, &own_id);
  2107         if (own_id) {
  2108             free(target_id->user_id);
  2109             target_id->user_id = own_id; // ownership transfer
  2110         }
  2111     }
  2112     
  2113     if (target_id->address) {
  2114         status = myself(session, target_id);
  2115         if (status != PEP_STATUS_OK)
  2116             goto pEp_error;
  2117     }
  2118     else if (!target_id->fpr)
  2119         return PEP_ILLEGAL_VALUE;
  2120     
  2121     *dst = NULL;
  2122 
  2123     // PEP_STATUS _status = update_identity(session, target_id);
  2124     // if (_status != PEP_STATUS_OK) {
  2125     //     status = _status;
  2126     //     goto pEp_error;
  2127     // }
  2128 
  2129     char* target_fpr = target_id->fpr;
  2130     if (!target_fpr)
  2131         return PEP_KEY_NOT_FOUND; // FIXME: Error condition
  2132  
  2133     keys = new_stringlist(target_fpr);
  2134     
  2135     stringlist_t *_k = keys;
  2136 
  2137     if (extra) {
  2138         _k = stringlist_append(_k, extra);
  2139         if (_k == NULL)
  2140             goto enomem;
  2141     }
  2142 
  2143     /* KG: did we ever do this??? */
  2144     // if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  2145     //     _attach_key(session, target_fpr, src);
  2146 
  2147     _src = wrap_message_as_attachment(NULL, src, false);
  2148     if (!_src)
  2149         goto pEp_error;
  2150 
  2151     msg = clone_to_empty_message(_src);
  2152     if (msg == NULL)
  2153         goto enomem;
  2154 
  2155     switch (enc_format) {
  2156         case PEP_enc_PGP_MIME:
  2157         case PEP_enc_PEP: // BUG: should be implemented extra
  2158             status = encrypt_PGP_MIME(session, _src, keys, msg, flags);
  2159             if (status == PEP_STATUS_OK || (src->longmsg && strstr(src->longmsg, "INNER")))
  2160                 _cleanup_src(src, false);
  2161             break;
  2162 
  2163         default:
  2164             assert(0);
  2165             status = PEP_ILLEGAL_VALUE;
  2166             goto pEp_error;
  2167     }
  2168 
  2169     if (status == PEP_OUT_OF_MEMORY)
  2170         goto enomem;
  2171 
  2172     if (status != PEP_STATUS_OK)
  2173         goto pEp_error;
  2174 
  2175      if (msg && msg->shortmsg == NULL) {
  2176          msg->shortmsg = _pEp_subj_copy();
  2177          assert(msg->shortmsg);
  2178          if (msg->shortmsg == NULL)
  2179              goto enomem;
  2180      }
  2181 
  2182      if (msg) {
  2183          if (_src->id) {
  2184              msg->id = strdup(_src->id);
  2185              assert(msg->id);
  2186              if (msg->id == NULL)
  2187                  goto enomem;
  2188          }
  2189          decorate_message(msg, PEP_rating_undefined, NULL, true, true);
  2190      }
  2191 
  2192     *dst = msg;
  2193     
  2194     if (src != _src)
  2195         free_message(_src);
  2196 
  2197     return status;
  2198 
  2199 enomem:
  2200     status = PEP_OUT_OF_MEMORY;
  2201 
  2202 pEp_error:
  2203     free_stringlist(keys);
  2204     free_message(msg);
  2205     if (src != _src)
  2206         free_message(_src);
  2207 
  2208     return status;
  2209 }
  2210 
  2211 // static PEP_STATUS _update_identity_for_incoming_message(
  2212 //         PEP_SESSION session,
  2213 //         const message *src
  2214 //     )
  2215 // {
  2216 //     PEP_STATUS status;
  2217 // 
  2218 //     if (src->from && src->from->address) {
  2219 //         if (!is_me(session, src->from))
  2220 //             status = update_identity(session, src->from);
  2221 //         else
  2222 //             status = myself(session, src->from);
  2223 //         if (status == PEP_STATUS_OK
  2224 //                 && is_a_pEpmessage(src)
  2225 //                 && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
  2226 //                 && src->from->comm_type != PEP_ct_pEp_unconfirmed
  2227 //                 && src->from->comm_type != PEP_ct_pEp)
  2228 //         {
  2229 //             src->from->comm_type |= PEP_ct_pEp_unconfirmed;
  2230 //             status = set_identity(session, src->from);
  2231 //         }
  2232 //         return status;
  2233 //     }
  2234 //     return PEP_ILLEGAL_VALUE;
  2235 // }
  2236 
  2237 
  2238 static PEP_STATUS _get_detached_signature(message* msg, 
  2239                                           bloblist_t** signature_blob) {
  2240     bloblist_t* attach_curr = msg->attachments;
  2241 
  2242     *signature_blob = NULL;
  2243 
  2244     while (attach_curr) {
  2245         if (strcasecmp(attach_curr->mime_type, "application/pgp-signature") == 0) {
  2246             *signature_blob = attach_curr;
  2247             break;
  2248         }
  2249         attach_curr = attach_curr->next;
  2250     }
  2251 
  2252     return PEP_STATUS_OK;
  2253 }
  2254 
  2255 static PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
  2256                                    char** stext, size_t* ssize) {
  2257 
  2258     char* signed_boundary = NULL;
  2259     char* signpost = strstr(ptext, "Content-Type: multipart/signed");
  2260 
  2261     *ssize = 0;
  2262     *stext = NULL;
  2263 
  2264     if (!signpost)
  2265         return PEP_UNKNOWN_ERROR;
  2266 
  2267     char* curr_line = signpost;
  2268 //    const char* end_text = ptext + psize;
  2269     const char* boundary_key = "boundary=";
  2270     const size_t BOUNDARY_KEY_SIZE = 9;
  2271 
  2272     char* start_boundary = strstr(curr_line, boundary_key);
  2273     if (!start_boundary)
  2274         return PEP_UNKNOWN_ERROR;
  2275 
  2276     start_boundary += BOUNDARY_KEY_SIZE;
  2277 
  2278     bool quoted = (*start_boundary == '"');
  2279 
  2280     if (quoted)
  2281         start_boundary++;
  2282         
  2283     char* end_boundary = (quoted ? strstr(start_boundary, "\"") : strstr(start_boundary, ";")); // FIXME: third possiblity is CRLF, or?
  2284 
  2285     if (!end_boundary)
  2286         return PEP_UNKNOWN_ERROR;
  2287 
  2288     // Add space for the "--"
  2289     size_t boundary_strlen = (end_boundary - start_boundary) + 2;
  2290 
  2291     signed_boundary = calloc(boundary_strlen + 1, 1);
  2292     strlcpy(signed_boundary, "--", boundary_strlen + 1);
  2293     strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
  2294 
  2295     start_boundary = strstr(end_boundary, signed_boundary);
  2296 
  2297     if (!start_boundary)
  2298         return PEP_UNKNOWN_ERROR;
  2299 
  2300     start_boundary += boundary_strlen;
  2301 
  2302     if (*start_boundary == '\r') {
  2303         if (*(start_boundary + 1) == '\n')
  2304             start_boundary += 2;
  2305     }
  2306     else if (*start_boundary == '\n')
  2307         start_boundary++;
  2308 
  2309     end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
  2310 
  2311     if (!end_boundary)
  2312         return PEP_UNKNOWN_ERROR;
  2313 
  2314     // See RFC3156 section 5...
  2315     end_boundary--; 
  2316     if (*(end_boundary - 1) == '\r')
  2317         end_boundary--; 
  2318 
  2319     *ssize = end_boundary - start_boundary;
  2320     *stext = start_boundary;
  2321     free(signed_boundary);
  2322 
  2323     return PEP_STATUS_OK;
  2324 }
  2325 
  2326 static PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in, 
  2327                                    stringlist_t** keylist_in_out, 
  2328                                    pEp_identity* from) {
  2329     
  2330     if (!verify_in || !(*verify_in)) // this isn't really a problem.
  2331         return PEP_STATUS_OK;
  2332     
  2333     stringlist_t* orig_verify = *verify_in;
  2334     
  2335     stringlist_t* verify_curr = NULL;
  2336     stringlist_t* from_keys = NULL;
  2337     
  2338     /* FIXME: what to do if head needs to be null */
  2339     PEP_STATUS status = find_keys(session, from->address, &from_keys);
  2340     
  2341     stringlist_t* from_fpr_node = NULL;
  2342     stringlist_t* from_curr;
  2343     
  2344     for (from_curr = from_keys; from_curr; from_curr = from_curr->next) {
  2345         for (verify_curr = orig_verify; verify_curr; verify_curr = verify_curr->next) {
  2346             if (from_curr->value && verify_curr->value &&
  2347                 _same_fpr(from_curr->value, strlen(from_curr->value),
  2348                           verify_curr->value, strlen(verify_curr->value))) {
  2349                 from_fpr_node = from_curr;
  2350                 break;
  2351             }
  2352         }
  2353     }
  2354     
  2355     if (!from_fpr_node) {
  2356         status = PEP_KEY_NOT_FOUND;
  2357         goto free;
  2358     }
  2359 
  2360     verify_curr = orig_verify;
  2361     
  2362     /* put "from" signer at the beginning of the list */
  2363     if (!_same_fpr(orig_verify->value, strlen(orig_verify->value),
  2364                    from_fpr_node->value, strlen(from_fpr_node->value))) {
  2365         orig_verify = stringlist_delete(orig_verify, from_fpr_node->value);
  2366         verify_curr = new_stringlist(from_fpr_node->value);
  2367         verify_curr->next = orig_verify;
  2368     }
  2369 
  2370     /* append keylist to signers */
  2371     if (keylist_in_out && *keylist_in_out && (*keylist_in_out)->value) {
  2372         stringlist_t** tail_pp = &verify_curr->next;
  2373         
  2374         while (*tail_pp) {
  2375             tail_pp = &((*tail_pp)->next);
  2376         }
  2377         stringlist_t* second_list = *keylist_in_out;
  2378         if (second_list) {
  2379             char* listhead_val = second_list->value;
  2380             if (!listhead_val || listhead_val[0] == '\0') {
  2381                 /* remove head, basically. This can happen when,
  2382                    for example, the signature is detached and
  2383                    verification is not seen directly after
  2384                    decryption, so no signer is presumed in
  2385                    the first construction of the keylist */
  2386                 *keylist_in_out = (*keylist_in_out)->next;
  2387                 second_list->next = NULL;
  2388                 free_stringlist(second_list);
  2389             }
  2390         }
  2391         *tail_pp = *keylist_in_out;
  2392     }
  2393     
  2394     *keylist_in_out = verify_curr;
  2395     
  2396     status = PEP_STATUS_OK;
  2397     
  2398 free:
  2399     free_stringlist(from_keys);
  2400     return status;
  2401 }
  2402 
  2403 static PEP_STATUS amend_rating_according_to_sender_and_recipients(
  2404        PEP_SESSION session,
  2405        PEP_rating *rating,
  2406        pEp_identity *sender,
  2407        stringlist_t *recipients) {
  2408     
  2409     PEP_STATUS status = PEP_STATUS_OK;
  2410 
  2411     if (*rating > PEP_rating_mistrust) {
  2412 
  2413         if (recipients == NULL) {
  2414             *rating = PEP_rating_undefined;
  2415             return PEP_STATUS_OK;
  2416         }
  2417 
  2418         char *fpr = recipients->value;
  2419 
  2420         if (!(sender && sender->user_id && sender->user_id[0] && fpr && fpr[0])) {
  2421             *rating = PEP_rating_unreliable;
  2422         }
  2423         else {
  2424             pEp_identity *_sender = new_identity(sender->address, fpr,
  2425                                                  sender->user_id, sender->username);
  2426             if (_sender == NULL)
  2427                 return PEP_OUT_OF_MEMORY;
  2428 
  2429             status = get_trust(session, _sender);
  2430             if (_sender->comm_type == PEP_ct_unknown) {
  2431                 get_key_rating(session, fpr, &_sender->comm_type);
  2432             }
  2433             if (_sender->comm_type != PEP_ct_unknown) {
  2434                 *rating = keylist_rating(session, recipients, 
  2435                             fpr, _rating(_sender->comm_type, 
  2436                                           PEP_rating_undefined));
  2437             }
  2438             
  2439             free_identity(_sender);
  2440             if (status == PEP_CANNOT_FIND_IDENTITY)
  2441                status = PEP_STATUS_OK;
  2442         }
  2443     }
  2444     return status;
  2445 }
  2446 
  2447 // FIXME: Do we need to remove the attachment? I think we do...
  2448 static bool pull_up_attached_main_msg(message* src) {
  2449     char* slong = src->longmsg;
  2450     char* sform = src->longmsg_formatted;
  2451     bloblist_t* satt = src->attachments;
  2452     
  2453     if ((!slong || slong[0] == '\0')
  2454          && (!sform || sform[0] == '\0')) {
  2455         if (satt) {
  2456             const char* inner_mime_type = satt->mime_type;
  2457             if (strcasecmp(inner_mime_type, "text/plain") == 0) {
  2458                 free(slong); /* in case of "" */
  2459                 src->longmsg = strndup(satt->value, satt->size); 
  2460                 
  2461                 bloblist_t* next_node = satt->next;
  2462                 if (next_node) {
  2463                     inner_mime_type = next_node->mime_type;
  2464                     if (strcasecmp(inner_mime_type, "text/html") == 0) {
  2465                         free(sform);
  2466                         src->longmsg_formatted = strndup(next_node->value, next_node->size);
  2467                     }
  2468                 }
  2469             }
  2470             else if (strcasecmp(inner_mime_type, "text/html") == 0) {
  2471                 free(sform);
  2472                 src->longmsg_formatted = strndup(satt->value, satt->size);
  2473             }
  2474         }
  2475         return true;
  2476     }
  2477     return false;
  2478 }
  2479 
  2480 
  2481 
  2482 static PEP_STATUS unencapsulate_hidden_fields(message* src, message* msg,
  2483                                               char** msg_wrap_info) {
  2484     if (!src)
  2485         return PEP_ILLEGAL_VALUE;
  2486     unsigned char pEpstr[] = PEP_SUBJ_STRING;
  2487     PEP_STATUS status = PEP_STATUS_OK;
  2488 
  2489     bool change_source_in_place = (msg ? false : true);
  2490     
  2491     if (change_source_in_place)
  2492         msg = src;
  2493         
  2494     
  2495     switch (src->enc_format) {
  2496         case PEP_enc_PGP_MIME:
  2497         case PEP_enc_pieces:
  2498         case PEP_enc_PGP_MIME_Outlook1:
  2499 //        case PEP_enc_none: // FIXME - this is wrong
  2500 
  2501             if (!change_source_in_place)
  2502                 status = copy_fields(msg, src);
  2503                 
  2504             if (status != PEP_STATUS_OK)
  2505                 return status;
  2506                 
  2507             // FIXME: This is a mess. Talk with VB about how far we go to identify
  2508             if (is_a_pEpmessage(src) || (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0 ||
  2509                 _unsigned_signed_strcmp(pEpstr, src->shortmsg, PEP_SUBJ_BYTELEN) == 0) ||
  2510                 (strcmp(src->shortmsg, "p=p") == 0))
  2511             {
  2512                 char * shortmsg = NULL;
  2513                 char * longmsg = NULL;
  2514         
  2515                 if (msg->longmsg) {
  2516                     int r = separate_short_and_long(msg->longmsg, 
  2517                                                     &shortmsg, 
  2518                                                     msg_wrap_info,
  2519                                                     &longmsg);
  2520                 
  2521                     if (r == -1)
  2522                         return PEP_OUT_OF_MEMORY;
  2523                 }
  2524 
  2525                 // We only use the shortmsg in version 1.0 messages; if it occurs where we
  2526                 // didn't replace the subject, we ignore this all
  2527                 if (!(*msg_wrap_info || change_source_in_place)) {
  2528                     if (!shortmsg || 
  2529                         (src->shortmsg != NULL && strcmp(src->shortmsg, "pEp") != 0 &&
  2530                          _unsigned_signed_strcmp(pEpstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0 &&
  2531                         strcmp(src->shortmsg, "p=p") != 0)) {
  2532                              
  2533                         if (shortmsg != NULL)
  2534                             free(shortmsg);                        
  2535                             
  2536                         if (src->shortmsg == NULL) {
  2537                             shortmsg = strdup("");
  2538                         }
  2539                         else {
  2540                             // FIXME: is msg->shortmsg always a copy of
  2541                             // src->shortmsg already?
  2542                             // if so, we need to change the logic so
  2543                             // that in this case, we don't free msg->shortmsg
  2544                             // and do this strdup, etc
  2545                             shortmsg = strdup(src->shortmsg);
  2546                         }        
  2547                     }
  2548                     free(msg->shortmsg);
  2549                     msg->shortmsg = shortmsg;
  2550                 }
  2551                 
  2552                 free(msg->longmsg);
  2553 
  2554                 msg->longmsg = longmsg;
  2555             }
  2556             else {
  2557                 if (!change_source_in_place) {
  2558                     msg->shortmsg = strdup(src->shortmsg);
  2559                     assert(msg->shortmsg);
  2560                     if (msg->shortmsg == NULL)
  2561                         return PEP_OUT_OF_MEMORY;
  2562                 }
  2563             }
  2564             break;
  2565         default:
  2566                 // BUG: must implement more
  2567                 NOT_IMPLEMENTED
  2568     }
  2569     return PEP_STATUS_OK;
  2570 
  2571 }
  2572 
  2573 static PEP_STATUS get_crypto_text(message* src, char** crypto_text, size_t* text_size) {
  2574                 
  2575     // this is only here because of how NOT_IMPLEMENTED works            
  2576     PEP_STATUS status = PEP_STATUS_OK;
  2577                     
  2578     switch (src->enc_format) {
  2579         case PEP_enc_PGP_MIME:
  2580             *crypto_text = src->attachments->next->value;
  2581             *text_size = src->attachments->next->size;
  2582             break;
  2583 
  2584         case PEP_enc_PGP_MIME_Outlook1:
  2585             *crypto_text = src->attachments->value;
  2586             *text_size = src->attachments->size;
  2587             break;
  2588 
  2589         case PEP_enc_pieces:
  2590             *crypto_text = src->longmsg;
  2591             *text_size = strlen(*crypto_text);
  2592             break;
  2593 
  2594         default:
  2595             NOT_IMPLEMENTED
  2596     }
  2597     
  2598     return status;
  2599 }
  2600 
  2601 
  2602 static PEP_STATUS verify_decrypted(PEP_SESSION session,
  2603                                    message* src,
  2604                                    message* msg, 
  2605                                    char* plaintext, 
  2606                                    size_t plaintext_size,
  2607                                    stringlist_t** keylist,
  2608                                    PEP_STATUS* decrypt_status,
  2609                                    PEP_cryptotech crypto) {
  2610 
  2611     assert(src && src->from);
  2612     
  2613     if (!src && !src->from)
  2614         return PEP_ILLEGAL_VALUE;
  2615 
  2616     PEP_STATUS _cached_decrypt_status = *decrypt_status;
  2617         
  2618     pEp_identity* sender = src->from;
  2619 
  2620     bloblist_t* detached_sig = NULL;
  2621     PEP_STATUS status = _get_detached_signature(msg, &detached_sig);
  2622     stringlist_t *verify_keylist = NULL;
  2623     
  2624     
  2625     if (detached_sig) {
  2626         char* dsig_text = detached_sig->value;
  2627         size_t dsig_size = detached_sig->size;
  2628         size_t ssize = 0;
  2629         char* stext = NULL;
  2630 
  2631         status = _get_signed_text(plaintext, plaintext_size, &stext, &ssize);
  2632 
  2633         if (ssize > 0 && stext) {
  2634             status = cryptotech[crypto].verify_text(session, stext,
  2635                                                     ssize, dsig_text, dsig_size,
  2636                                                     &verify_keylist);
  2637         }
  2638         
  2639         if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
  2640         {
  2641             *decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
  2642         
  2643             status = combine_keylists(session, &verify_keylist, keylist, sender);
  2644         }
  2645     }
  2646     else {
  2647         size_t csize, psize;
  2648         char* ctext;
  2649         char* ptext;
  2650         get_crypto_text(src, &ctext, &csize);
  2651         // reverify - we may have imported a key in the meantime
  2652         // status = cryptotech[crypto].verify_text(session, ctext,
  2653         //                                         csize, NULL, 0,
  2654         //                                         &verify_keylist);
  2655         free_stringlist(*keylist);
  2656         *decrypt_status = decrypt_and_verify(session, ctext, csize,
  2657                                              NULL, 0,
  2658                                              &ptext, &psize, keylist);
  2659         
  2660     }
  2661 
  2662     if (*decrypt_status != PEP_DECRYPTED_AND_VERIFIED)
  2663         *decrypt_status = _cached_decrypt_status;                                
  2664 
  2665     return PEP_STATUS_OK;
  2666 }
  2667 
  2668 static PEP_STATUS _decrypt_in_pieces(PEP_SESSION session, 
  2669                                      message* src, 
  2670                                      message** msg_ptr, 
  2671                                      char* ptext,
  2672                                      size_t psize) {
  2673                             
  2674     PEP_STATUS status = PEP_STATUS_OK;
  2675     
  2676     *msg_ptr = clone_to_empty_message(src);
  2677 
  2678     if (*msg_ptr == NULL)
  2679         return PEP_OUT_OF_MEMORY;
  2680 
  2681     message* msg = *msg_ptr;
  2682 
  2683     msg->longmsg = strdup(ptext);
  2684     ptext = NULL;
  2685 
  2686     bloblist_t *_m = msg->attachments;
  2687     if (_m == NULL && src->attachments && src->attachments->value) {
  2688         msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
  2689         _m = msg->attachments;
  2690     }
  2691 
  2692     bloblist_t *_s;
  2693     for (_s = src->attachments; _s; _s = _s->next) {
  2694         if (_s->value == NULL && _s->size == 0){
  2695             _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
  2696             if (_m == NULL)
  2697                 return PEP_OUT_OF_MEMORY;
  2698 
  2699         }
  2700         else if (is_encrypted_attachment(_s)) {
  2701             stringlist_t *_keylist = NULL;
  2702             char *attctext  = _s->value;
  2703             size_t attcsize = _s->size;
  2704 
  2705             free(ptext);
  2706             ptext = NULL;
  2707 
  2708             status = decrypt_and_verify(session, attctext, attcsize,
  2709                                         NULL, 0,
  2710                                         &ptext, &psize, &_keylist);
  2711             free_stringlist(_keylist);
  2712 
  2713             if (ptext) {
  2714                 if (is_encrypted_html_attachment(_s)) {
  2715                     msg->longmsg_formatted = ptext;
  2716                     ptext = NULL;
  2717                 }
  2718                 else {
  2719                     static const char * const mime_type = "application/octet-stream";
  2720                     char * const filename =
  2721                         without_double_ending(_s->filename);
  2722                     if (filename == NULL)
  2723                         return PEP_OUT_OF_MEMORY;
  2724 
  2725                     _m = bloblist_add(_m, ptext, psize, mime_type,
  2726                         filename);
  2727                     free(filename);
  2728                     if (_m == NULL)
  2729                         return PEP_OUT_OF_MEMORY;
  2730 
  2731                     ptext = NULL;
  2732 
  2733                     if (msg->attachments == NULL)
  2734                         msg->attachments = _m;
  2735                 }
  2736             }
  2737             else {
  2738                 char *copy = malloc(_s->size);
  2739                 assert(copy);
  2740                 if (copy == NULL)
  2741                     return PEP_OUT_OF_MEMORY;
  2742                 memcpy(copy, _s->value, _s->size);
  2743                 _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  2744                 if (_m == NULL)
  2745                     return PEP_OUT_OF_MEMORY;
  2746             }
  2747         }
  2748         else {
  2749             char *copy = malloc(_s->size);
  2750             assert(copy);
  2751             if (copy == NULL)
  2752                 return PEP_OUT_OF_MEMORY;
  2753             memcpy(copy, _s->value, _s->size);
  2754             _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  2755             if (_m == NULL)
  2756                 return PEP_OUT_OF_MEMORY;
  2757         }
  2758     }
  2759     return status;
  2760 }
  2761 
  2762 static PEP_STATUS import_priv_keys_from_decrypted_msg(PEP_SESSION session,
  2763                                                       message* src, 
  2764                                                       message* msg,
  2765                                                       bool* imported_keys,
  2766                                                       bool* imported_private,
  2767                                                       identity_list** private_il) {
  2768                                                           
  2769     PEP_STATUS status = PEP_STATUS_OK;
  2770     
  2771     // check for private key in decrypted message attachment while importing
  2772     identity_list *_private_il = NULL;
  2773     *imported_keys = import_attached_keys(session, msg, &_private_il);
  2774     
  2775     if (_private_il && identity_list_length(_private_il) == 1 &&
  2776         _private_il->ident->address)
  2777         *imported_private = true;
  2778 
  2779     if (private_il && imported_private) {
  2780         // the private identity list should NOT be subject to myself() or
  2781         // update_identity() at this point.
  2782         // If the receiving app wants them to be in the trust DB, it
  2783         // should call set_own_key() on them upon return.
  2784         // We do, however, prepare these so the app can use them
  2785         // directly in a set_own_key() call by putting the own_id on it.
  2786         char* own_id = NULL;
  2787         status = get_default_own_userid(session, &own_id);
  2788         
  2789         if (status != PEP_STATUS_OK) {
  2790             free(own_id);
  2791             own_id = NULL;
  2792         }
  2793         
  2794         identity_list* il = _private_il;
  2795         for ( ; il; il = il->next) {
  2796             if (own_id) {
  2797                 free(il->ident->user_id);
  2798                 il->ident->user_id = strdup(own_id);
  2799             }
  2800             il->ident->me = true;
  2801         }
  2802         *private_il = _private_il;
  2803         
  2804         free(own_id);
  2805     }
  2806     else
  2807         free_identity_list(_private_il);
  2808  
  2809     
  2810     return status;
  2811 }
  2812 
  2813 static PEP_STATUS update_sender_to_pEp_trust(
  2814         PEP_SESSION session, 
  2815         pEp_identity* sender, 
  2816         stringlist_t* keylist) 
  2817 {
  2818     assert(session);
  2819     assert(sender);
  2820     assert(keylist && !EMPTYSTR(keylist->value));
  2821     
  2822     if (!session || !sender || !keylist || EMPTYSTR(keylist->value))
  2823         return PEP_ILLEGAL_VALUE;
  2824         
  2825     free(sender->fpr);
  2826     sender->fpr = NULL;
  2827     
  2828     PEP_STATUS status = 
  2829             is_me(session, sender) ? myself(session, sender) : update_identity(session, sender);
  2830 
  2831     if (EMPTYSTR(sender->fpr) || strcmp(sender->fpr, keylist->value) != 0) {
  2832         free(sender->fpr);
  2833         sender->fpr = strdup(keylist->value);
  2834         if (!sender->fpr)
  2835             return PEP_OUT_OF_MEMORY;
  2836         status = set_pgp_keypair(session, sender->fpr);
  2837         if (status != PEP_STATUS_OK)
  2838             return status;
  2839             
  2840         status = get_trust(session, sender);
  2841         
  2842         if (status == PEP_CANNOT_FIND_IDENTITY || sender->comm_type == PEP_ct_unknown) {
  2843             PEP_comm_type ct = PEP_ct_unknown;
  2844             status = get_key_rating(session, sender->fpr, &ct);
  2845             if (status != PEP_STATUS_OK)
  2846                 return status;
  2847                 
  2848             sender->comm_type = ct;    
  2849         }
  2850     }
  2851     
  2852     // Could be done elegantly, but we do this explicitly here for readability.
  2853     // This file's code is difficult enough to parse. But change at will.
  2854     switch (sender->comm_type) {
  2855         case PEP_ct_OpenPGP_unconfirmed:
  2856         case PEP_ct_OpenPGP:
  2857             sender->comm_type = PEP_ct_pEp_unconfirmed | (sender->comm_type & PEP_ct_confirmed);
  2858             status = set_trust(session, sender);
  2859             break;
  2860         default:
  2861             status = PEP_CANNOT_SET_TRUST;
  2862             break;
  2863     }
  2864     
  2865     return status;
  2866 }
  2867 
  2868 static PEP_STATUS reconcile_identity(pEp_identity* srcid,
  2869                                      pEp_identity* resultid) {
  2870     assert(srcid);
  2871     assert(resultid);
  2872 
  2873     if (!srcid || !resultid)
  2874         return PEP_ILLEGAL_VALUE;
  2875         
  2876     if (!EMPTYSTR(srcid->user_id)) {
  2877         if (EMPTYSTR(resultid->user_id) ||
  2878              strcmp(srcid->user_id, resultid->user_id) != 0) {
  2879             free(resultid->user_id);
  2880             resultid->user_id = strdup(srcid->user_id);
  2881         }
  2882     }
  2883     
  2884     resultid->lang[0] = srcid->lang[0];
  2885     resultid->me = srcid->me;
  2886     resultid->flags = srcid->flags;
  2887 
  2888     return PEP_STATUS_OK;
  2889 }
  2890 
  2891 static PEP_STATUS reconcile_identity_lists(identity_list* src_ids,
  2892                                            identity_list* result_ids) {
  2893                                            
  2894     identity_list* curr_id = result_ids;
  2895     
  2896     PEP_STATUS status = PEP_STATUS_OK;
  2897     
  2898     while (curr_id) {
  2899         identity_list* curr_src_id = src_ids;
  2900         pEp_identity* result_identity = curr_id->ident;
  2901         
  2902         while (curr_src_id) {
  2903             pEp_identity* source_identity = curr_src_id->ident;
  2904             
  2905             if (EMPTYSTR(source_identity->address) || EMPTYSTR(result_identity->address))
  2906                 return PEP_ILLEGAL_VALUE; // something went badly wrong
  2907             
  2908             if (strcasecmp(source_identity->address, result_identity->address) == 0) {
  2909                 status = reconcile_identity(source_identity, result_identity);
  2910                 if (status != PEP_STATUS_OK)
  2911                     return status;
  2912             }
  2913             curr_src_id = curr_src_id->next;        
  2914         }
  2915         curr_id = curr_id->next;
  2916     }
  2917     return status;    
  2918 }
  2919 
  2920 static PEP_STATUS reconcile_src_and_inner_messages(message* src, 
  2921                                              message* inner_message) {
  2922 
  2923     PEP_STATUS status = PEP_STATUS_OK;
  2924     
  2925     if (strcasecmp(src->from->address, inner_message->from->address) == 0)
  2926         status = reconcile_identity(src->from, inner_message->from);
  2927     
  2928     if (status == PEP_STATUS_OK && inner_message->to)
  2929         status = reconcile_identity_lists(src->to, inner_message->to);
  2930 
  2931     if (status == PEP_STATUS_OK && inner_message->cc)
  2932         status = reconcile_identity_lists(src->cc, inner_message->cc);
  2933 
  2934     if (status == PEP_STATUS_OK && inner_message->bcc)
  2935         status = reconcile_identity_lists(src->bcc, inner_message->bcc);
  2936 
  2937     return status;
  2938     // FIXME - are there any flags or anything else we need to be sure are carried?
  2939 }
  2940 
  2941 static bool is_trusted_own_priv_fpr(PEP_SESSION session, 
  2942                        const char* own_id, 
  2943                        const char* fpr
  2944     ) 
  2945 {   
  2946     bool retval = false;
  2947     if (!EMPTYSTR(fpr)) {
  2948         pEp_identity* test_identity = new_identity(NULL, fpr, own_id, NULL);
  2949         if (test_identity) {
  2950             PEP_STATUS status = get_trust(session, test_identity);
  2951             if (status == PEP_STATUS_OK) {
  2952                 if (test_identity->comm_type & PEP_ct_confirmed) {
  2953                     bool has_priv = false;
  2954                     status = contains_priv_key(session, fpr, &has_priv);
  2955                     if (status == PEP_STATUS_OK && has_priv)
  2956                         retval = true;
  2957                 }
  2958             }
  2959             free(test_identity);
  2960         }
  2961     }
  2962     return retval;
  2963 }
  2964 
  2965 static bool reject_fpr(PEP_SESSION session, const char* fpr) {
  2966     bool reject = true;
  2967 
  2968     PEP_STATUS status = key_revoked(session, fpr, &reject);
  2969 
  2970     if (!reject) {
  2971         status = key_expired(session, fpr, time(NULL), &reject);
  2972         if (reject) {
  2973             timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
  2974             status = renew_key(session, fpr, ts);
  2975             free_timestamp(ts);
  2976             if (status == PEP_STATUS_OK)
  2977                 reject = false;
  2978         }
  2979     }
  2980     return reject;
  2981 }
  2982 
  2983 static char* seek_good_trusted_private_fpr(PEP_SESSION session, char* own_id, 
  2984                                            stringlist_t* keylist) {
  2985     if (!own_id || !keylist)
  2986         return NULL;
  2987         
  2988     stringlist_t* kl_curr = keylist;
  2989     while (kl_curr) {
  2990         char* fpr = kl_curr->value;
  2991         
  2992         if (is_trusted_own_priv_fpr(session, own_id, fpr)) { 
  2993             if (!reject_fpr(session, fpr))
  2994                 return strdup(fpr);
  2995         }
  2996             
  2997         kl_curr = kl_curr->next;
  2998     }
  2999 
  3000     char* target_own_fpr = NULL;
  3001     
  3002     // Last shot...
  3003     PEP_STATUS status = get_user_default_key(session, own_id, 
  3004                                              &target_own_fpr);
  3005 
  3006     if (status == PEP_STATUS_OK && !EMPTYSTR(target_own_fpr)) {
  3007         if (is_trusted_own_priv_fpr(session, own_id, target_own_fpr)) { 
  3008             if (!reject_fpr(session, target_own_fpr))
  3009                 return target_own_fpr;
  3010         }
  3011     }
  3012     
  3013     // TODO: We can also go through all of the other available fprs for the
  3014     // own identity, but then I submit this function requires a little refactoring
  3015         
  3016     return NULL;
  3017 }
  3018 
  3019 DYNAMIC_API PEP_STATUS _decrypt_message(
  3020         PEP_SESSION session,
  3021         message *src,
  3022         message **dst,
  3023         stringlist_t **keylist,
  3024         PEP_rating *rating,
  3025         PEP_decrypt_flags_t *flags,
  3026         identity_list **private_il
  3027     )
  3028 {
  3029     
  3030     assert(session);
  3031     assert(src);
  3032     assert(dst);
  3033     assert(keylist);
  3034     assert(rating);
  3035     assert(flags);
  3036 
  3037     if (!(session && src && dst && keylist && rating && flags))
  3038         return PEP_ILLEGAL_VALUE;
  3039 
  3040     /*** Begin init ***/
  3041     PEP_STATUS status = PEP_STATUS_OK;
  3042     PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
  3043     PEP_STATUS _decrypt_in_pieces_status = PEP_CANNOT_DECRYPT_UNKNOWN;
  3044     message* msg = NULL;
  3045     message* calculated_src = src;
  3046     
  3047     char *ctext;
  3048     size_t csize;
  3049     char *ptext = NULL;
  3050     size_t psize;
  3051     stringlist_t *_keylist = NULL;
  3052     char* signer_fpr = NULL;
  3053     bool is_pEp_msg = is_a_pEpmessage(src);
  3054 
  3055     // Grab input flags
  3056     bool reencrypt = (((*flags & PEP_decrypt_flag_untrusted_server) > 0) && *keylist && !EMPTYSTR((*keylist)->value));
  3057     
  3058     // We own this pointer, and we take control of *keylist if reencrypting.
  3059     stringlist_t* extra = NULL;
  3060     if (reencrypt) {
  3061         if (*keylist) {
  3062             extra = *keylist;
  3063         }
  3064     }
  3065             
  3066     *dst = NULL;
  3067     *keylist = NULL;
  3068     *rating = PEP_rating_undefined;
  3069 //    *flags = 0;
  3070     
  3071     /*** End init ***/
  3072 
  3073     // Ok, before we do anything, if it's a pEp message, regardless of whether it's
  3074     // encrypted or not, we set the sender as a pEp user. This has NOTHING to do
  3075     // with the key.
  3076     if (src->from && !(is_me(session, src->from))) {
  3077         if (is_pEp_msg) {
  3078             pEp_identity* tmp_from = src->from;
  3079             
  3080             // Ensure there's a user id
  3081             if (EMPTYSTR(tmp_from->user_id) && tmp_from->address) {
  3082                 status = update_identity(session, tmp_from);
  3083                 if (status == PEP_CANNOT_FIND_IDENTITY) {
  3084                     tmp_from->user_id = calloc(1, strlen(tmp_from->address) + 6);
  3085                     if (!tmp_from->user_id)
  3086                         return PEP_OUT_OF_MEMORY;
  3087                     snprintf(tmp_from->user_id, strlen(tmp_from->address) + 6,
  3088                              "TOFU_%s", tmp_from->address);        
  3089                     status = PEP_STATUS_OK;
  3090                 }
  3091             }
  3092             if (status == PEP_STATUS_OK) {
  3093                 // Now set user as PEP (may also create an identity if none existed yet)
  3094                 status = set_as_pEp_user(session, tmp_from);
  3095             }
  3096         }
  3097     }
  3098     // We really need key used in signing to do anything further on the pEp comm_type.
  3099     // So we can't adjust the rating of the sender just yet.
  3100 
  3101     /*** Begin Import any attached public keys and update identities accordingly ***/
  3102     // Private key in unencrypted mail are ignored -> NULL
  3103     bool imported_keys = import_attached_keys(session, src, NULL);
  3104 
  3105     // FIXME: is this really necessary here?
  3106     if (!is_me(session, src->from))
  3107         status = update_identity(session, src->from);
  3108     else
  3109         status = myself(session, src->from);
  3110         
  3111     if (status != PEP_STATUS_OK)
  3112         return status;
  3113     
  3114     /*** End Import any attached public keys and update identities accordingly ***/
  3115     
  3116     /*** Begin get detached signatures that are attached to the encrypted message ***/
  3117     // Get detached signature, if any
  3118     bloblist_t* detached_sig = NULL;
  3119     char* dsig_text = NULL;
  3120     size_t dsig_size = 0;
  3121     status = _get_detached_signature(src, &detached_sig);
  3122     if (detached_sig) {
  3123         dsig_text = detached_sig->value;
  3124         dsig_size = detached_sig->size;
  3125     }
  3126     /*** End get detached signatures that are attached to the encrypted message ***/
  3127 
  3128     /*** Determine encryption format ***/
  3129     PEP_cryptotech crypto = determine_encryption_format(src);
  3130 
  3131     // Check for and deal with unencrypted messages
  3132     if (src->enc_format == PEP_enc_none) {
  3133 
  3134         *rating = PEP_rating_unencrypted;
  3135 
  3136         if (imported_keys)
  3137             remove_attached_keys(src);
  3138                                     
  3139         pull_up_attached_main_msg(src);
  3140         
  3141         return PEP_UNENCRYPTED;
  3142     }
  3143 
  3144     status = get_crypto_text(src, &ctext, &csize);
  3145     if (status != PEP_STATUS_OK)
  3146         return status;
  3147         
  3148     /** Ok, we should be ready to decrypt. Try decrypt and verify first! **/
  3149     status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  3150                                                    csize, dsig_text, dsig_size,
  3151                                                    &ptext, &psize, &_keylist);
  3152 
  3153     if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
  3154         goto pEp_error;
  3155 
  3156     decrypt_status = status;
  3157     
  3158     bool imported_private_key_address = false;
  3159 
  3160     if (ptext) { 
  3161         /* we got a plaintext from decryption */
  3162         switch (src->enc_format) {
  3163             
  3164             case PEP_enc_PGP_MIME:
  3165             case PEP_enc_PGP_MIME_Outlook1:
  3166             
  3167                 status = mime_decode_message(ptext, psize, &msg);
  3168                 if (status != PEP_STATUS_OK)
  3169                     goto pEp_error;
  3170                 
  3171                 /* Ensure messages whose maintext is in the attachments
  3172                    move main text into message struct longmsg et al */
  3173                 /* KG: This IS a src modification of old - we're adding to it
  3174                    w/ memhole subject, but the question is whether or not
  3175                    this is OK overall... */
  3176                 pull_up_attached_main_msg(msg);
  3177                 if (msg->shortmsg) {
  3178                     free(src->shortmsg);
  3179                     src->shortmsg = strdup(msg->shortmsg);                    
  3180                 }
  3181 
  3182                 // check for private key in decrypted message attachment while importing
  3183                 // N.B. Apparently, we always import private keys into the keyring; however,
  3184                 // we do NOT always allow those to be used for encryption. THAT is controlled
  3185                 // by setting it as an own identity associated with the key in the DB.
  3186                 status = import_priv_keys_from_decrypted_msg(session, src, msg,
  3187                                                              &imported_keys,
  3188                                                              &imported_private_key_address,
  3189                                                              private_il);
  3190                 if (status != PEP_STATUS_OK)
  3191                     goto pEp_error;            
  3192 
  3193                 /* if decrypted, but not verified... */
  3194                 if (decrypt_status == PEP_DECRYPTED) {
  3195                                                                                      
  3196                     status = verify_decrypted(session,
  3197                                               src, msg,
  3198                                               ptext, psize,
  3199                                               &_keylist,
  3200                                               &decrypt_status,
  3201                                               crypto);
  3202                 }
  3203                 break;
  3204 
  3205             case PEP_enc_pieces:
  3206                 status = PEP_STATUS_OK;
  3207                 
  3208                 _decrypt_in_pieces_status = _decrypt_in_pieces(session, src, &msg, ptext, psize);
  3209             
  3210                 switch (_decrypt_in_pieces_status) {
  3211                     case PEP_DECRYPTED:
  3212                     case PEP_DECRYPTED_AND_VERIFIED:
  3213                         if (decrypt_status <= PEP_DECRYPTED_AND_VERIFIED)
  3214                             decrypt_status = MIN(decrypt_status, _decrypt_in_pieces_status);
  3215                         break;
  3216                     case PEP_STATUS_OK:
  3217                         break;    
  3218                     case PEP_OUT_OF_MEMORY:
  3219                         goto enomem;
  3220                     default:
  3221                         decrypt_status = _decrypt_in_pieces_status;
  3222                         break;
  3223                 }
  3224                 break;
  3225             default:
  3226                 // BUG: must implement more
  3227                 NOT_IMPLEMENTED
  3228         }
  3229 
  3230         if (status == PEP_OUT_OF_MEMORY)
  3231             goto enomem;
  3232             
  3233         if (status != PEP_STATUS_OK)
  3234             goto pEp_error;
  3235 
  3236         if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
  3237             char* wrap_info = NULL;
  3238             
  3239             status = unencapsulate_hidden_fields(src, msg, &wrap_info);
  3240 
  3241 //            bool is_transport_wrapper = false;
  3242             
  3243             // FIXME: replace with enums, check status
  3244             if (wrap_info) {
  3245                 if (strcmp(wrap_info, "OUTER") == 0) {
  3246                     // this only occurs in with a direct outer wrapper
  3247                     // where the actual content is in the inner wrapper
  3248                     message* inner_message = NULL;                    
  3249                     bloblist_t* actual_message = msg->attachments;
  3250                     
  3251                     while (actual_message) {
  3252                         char* mime_type = actual_message->mime_type;
  3253                         if (mime_type) {
  3254                             
  3255                             // libetpan appears to change the mime_type on this one.
  3256                             // *growl*
  3257                             if (strcmp("message/rfc822", mime_type) == 0 ||
  3258                                 strcmp("text/rfc822", mime_type) == 0) {
  3259                                     
  3260                                 status = mime_decode_message(actual_message->value, 
  3261                                                              actual_message->size, 
  3262                                                              &inner_message);
  3263                                 if (status != PEP_STATUS_OK)
  3264                                     goto pEp_error;
  3265                                 
  3266                                 if (inner_message) {
  3267                                     // Though this will strip any message info on the
  3268                                     // attachment, this is safe, as we do not
  3269                                     // produce more than one attachment-as-message,
  3270                                     // and those are the only ones with such info.
  3271                                     // Since we capture the information, this is ok.
  3272                                     wrap_info = NULL;
  3273                                     inner_message->enc_format = src->enc_format;
  3274                                     // FIXME
  3275                                     status = unencapsulate_hidden_fields(inner_message, NULL, &wrap_info);
  3276                                     if (wrap_info) {
  3277                                         // useless check, but just in case we screw up?
  3278                                         if (strcmp(wrap_info, "INNER") == 0) {
  3279                                             if (status != PEP_STATUS_OK) {
  3280                                                 free_message(inner_message);
  3281                                                 goto pEp_error;
  3282                                             }
  3283 
  3284                                             // check for private key in decrypted message attachment while importing
  3285                                             // N.B. Apparently, we always import private keys into the keyring; however,
  3286                                             // we do NOT always allow those to be used for encryption. THAT is controlled
  3287                                             // by setting it as an own identity associated with the key in the DB.
  3288                                             
  3289                                             // If we have a message 2.0 message, we are ONLY going to be ok with keys
  3290                                             // we imported from THIS part of the message.
  3291                                             imported_private_key_address = false;
  3292                                             free(private_il);
  3293                                             private_il = NULL;
  3294                                             status = import_priv_keys_from_decrypted_msg(session, src, inner_message,
  3295                                                                                          &imported_keys,
  3296                                                                                          &imported_private_key_address,
  3297                                                                                          private_il);
  3298                                             if (status != PEP_STATUS_OK)
  3299                                                 goto pEp_error;            
  3300 
  3301                                             // THIS is our message
  3302                                             // Now, let's make sure we've copied in 
  3303                                             // any information sent in by the app if
  3304                                             // needed...
  3305                                             reconcile_src_and_inner_messages(src, inner_message);
  3306                                             
  3307                                             // FIXME: free msg, but check references
  3308                                             //src = msg = inner_message;
  3309                                             calculated_src = msg = inner_message;
  3310                                             
  3311                                             if (src->from) {
  3312                                                 if (!is_me(session, src->from))
  3313                                                     update_identity(session, (src->from));
  3314                                                 else
  3315                                                     myself(session, src->from);
  3316                                             }
  3317                                             break;        
  3318                                         }
  3319                                         else { // should never happen
  3320                                             status = PEP_UNKNOWN_ERROR;
  3321                                             free_message(inner_message);
  3322                                             goto pEp_error;
  3323                                         }
  3324                                     }
  3325                                     inner_message->enc_format = PEP_enc_none;
  3326                                 }
  3327                                 else { // forwarded message, leave it alone
  3328                                     free_message(inner_message);
  3329                                 }
  3330                             }
  3331                         }
  3332                         actual_message = actual_message->next;
  3333                     }                    
  3334                 }
  3335                 else if (strcmp(wrap_info, "TRANSPORT") == 0) {
  3336                     // FIXME: this gets even messier.
  3337                     // (TBI in ENGINE-278)
  3338                 }
  3339                 else {} // shouldn't be anything to be done here
  3340             }
  3341         }
  3342         
  3343         *rating = decrypt_rating(decrypt_status);
  3344         
  3345         // Ok, so if it was signed and it's all verified, we can update
  3346         // eligible signer comm_types to PEP_ct_pEp_*
  3347         if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && is_pEp_msg)
  3348             status = update_sender_to_pEp_trust(session, calculated_src->from, _keylist);
  3349 
  3350         /* Ok, now we have a keylist used for decryption/verification.
  3351            now we need to update the message rating with the 
  3352            sender and recipients in mind */
  3353         status = amend_rating_according_to_sender_and_recipients(session,
  3354                  rating, calculated_src->from, _keylist);
  3355 
  3356         if (status != PEP_STATUS_OK)
  3357             goto pEp_error;
  3358         
  3359         /* We decrypted ok, hallelujah. */
  3360         msg->enc_format = PEP_enc_none;    
  3361     } 
  3362     else {
  3363         // We did not get a plaintext out of the decryption process.
  3364         // Abort and return error.
  3365         *rating = decrypt_rating(decrypt_status);
  3366         goto pEp_error;
  3367     }
  3368 
  3369     /* 
  3370        Ok, at this point, we know we have a reliably decrypted message.
  3371        Prepare the output message for return.
  3372     */
  3373     
  3374     // 1. Check to see if this message is to us and contains an own key imported 
  3375     // from own trusted message
  3376     if (*rating >= PEP_rating_trusted && imported_private_key_address) {
  3377 
  3378         if (msg && msg->to && msg->to->ident) {            
  3379             // This will only happen rarely, so we can do this.
  3380             PEP_STATUS _tmp_status = PEP_STATUS_OK;
  3381             
  3382             if (!is_me(session, msg->to->ident))
  3383                 _tmp_status = update_identity(session, msg->to->ident);
  3384             
  3385             if (_tmp_status == PEP_STATUS_OK && is_me(session, msg->to->ident)) {
  3386                 // flag it as such
  3387                 *flags |= PEP_decrypt_flag_own_private_key;
  3388             }
  3389         }
  3390     }
  3391 
  3392     // 2. Clean up message and prepare for return 
  3393     if (msg) {
  3394         
  3395         /* add pEp-related status flags to header */
  3396         decorate_message(msg, *rating, _keylist, false, false);
  3397         
  3398         if (imported_keys)
  3399             remove_attached_keys(msg);
  3400                     
  3401         if (calculated_src->id && calculated_src != msg) {
  3402             msg->id = strdup(calculated_src->id);
  3403             assert(msg->id);
  3404             if (msg->id == NULL)
  3405                 goto enomem;
  3406         }
  3407     } // End prepare output message for return
  3408 
  3409     *dst = msg;
  3410     *keylist = _keylist;
  3411 
  3412     if (reencrypt) {
  3413         if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
  3414             message* reencrypt_msg = NULL;
  3415             PEP_STATUS reencrypt_status = PEP_CANNOT_REENCRYPT;
  3416             char* own_id = NULL;
  3417             status = get_default_own_userid(session, &own_id);
  3418             if (own_id) {
  3419                 char* target_own_fpr = seek_good_trusted_private_fpr(session,
  3420                                                                      own_id,
  3421                                                                      _keylist);
  3422                 if (target_own_fpr) {
  3423                     pEp_identity* target_id = new_identity(NULL, target_own_fpr, 
  3424                                                            own_id, NULL);
  3425                     if (target_id) {
  3426                         reencrypt_status = encrypt_message_for_self(session, target_id, msg,
  3427                                                                     extra, &reencrypt_msg, PEP_enc_PGP_MIME,
  3428                                                                     0);
  3429                         if (reencrypt_status != PEP_STATUS_OK)
  3430                             reencrypt_status = PEP_CANNOT_REENCRYPT;
  3431                         
  3432                         free_identity(target_id);
  3433                     }
  3434                     free(target_own_fpr);
  3435                 }     
  3436                 free(own_id);
  3437             }
  3438             free_stringlist(extra); // This was an input variable for us. Keylist is overwritten above.
  3439             
  3440             if (reencrypt_status != PEP_CANNOT_REENCRYPT && reencrypt_msg) {
  3441                 message_transfer(src, reencrypt_msg);
  3442                 *flags |= PEP_decrypt_flag_src_modified;
  3443                 free_message(reencrypt_msg);
  3444             }
  3445             else
  3446                 decrypt_status = PEP_CANNOT_REENCRYPT;
  3447         }
  3448     }
  3449         
  3450     if(decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
  3451         return PEP_STATUS_OK;
  3452     else
  3453         return decrypt_status;
  3454 
  3455 enomem:
  3456     status = PEP_OUT_OF_MEMORY;
  3457 
  3458 pEp_error:
  3459     free(ptext);
  3460     free(signer_fpr);
  3461     free_message(msg);
  3462     free_stringlist(_keylist);
  3463 
  3464     return status;
  3465 }
  3466 
  3467 DYNAMIC_API PEP_STATUS decrypt_message(
  3468         PEP_SESSION session,
  3469         message *src,
  3470         message **dst,
  3471         stringlist_t **keylist,
  3472         PEP_rating *rating,
  3473         PEP_decrypt_flags_t *flags
  3474     )
  3475 {
  3476     PEP_STATUS status = _decrypt_message(session, src, dst, keylist, rating, flags, NULL);
  3477 
  3478     if (session->inject_sync_event && *dst && (*dst)->attachments) {
  3479         for (bloblist_t *bl = (*dst)->attachments; bl ; bl = bl->next) {
  3480             if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0)
  3481                 signal_Sync_message(session, *rating, bl->value, bl->size);
  3482         }
  3483     }
  3484 
  3485     return status;
  3486 }
  3487 
  3488 DYNAMIC_API PEP_STATUS own_message_private_key_details(
  3489         PEP_SESSION session,
  3490         message *msg,
  3491         pEp_identity **ident
  3492     )
  3493 {
  3494     assert(session);
  3495     assert(msg);
  3496     assert(ident);
  3497 
  3498     if (!(session && msg && ident))
  3499         return PEP_ILLEGAL_VALUE;
  3500 
  3501     message *dst = NULL;
  3502     stringlist_t *keylist = NULL;
  3503     PEP_rating rating;
  3504     PEP_decrypt_flags_t flags;
  3505 
  3506     *ident = NULL;
  3507 
  3508     identity_list *private_il = NULL;
  3509     PEP_STATUS status = _decrypt_message(session, msg,  &dst, &keylist, &rating, &flags, &private_il);
  3510     free_message(dst);
  3511     free_stringlist(keylist);
  3512 
  3513     if (status == PEP_STATUS_OK &&
  3514         flags & PEP_decrypt_flag_own_private_key &&
  3515         private_il)
  3516     {
  3517         *ident = identity_dup(private_il->ident);
  3518     }
  3519 
  3520     free_identity_list(private_il);
  3521 
  3522     return status;
  3523 }
  3524 
  3525 // Note: if comm_type_determine is false, it generally means that
  3526 // we were unable to get key information for anyone in the list,
  3527 // likely because a key is missing.
  3528 static void _max_comm_type_from_identity_list(
  3529         identity_list *identities,
  3530         PEP_SESSION session,
  3531         PEP_comm_type *max_comm_type,
  3532         bool *comm_type_determined
  3533     )
  3534 {
  3535     identity_list * il;
  3536     for (il = identities; il != NULL; il = il->next)
  3537     {
  3538         if (il->ident)
  3539         {   
  3540             PEP_STATUS status = PEP_STATUS_OK;
  3541             *max_comm_type = _get_comm_type(session, *max_comm_type,
  3542                 il->ident);
  3543             *comm_type_determined = true;
  3544             
  3545             bool is_blacklisted = false;
  3546             if (il->ident->fpr && IS_PGP_CT(il->ident->comm_type)) {
  3547                 status = blacklist_is_listed(session, il->ident->fpr, &is_blacklisted);
  3548                 if (is_blacklisted) {
  3549                     bool user_default, ident_default, address_default; 
  3550                     status = get_valid_pubkey(session, il->ident,
  3551                                               &ident_default, &user_default,
  3552                                               &address_default,
  3553                                               true);
  3554                     if (status != PEP_STATUS_OK || il->ident->fpr == NULL) {
  3555                         il->ident->comm_type = PEP_ct_key_not_found;
  3556                     }
  3557                 }    
  3558             }
  3559     
  3560             // check for the return statuses which might not a representative
  3561             // value in the comm_type
  3562             if (status == PEP_ILLEGAL_VALUE || status == PEP_CANNOT_SET_PERSON ||
  3563                 status == PEP_CANNOT_FIND_IDENTITY) {
  3564                 // PEP_CANNOT_FIND_IDENTITY only comes back when we've really
  3565                 // got nothing from update_identity after applying the whole
  3566                 // heuristic
  3567                 *max_comm_type = PEP_ct_no_encryption;
  3568                 *comm_type_determined = true;
  3569             }
  3570         }
  3571     }
  3572 }
  3573 
  3574 DYNAMIC_API PEP_STATUS outgoing_message_rating(
  3575         PEP_SESSION session,
  3576         message *msg,
  3577         PEP_rating *rating
  3578     )
  3579 {
  3580     PEP_comm_type max_comm_type = PEP_ct_pEp;
  3581     bool comm_type_determined = false;
  3582 
  3583     assert(session);
  3584     assert(msg);
  3585     assert(msg->dir == PEP_dir_outgoing);
  3586     assert(rating);
  3587 
  3588     if (!(session && msg && rating))
  3589         return PEP_ILLEGAL_VALUE;
  3590 
  3591     if (msg->dir != PEP_dir_outgoing)
  3592         return PEP_ILLEGAL_VALUE;
  3593 
  3594     *rating = PEP_rating_undefined;
  3595 
  3596     _max_comm_type_from_identity_list(msg->to, session,
  3597                                       &max_comm_type, &comm_type_determined);
  3598 
  3599     _max_comm_type_from_identity_list(msg->cc, session,
  3600                                       &max_comm_type, &comm_type_determined);
  3601 
  3602     _max_comm_type_from_identity_list(msg->bcc, session,
  3603                                       &max_comm_type, &comm_type_determined);
  3604 
  3605     if (comm_type_determined == false) {
  3606         // likely means there was a massive screwup with no sender or recipient
  3607         // keys
  3608         *rating = PEP_rating_undefined;
  3609     }
  3610     else
  3611         *rating = MAX(_rating(max_comm_type, PEP_rating_undefined),
  3612                                PEP_rating_unencrypted);
  3613 
  3614     return PEP_STATUS_OK;
  3615 }
  3616 
  3617 DYNAMIC_API PEP_STATUS identity_rating(
  3618         PEP_SESSION session,
  3619         pEp_identity *ident,
  3620         PEP_rating *rating
  3621     )
  3622 {
  3623     PEP_STATUS status = PEP_STATUS_OK;
  3624 
  3625     assert(session);
  3626     assert(ident);
  3627     assert(rating);
  3628 
  3629     if (!(session && ident && rating))
  3630         return PEP_ILLEGAL_VALUE;
  3631 
  3632     if (ident->me)
  3633         status = _myself(session, ident, false, true);
  3634     else
  3635         status = update_identity(session, ident);
  3636 
  3637     bool is_blacklisted = false;
  3638     
  3639     if (ident->fpr && IS_PGP_CT(ident->comm_type)) {
  3640         status = blacklist_is_listed(session, ident->fpr, &is_blacklisted);
  3641         if (status != PEP_STATUS_OK) {
  3642             return status; // DB ERROR
  3643         }
  3644         if (is_blacklisted) {
  3645             bool user_default, ident_default, address_default; 
  3646             status = get_valid_pubkey(session, ident,
  3647                                        &ident_default, &user_default,
  3648                                        &address_default,
  3649                                        true);
  3650             if (status != PEP_STATUS_OK || ident->fpr == NULL) {
  3651                 ident->comm_type = PEP_ct_key_not_found;
  3652                 status = PEP_STATUS_OK;                        
  3653             }
  3654         }    
  3655     }
  3656 
  3657     if (status == PEP_STATUS_OK)
  3658         *rating = _rating(ident->comm_type, PEP_rating_undefined);
  3659 
  3660     return status;
  3661 }
  3662 
  3663 DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
  3664 {
  3665     PEP_STATUS status = PEP_STATUS_OK;
  3666 
  3667     assert(path);
  3668     if (path == NULL)
  3669         return PEP_ILLEGAL_VALUE;
  3670 
  3671     if (cryptotech[tech].binary_path == NULL)
  3672         *path = NULL;
  3673     else
  3674         status = cryptotech[tech].binary_path(path);
  3675 
  3676     return status;
  3677 }
  3678 
  3679 
  3680 DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
  3681 {
  3682     if (rating == PEP_rating_b0rken || rating == PEP_rating_have_no_key)
  3683         return PEP_color_no_color;
  3684 
  3685     if (rating < PEP_rating_undefined)
  3686         return PEP_color_red;
  3687 
  3688     if (rating < PEP_rating_reliable)
  3689         return PEP_color_no_color;
  3690 
  3691     if (rating < PEP_rating_trusted)
  3692         return PEP_color_yellow;
  3693 
  3694     if (rating >= PEP_rating_trusted)
  3695         return PEP_color_green;
  3696 
  3697     // this should never happen
  3698     assert(false);
  3699     return PEP_color_no_color;
  3700 }
  3701 
  3702 /* [0-9]: 0x30 - 0x39; [A-F] = 0x41 - 0x46; [a-f] = 0x61 - 0x66 */
  3703 static short asciihex_to_num(char a) {
  3704     short conv_num = -1;
  3705     if (a >= 0x30 && a <= 0x39)
  3706         conv_num = a - 0x30;
  3707     else {
  3708         // convert case, subtract offset, get number
  3709         conv_num = ((a | 0x20) - 0x61) + 10;
  3710         if (conv_num < 0xa || conv_num > 0xf)
  3711             conv_num = -1;
  3712     }
  3713     return conv_num;
  3714 }
  3715 
  3716 static char num_to_asciihex(short h) {
  3717     if (h < 0 || h > 16)
  3718         return '\0';
  3719     if (h < 10)
  3720         return (char)(h + 0x30);
  3721     return (char)((h - 10) + 0x41); // for readability
  3722 }
  3723 
  3724 static char xor_hex_chars(char a, char b) {
  3725     short a_num = asciihex_to_num(a);
  3726     short b_num = asciihex_to_num(b);
  3727     if (a_num < 0 || b_num < 0)
  3728         return '\0';
  3729     short xor_num = a_num^b_num;
  3730     return num_to_asciihex(xor_num);
  3731 }
  3732 
  3733 static char* skip_separators(char* current, char* begin) {
  3734     while (current >= begin) {
  3735         /* .:,;-_ ' ' - [2c-2e] [3a-3b] [20] [5f] */
  3736         char check_char = *current;
  3737         switch (check_char) {
  3738             case '.':
  3739             case ':':
  3740             case ',':
  3741             case ';':
  3742             case '-':
  3743             case '_':
  3744             case ' ':
  3745                 current--;
  3746                 continue;
  3747             default:
  3748                 break;
  3749         }
  3750         break;
  3751     }
  3752     return current;
  3753 }
  3754 
  3755 PEP_STATUS check_for_zero_fpr(char* fpr) {
  3756     PEP_STATUS status = PEP_TRUSTWORDS_DUPLICATE_FPR;
  3757     
  3758     while (*fpr) {
  3759         if (*fpr != '0') {
  3760             status = PEP_STATUS_OK;
  3761             break;
  3762         }
  3763         fpr++;    
  3764     }
  3765     
  3766     return status;
  3767     
  3768 }
  3769 
  3770 DYNAMIC_API PEP_STATUS get_trustwords(
  3771     PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
  3772     const char* lang, char **words, size_t *wsize, bool full
  3773 )
  3774 {
  3775     assert(session);
  3776     assert(id1);
  3777     assert(id2);
  3778     assert(id1->fpr);
  3779     assert(id2->fpr);
  3780     assert(words);
  3781     assert(wsize);
  3782 
  3783     int SHORT_NUM_TWORDS = 5; 
  3784     
  3785     PEP_STATUS status = PEP_STATUS_OK;
  3786     
  3787     if (!(session && id1 && id2 && words && wsize) ||
  3788         !(id1->fpr) || (!id2->fpr))
  3789         return PEP_ILLEGAL_VALUE;
  3790 
  3791     char *source1 = id1->fpr;
  3792     char *source2 = id2->fpr;
  3793 
  3794     int source1_len = strlen(source1);
  3795     int source2_len = strlen(source2);
  3796     int max_len;
  3797         
  3798     *words = NULL;    
  3799     *wsize = 0;
  3800 
  3801     max_len = (source1_len > source2_len ? source1_len : source2_len);
  3802     
  3803     char* XORed_fpr = (char*)(calloc(max_len + 1, 1));
  3804     *(XORed_fpr + max_len) = '\0';
  3805     char* result_curr = XORed_fpr + max_len - 1;
  3806     char* source1_curr = source1 + source1_len - 1;
  3807     char* source2_curr = source2 + source2_len - 1;
  3808 
  3809     while (source1 <= source1_curr && source2 <= source2_curr) {
  3810         source1_curr = skip_separators(source1_curr, source1);
  3811         source2_curr = skip_separators(source2_curr, source2);
  3812         
  3813         if (source1_curr < source1 || source2_curr < source2)
  3814             break;
  3815             
  3816         char xor_hex = xor_hex_chars(*source1_curr, *source2_curr);
  3817         if (xor_hex == '\0') {
  3818             status = PEP_ILLEGAL_VALUE;
  3819             goto error_release;
  3820         }
  3821         
  3822         *result_curr = xor_hex;
  3823         result_curr--; source1_curr--; source2_curr--;
  3824     }
  3825 
  3826     char* remainder_start = NULL;
  3827     char* remainder_curr = NULL;
  3828     
  3829     if (source1 <= source1_curr) {
  3830         remainder_start = source1;
  3831         remainder_curr = source1_curr;
  3832     }
  3833     else if (source2 <= source2_curr) {
  3834         remainder_start = source2;
  3835         remainder_curr = source2_curr;
  3836     }
  3837     if (remainder_curr) {
  3838         while (remainder_start <= remainder_curr) {
  3839             remainder_curr = skip_separators(remainder_curr, remainder_start);
  3840             
  3841             if (remainder_curr < remainder_start)
  3842                 break;
  3843             
  3844             char the_char = *remainder_curr;
  3845             
  3846             if (asciihex_to_num(the_char) < 0) {
  3847                 status = PEP_ILLEGAL_VALUE;
  3848                 goto error_release;
  3849             }
  3850             
  3851             *result_curr = the_char;                
  3852             result_curr--;
  3853             remainder_curr--;
  3854         }
  3855     }
  3856     
  3857     result_curr++;
  3858 
  3859     if (result_curr > XORed_fpr) {
  3860         char* tempstr = strdup(result_curr);
  3861         free(XORed_fpr);
  3862         XORed_fpr = tempstr;
  3863     }
  3864     
  3865     status = check_for_zero_fpr(XORed_fpr);
  3866     
  3867     if (status != PEP_STATUS_OK)
  3868         goto error_release;
  3869     
  3870     size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
  3871 
  3872     char* the_words = NULL;
  3873     size_t the_size = 0;
  3874 
  3875     status = trustwords(session, XORed_fpr, lang, &the_words, &the_size, max_words_per_id);
  3876     if (status != PEP_STATUS_OK)
  3877         goto error_release;
  3878 
  3879     *words = the_words;
  3880     *wsize = the_size;
  3881     
  3882     status = PEP_STATUS_OK;
  3883 
  3884     goto the_end;
  3885 
  3886     error_release:
  3887         free (XORed_fpr);
  3888         
  3889     the_end:
  3890     return status;
  3891 }
  3892 
  3893 DYNAMIC_API PEP_STATUS get_message_trustwords(
  3894     PEP_SESSION session, 
  3895     message *msg,
  3896     stringlist_t *keylist,
  3897     pEp_identity* received_by,
  3898     const char* lang, char **words, bool full
  3899 )
  3900 {
  3901     assert(session);
  3902     assert(msg);
  3903     assert(received_by);
  3904     assert(received_by->address);
  3905     assert(lang);
  3906     assert(words);
  3907 
  3908     if (!(session && 
  3909           msg &&
  3910           received_by && 
  3911           received_by->address && 
  3912           lang && 
  3913           words))
  3914         return PEP_ILLEGAL_VALUE;
  3915     
  3916     pEp_identity* partner = NULL;
  3917      
  3918     PEP_STATUS status = PEP_STATUS_OK;
  3919     
  3920     *words = NULL;
  3921 
  3922     // We want fingerprint of key that did sign the message
  3923 
  3924     if (keylist == NULL) {
  3925 
  3926         // Message is to be decrypted
  3927         message *dst = NULL;
  3928         stringlist_t *_keylist = keylist;
  3929         PEP_rating rating;
  3930         PEP_decrypt_flags_t flags;
  3931         status = decrypt_message( session, msg, &dst, &_keylist, &rating, &flags);
  3932 
  3933         if (status != PEP_STATUS_OK) {
  3934             free_message(dst);
  3935             free_stringlist(_keylist);
  3936             return status;
  3937         }
  3938 
  3939         if (dst && dst->from && _keylist) {
  3940             partner = identity_dup(dst->from); 
  3941             if(partner){
  3942                 free(partner->fpr);
  3943                 partner->fpr = strdup(_keylist->value);
  3944                 if (partner->fpr == NULL)
  3945                     status = PEP_OUT_OF_MEMORY;
  3946             } else {
  3947                 status = PEP_OUT_OF_MEMORY;
  3948             }
  3949         } else {
  3950             status = PEP_UNKNOWN_ERROR;
  3951         }
  3952 
  3953         free_message(dst);
  3954         free_stringlist(_keylist);
  3955 
  3956     } else {
  3957 
  3958         // Message already decrypted
  3959         if (keylist->value) {
  3960             partner = identity_dup(msg->from); 
  3961             if(partner){
  3962                 free(partner->fpr);
  3963                 partner->fpr = strdup(keylist->value);
  3964                 if (partner->fpr == NULL)
  3965                     status = PEP_OUT_OF_MEMORY;
  3966             } else {
  3967                 status = PEP_OUT_OF_MEMORY;
  3968             }
  3969         } else {
  3970             status = PEP_ILLEGAL_VALUE;
  3971         }
  3972     }
  3973 
  3974     if (status != PEP_STATUS_OK) {
  3975         free_identity(partner);
  3976         return status;
  3977     }
  3978    
  3979     // Find own identity corresponding to given account address.
  3980     // In that case we want default key attached to own identity
  3981     pEp_identity *stored_identity = NULL;
  3982     status = get_identity(session,
  3983                           received_by->address,
  3984                           PEP_OWN_USERID,
  3985                           &stored_identity);
  3986 
  3987     if (status != PEP_STATUS_OK) {
  3988         free_identity(stored_identity);
  3989         return status;
  3990     }
  3991 
  3992     // get the trustwords
  3993     size_t wsize;
  3994     status = get_trustwords(session, 
  3995                             partner, received_by, 
  3996                             lang, words, &wsize, full);
  3997 
  3998     return status;
  3999 }
  4000 
  4001 DYNAMIC_API PEP_STATUS MIME_decrypt_message(
  4002     PEP_SESSION session,
  4003     const char *mimetext,
  4004     size_t size,
  4005     char** mime_plaintext,
  4006     stringlist_t **keylist,
  4007     PEP_rating *rating,
  4008     PEP_decrypt_flags_t *flags,
  4009     char** modified_src
  4010 )
  4011 {
  4012     assert(mimetext);
  4013     assert(mime_plaintext);
  4014     assert(keylist);
  4015     assert(rating);
  4016     assert(flags);
  4017     assert(modified_src);
  4018 
  4019     if (!(mimetext && mime_plaintext && keylist && rating && flags && modified_src))
  4020         return PEP_ILLEGAL_VALUE;
  4021         
  4022     PEP_STATUS status = PEP_STATUS_OK;
  4023     message* tmp_msg = NULL;
  4024     message* dec_msg = NULL;
  4025     *mime_plaintext = NULL;
  4026 
  4027     status = mime_decode_message(mimetext, size, &tmp_msg);
  4028     if (status != PEP_STATUS_OK)
  4029         goto pEp_error;
  4030 
  4031     // MIME decode message delivers only addresses. We need more.
  4032     if (tmp_msg->from) {
  4033         if (!is_me(session, tmp_msg->from))
  4034             status = update_identity(session, (tmp_msg->from));
  4035         else
  4036             status = myself(session, tmp_msg->from);
  4037 
  4038         if (status == PEP_ILLEGAL_VALUE || status == PEP_OUT_OF_MEMORY)
  4039             goto pEp_error;
  4040     }
  4041 
  4042     status = update_identity_recip_list(session, tmp_msg->to);
  4043     if (status != PEP_STATUS_OK)
  4044         goto pEp_error;
  4045 
  4046     status = update_identity_recip_list(session, tmp_msg->cc);
  4047     if (status != PEP_STATUS_OK)
  4048         goto pEp_error;
  4049 
  4050     status = update_identity_recip_list(session, tmp_msg->bcc);
  4051     if (status != PEP_STATUS_OK)
  4052         goto pEp_error;
  4053 
  4054     PEP_STATUS decrypt_status = decrypt_message(session,
  4055                                                 tmp_msg,
  4056                                                 &dec_msg,
  4057                                                 keylist,
  4058                                                 rating,
  4059                                                 flags);
  4060 
  4061 
  4062     if (!dec_msg && (decrypt_status == PEP_UNENCRYPTED || decrypt_status == PEP_VERIFIED)) {
  4063         dec_msg = message_dup(tmp_msg);
  4064     }
  4065     
  4066     if (decrypt_status > PEP_CANNOT_DECRYPT_UNKNOWN || !dec_msg)
  4067     {
  4068         status = decrypt_status;
  4069         goto pEp_error;
  4070     }
  4071 
  4072     if (*flags & PEP_decrypt_flag_src_modified) {
  4073         _mime_encode_message_internal(tmp_msg, false, modified_src, true);
  4074         if (!modified_src) {
  4075             *flags &= (~PEP_decrypt_flag_src_modified);
  4076             decrypt_status = PEP_CANNOT_REENCRYPT; // Because we couldn't return it, I guess.
  4077         }
  4078     }
  4079 
  4080     // FIXME: test with att
  4081     status = _mime_encode_message_internal(dec_msg, false, mime_plaintext, true);
  4082 
  4083     if (status == PEP_STATUS_OK)
  4084     {
  4085         free(tmp_msg);
  4086         free(dec_msg);
  4087         return decrypt_status;
  4088     }
  4089     
  4090 pEp_error:
  4091     free_message(tmp_msg);
  4092     free_message(dec_msg);
  4093 
  4094     return status;
  4095 }
  4096 
  4097 
  4098 DYNAMIC_API PEP_STATUS MIME_encrypt_message(
  4099     PEP_SESSION session,
  4100     const char *mimetext,
  4101     size_t size,
  4102     stringlist_t* extra,
  4103     char** mime_ciphertext,
  4104     PEP_enc_format enc_format,
  4105     PEP_encrypt_flags_t flags
  4106 )
  4107 {
  4108     PEP_STATUS status = PEP_STATUS_OK;
  4109     message* tmp_msg = NULL;
  4110     message* enc_msg = NULL;
  4111 
  4112     status = mime_decode_message(mimetext, size, &tmp_msg);
  4113     if (status != PEP_STATUS_OK)
  4114         goto pEp_error;
  4115 
  4116     // MIME decode message delivers only addresses. We need more.
  4117     if (tmp_msg->from) {
  4118         char* own_id = NULL;
  4119         status = get_default_own_userid(session, &own_id);
  4120         free(tmp_msg->from->user_id);
  4121         
  4122         if (status != PEP_STATUS_OK || !own_id) {
  4123             tmp_msg->from->user_id = strdup(PEP_OWN_USERID);
  4124         }
  4125         else {
  4126             tmp_msg->from->user_id = own_id; // ownership transfer
  4127         }
  4128             
  4129         status = myself(session, tmp_msg->from);
  4130         if (status != PEP_STATUS_OK)
  4131             goto pEp_error;
  4132     }
  4133     
  4134     // Own identities can be retrieved here where they would otherwise
  4135     // fail because we lack all other information. This is ok and even
  4136     // desired. FIXME: IS it?
  4137     status = update_identity_recip_list(session, tmp_msg->to);
  4138     if (status != PEP_STATUS_OK)
  4139         goto pEp_error;
  4140     
  4141     status = update_identity_recip_list(session, tmp_msg->cc);
  4142     if (status != PEP_STATUS_OK)
  4143         goto pEp_error;
  4144     
  4145     status = update_identity_recip_list(session, tmp_msg->bcc);
  4146     if (status != PEP_STATUS_OK)
  4147         goto pEp_error;
  4148     
  4149     // This isn't incoming, though... so we need to reverse the direction
  4150     tmp_msg->dir = PEP_dir_outgoing;
  4151     status = encrypt_message(session,
  4152                              tmp_msg,
  4153                              extra,
  4154                              &enc_msg,
  4155                              enc_format,
  4156                              flags);
  4157                              
  4158     if (status != PEP_STATUS_OK)
  4159         goto pEp_error;
  4160 
  4161 
  4162     if (!enc_msg) {
  4163         status = PEP_UNKNOWN_ERROR;
  4164         goto pEp_error;
  4165     }
  4166 
  4167     status = _mime_encode_message_internal(enc_msg, false, mime_ciphertext, false);
  4168 
  4169 pEp_error:
  4170     free_message(tmp_msg);
  4171     free_message(enc_msg);
  4172 
  4173     return status;
  4174 
  4175 }
  4176 
  4177 DYNAMIC_API PEP_STATUS MIME_encrypt_message_for_self(
  4178     PEP_SESSION session,
  4179     pEp_identity* target_id,
  4180     const char *mimetext,
  4181     size_t size,
  4182     stringlist_t* extra,
  4183     char** mime_ciphertext,
  4184     PEP_enc_format enc_format,
  4185     PEP_encrypt_flags_t flags
  4186 )
  4187 {
  4188     PEP_STATUS status = PEP_STATUS_OK;
  4189     message* tmp_msg = NULL;
  4190     message* enc_msg = NULL;
  4191 
  4192     status = mime_decode_message(mimetext, size, &tmp_msg);
  4193     if (status != PEP_STATUS_OK)
  4194         goto pEp_error;
  4195 
  4196     // This isn't incoming, though... so we need to reverse the direction
  4197     tmp_msg->dir = PEP_dir_outgoing;
  4198     status = encrypt_message_for_self(session,
  4199                                       target_id,
  4200                                       tmp_msg,
  4201                                       extra,
  4202                                       &enc_msg,
  4203                                       enc_format,
  4204                                       flags);
  4205     if (status != PEP_STATUS_OK)
  4206         goto pEp_error;
  4207  
  4208     if (!enc_msg) {
  4209         status = PEP_UNKNOWN_ERROR;
  4210         goto pEp_error;
  4211     }
  4212 
  4213     status = mime_encode_message(enc_msg, false, mime_ciphertext);
  4214 
  4215 pEp_error:
  4216     free_message(tmp_msg);
  4217     free_message(enc_msg);
  4218 
  4219     return status;
  4220 }
  4221 
  4222 static PEP_rating string_to_rating(const char * rating)
  4223 {
  4224     if (rating == NULL)
  4225         return PEP_rating_undefined;
  4226     if (strcmp(rating, "cannot_decrypt") == 0)
  4227         return PEP_rating_cannot_decrypt;
  4228     if (strcmp(rating, "have_no_key") == 0)
  4229         return PEP_rating_have_no_key;
  4230     if (strcmp(rating, "unencrypted") == 0)
  4231         return PEP_rating_unencrypted;
  4232     if (strcmp(rating, "unencrypted_for_some") == 0)
  4233         return PEP_rating_unencrypted_for_some;
  4234     if (strcmp(rating, "unreliable") == 0)
  4235         return PEP_rating_unreliable;
  4236     if (strcmp(rating, "reliable") == 0)
  4237         return PEP_rating_reliable;
  4238     if (strcmp(rating, "trusted") == 0)
  4239         return PEP_rating_trusted;
  4240     if (strcmp(rating, "trusted_and_anonymized") == 0)
  4241         return PEP_rating_trusted_and_anonymized;
  4242     if (strcmp(rating, "fully_anonymous") == 0)
  4243         return PEP_rating_fully_anonymous;
  4244     if (strcmp(rating, "mistrust") == 0)
  4245         return PEP_rating_mistrust;
  4246     if (strcmp(rating, "b0rken") == 0)
  4247         return PEP_rating_b0rken;
  4248     if (strcmp(rating, "under_attack") == 0)
  4249         return PEP_rating_under_attack;
  4250     return PEP_rating_undefined;
  4251 }
  4252 
  4253 static PEP_STATUS string_to_keylist(const char * skeylist, stringlist_t **keylist)
  4254 {
  4255     if (skeylist == NULL || keylist == NULL)
  4256         return PEP_ILLEGAL_VALUE;
  4257 
  4258     stringlist_t *rkeylist = NULL;
  4259     stringlist_t *_kcurr = NULL;
  4260     const char * fpr_begin = skeylist;
  4261     const char * fpr_end = NULL;
  4262 
  4263     do {
  4264         fpr_end = strstr(fpr_begin, ",");
  4265         
  4266         char * fpr = strndup(
  4267             fpr_begin,
  4268             (fpr_end == NULL) ? strlen(fpr_begin) : fpr_end - fpr_begin);
  4269         
  4270         if (fpr == NULL)
  4271             goto enomem;
  4272         
  4273         _kcurr = stringlist_add(_kcurr, fpr);
  4274         if (_kcurr == NULL) {
  4275             free(fpr);
  4276             goto enomem;
  4277         }
  4278         
  4279         if (rkeylist == NULL)
  4280             rkeylist = _kcurr;
  4281         
  4282         fpr_begin = fpr_end ? fpr_end + 1 : NULL;
  4283         
  4284     } while (fpr_begin);
  4285     
  4286     *keylist = rkeylist;
  4287     return PEP_STATUS_OK;
  4288     
  4289 enomem:
  4290     free_stringlist(rkeylist);
  4291     return PEP_OUT_OF_MEMORY;
  4292 }
  4293 
  4294 DYNAMIC_API PEP_STATUS re_evaluate_message_rating(
  4295     PEP_SESSION session,
  4296     message *msg,
  4297     stringlist_t *x_keylist,
  4298     PEP_rating x_enc_status,
  4299     PEP_rating *rating
  4300 )
  4301 {
  4302     PEP_STATUS status = PEP_STATUS_OK;
  4303     stringlist_t *_keylist = x_keylist;
  4304     bool must_free_keylist = false;
  4305     PEP_rating _rating;
  4306 
  4307     assert(session);
  4308     assert(msg);
  4309     assert(rating);
  4310 
  4311     if (!(session && msg && rating))
  4312         return PEP_ILLEGAL_VALUE;
  4313 
  4314     *rating = PEP_rating_undefined;
  4315 
  4316     if (x_enc_status == PEP_rating_undefined){
  4317         for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
  4318             if (strcasecmp(i->value->key, "X-EncStatus") == 0){
  4319                 x_enc_status = string_to_rating(i->value->value);
  4320                 goto got_rating;
  4321             }
  4322         }
  4323         return PEP_ILLEGAL_VALUE;
  4324     }
  4325 
  4326 got_rating:
  4327 
  4328     _rating = x_enc_status;
  4329 
  4330     if (_keylist == NULL){
  4331         for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
  4332             if (strcasecmp(i->value->key, "X-KeyList") == 0){
  4333                 status = string_to_keylist(i->value->value, &_keylist);
  4334                 if (status != PEP_STATUS_OK)
  4335                     goto pEp_error;
  4336                 must_free_keylist = true;
  4337                 goto got_keylist;
  4338             }
  4339         }
  4340 
  4341         // there was no rcpt fpr, it could be an unencrypted mail
  4342         if(_rating == PEP_rating_unencrypted) {
  4343             *rating = _rating;
  4344             return PEP_STATUS_OK;
  4345         }
  4346 
  4347         return PEP_ILLEGAL_VALUE;
  4348     }
  4349 got_keylist:
  4350 
  4351     if (!is_me(session, msg->from))
  4352         status = update_identity(session, msg->from);
  4353     else
  4354         status = myself(session, msg->from);
  4355 
  4356     switch (status) {
  4357         case PEP_KEY_NOT_FOUND:
  4358         case PEP_KEY_UNSUITABLE:
  4359         case PEP_KEY_BLACKLISTED:
  4360         case PEP_CANNOT_FIND_IDENTITY:
  4361         case PEP_CANNOT_FIND_ALIAS:
  4362             status = PEP_STATUS_OK;
  4363         case PEP_STATUS_OK:
  4364             break;
  4365         default:
  4366             goto pEp_error;
  4367     }
  4368 
  4369     status = amend_rating_according_to_sender_and_recipients(session, &_rating,
  4370             msg->from, _keylist);
  4371     if (status == PEP_STATUS_OK)
  4372         *rating = _rating;
  4373     
  4374 pEp_error:
  4375     if (must_free_keylist)
  4376         free_stringlist(_keylist);
  4377 
  4378     return status;
  4379 }