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