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