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