src/message_api.c
author Krista 'DarthMama' Bennett <krista@pep.foundation>
Wed, 07 Aug 2019 12:14:53 +0200
branchENGINE-559
changeset 3958 092843cb7ad2
parent 3955 77d397b32029
parent 3945 7de09fb6c9c9
child 3962 9bf0c18c719c
child 3963 60b100beecb3
permissions -rw-r--r--
merge
     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         return false;        
  1093     if (strcmp(msg->attachments->mime_type, "application/pgp-encrypted") != 0)    
  1094         return false;
  1095     if (!msg->attachments->next->mime_type || 
  1096         strcmp(msg->attachments->next->mime_type, "application/octet-stream") != 0)        
  1097         return false;
  1098     return true;    
  1099 }
  1100 
  1101 static PEP_rating _rating(PEP_comm_type ct)
  1102 {
  1103     if (ct == PEP_ct_unknown)
  1104         return PEP_rating_undefined;
  1105 
  1106     else if (ct == PEP_ct_key_not_found)
  1107         return PEP_rating_have_no_key;
  1108 
  1109     else if (ct == PEP_ct_compromised)
  1110         return PEP_rating_under_attack;
  1111 
  1112     else if (ct == PEP_ct_mistrusted)
  1113         return PEP_rating_mistrust;
  1114 
  1115     if (ct == PEP_ct_no_encryption || ct == PEP_ct_no_encrypted_channel ||
  1116             ct == PEP_ct_my_key_not_included)
  1117             return PEP_rating_unencrypted;
  1118 
  1119     if (ct >= PEP_ct_confirmed_enc_anon)
  1120         return PEP_rating_trusted_and_anonymized;
  1121 
  1122     else if (ct >= PEP_ct_strong_encryption)
  1123         return PEP_rating_trusted;
  1124 
  1125     else if (ct >= PEP_ct_strong_but_unconfirmed && ct < PEP_ct_confirmed)
  1126         return PEP_rating_reliable;
  1127 
  1128     else
  1129         return PEP_rating_unreliable;
  1130 }
  1131 
  1132 static bool is_encrypted_attachment(const bloblist_t *blob)
  1133 {
  1134     assert(blob);
  1135 
  1136     if (blob == NULL || blob->filename == NULL || is_cid_uri(blob->filename))
  1137         return false;
  1138 
  1139     char *ext = strrchr(blob->filename, '.');
  1140     if (ext == NULL)
  1141         return false;
  1142 
  1143     if (strcmp(blob->mime_type, "application/octet-stream") == 0) {
  1144         if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0)
  1145             return true;
  1146     }
  1147     if (strcmp(ext, ".asc") == 0 && blob->size > 0) {            
  1148         const char* pubk_needle = "BEGIN PGP PUBLIC KEY";
  1149         size_t pubk_needle_size = strlen(pubk_needle);
  1150         const char* privk_needle = "BEGIN PGP PRIVATE KEY";
  1151         size_t privk_needle_size = strlen(privk_needle);
  1152 
  1153         if (!(_memnmemn(pubk_needle, pubk_needle_size, blob->value, blob->size)) &&
  1154             !(_memnmemn(privk_needle, privk_needle_size, blob->value, blob->size)))
  1155             return true;
  1156     }
  1157 
  1158     return false;
  1159 }
  1160 
  1161 static bool is_encrypted_html_attachment(const bloblist_t *blob)
  1162 {
  1163     assert(blob);
  1164     assert(blob->filename);
  1165     if (blob == NULL || blob->filename == NULL || is_cid_uri(blob->filename))
  1166         return false;
  1167 
  1168     const char* bare_filename_ptr = _get_resource_ptr_noown(blob->filename);
  1169     bare_filename_ptr += strlen(bare_filename_ptr) - 15;
  1170     if (strncmp(bare_filename_ptr, "PGPexch.htm.", 12) == 0) {
  1171         if (strcmp(bare_filename_ptr + 11, ".pgp") == 0 ||
  1172             strcmp(bare_filename_ptr + 11, ".asc") == 0)
  1173             return true;
  1174     }
  1175 
  1176     return false;
  1177 }
  1178 
  1179 static char * without_double_ending(const char *filename)
  1180 {
  1181     assert(filename);
  1182     if (filename == NULL || is_cid_uri(filename))
  1183         return NULL;
  1184 
  1185     char *ext = strrchr(filename, '.');
  1186     if (ext == NULL)
  1187         return NULL;
  1188 
  1189     char *result = strndup(filename, ext - filename);
  1190     assert(result);
  1191     return result;
  1192 }
  1193 
  1194 static PEP_rating decrypt_rating(PEP_STATUS status)
  1195 {
  1196     switch (status) {
  1197     case PEP_UNENCRYPTED:
  1198     case PEP_VERIFIED:
  1199     case PEP_VERIFY_NO_KEY:
  1200     case PEP_VERIFIED_AND_TRUSTED:
  1201         return PEP_rating_unencrypted;
  1202 
  1203     case PEP_DECRYPTED:
  1204     case PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH:
  1205         return PEP_rating_unreliable;
  1206 
  1207     case PEP_DECRYPTED_AND_VERIFIED:
  1208         return PEP_rating_reliable;
  1209 
  1210     case PEP_DECRYPT_NO_KEY:
  1211         return PEP_rating_have_no_key;
  1212 
  1213     case PEP_DECRYPT_WRONG_FORMAT:
  1214     case PEP_CANNOT_DECRYPT_UNKNOWN:
  1215         return PEP_rating_cannot_decrypt;
  1216 
  1217     default:
  1218         return PEP_rating_undefined;
  1219     }
  1220 }
  1221 
  1222 static PEP_rating key_rating(PEP_SESSION session, const char *fpr)
  1223 {
  1224 
  1225     assert(session);
  1226     assert(fpr);
  1227 
  1228     if (session == NULL || fpr == NULL)
  1229         return PEP_rating_undefined;
  1230 
  1231 
  1232     PEP_comm_type bare_comm_type = PEP_ct_unknown;
  1233     PEP_comm_type resulting_comm_type = PEP_ct_unknown;
  1234     PEP_STATUS status = get_key_rating(session, fpr, &bare_comm_type);
  1235     if (status != PEP_STATUS_OK)
  1236         return PEP_rating_undefined;
  1237 
  1238     PEP_comm_type least_comm_type = PEP_ct_unknown;
  1239     least_trust(session, fpr, &least_comm_type);
  1240 
  1241     if (least_comm_type == PEP_ct_unknown) {
  1242         resulting_comm_type = bare_comm_type;
  1243     } else if (least_comm_type < PEP_ct_strong_but_unconfirmed ||
  1244                bare_comm_type < PEP_ct_strong_but_unconfirmed) {
  1245         // take minimum if anything bad
  1246         resulting_comm_type = least_comm_type < bare_comm_type ? 
  1247                               least_comm_type : 
  1248                               bare_comm_type;
  1249     } else {
  1250         resulting_comm_type = least_comm_type;
  1251     }
  1252     return _rating(resulting_comm_type);
  1253 }
  1254 
  1255 static PEP_rating worst_rating(PEP_rating rating1, PEP_rating rating2) {
  1256     return ((rating1 < rating2) ? rating1 : rating2);
  1257 }
  1258 
  1259 static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist, char* sender_fpr, PEP_rating sender_rating)
  1260 {
  1261     PEP_rating rating = sender_rating;
  1262 
  1263     assert(keylist && keylist->value);
  1264     if (keylist == NULL || keylist->value == NULL)
  1265         return PEP_rating_undefined;
  1266 
  1267     stringlist_t *_kl;
  1268     for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
  1269 
  1270         // Ignore own fpr
  1271         if(_same_fpr(sender_fpr, strlen(sender_fpr), _kl->value, strlen(_kl->value)))
  1272             continue;
  1273 
  1274         PEP_rating _rating_ = key_rating(session, _kl->value);
  1275          
  1276         if (_rating_ <= PEP_rating_mistrust)
  1277             return _rating_;
  1278             
  1279         rating = worst_rating(rating, _rating_);
  1280     }
  1281 
  1282     return rating;
  1283 }
  1284 
  1285 // Internal function WARNING:
  1286 // Only call this on an ident that might have its FPR set from retrieval!
  1287 // (or on one without an fpr)
  1288 // We do not want myself() setting the fpr here.
  1289 static PEP_comm_type _get_comm_type(
  1290     PEP_SESSION session,
  1291     PEP_comm_type max_comm_type,
  1292     pEp_identity *ident
  1293     )
  1294 {
  1295     PEP_STATUS status = PEP_STATUS_OK;
  1296 
  1297     if (max_comm_type == PEP_ct_compromised)
  1298         return PEP_ct_compromised;
  1299 
  1300     if (max_comm_type == PEP_ct_mistrusted)
  1301         return PEP_ct_mistrusted;
  1302 
  1303     if (!is_me(session, ident))
  1304         status = update_identity(session, ident);
  1305     else
  1306         // ???
  1307         status = _myself(session, ident, false, false, true);
  1308 
  1309     if (status == PEP_STATUS_OK) {
  1310         if (ident->comm_type == PEP_ct_compromised)
  1311             return PEP_ct_compromised;
  1312         else if (ident->comm_type == PEP_ct_mistrusted)
  1313             return PEP_ct_mistrusted;
  1314         else
  1315             return MIN(max_comm_type, ident->comm_type);
  1316     }
  1317     else {
  1318         return PEP_ct_unknown;
  1319     }
  1320 }
  1321 
  1322 static PEP_comm_type _get_comm_type_preview(
  1323     PEP_SESSION session,
  1324     PEP_comm_type max_comm_type,
  1325     pEp_identity *ident
  1326     )
  1327 {
  1328     assert(session);
  1329     assert(ident);
  1330 
  1331     PEP_STATUS status = PEP_STATUS_OK;
  1332 
  1333     if (max_comm_type == PEP_ct_compromised)
  1334         return PEP_ct_compromised;
  1335 
  1336     if (max_comm_type == PEP_ct_mistrusted)
  1337         return PEP_ct_mistrusted;
  1338 
  1339     PEP_comm_type comm_type = PEP_ct_unknown;
  1340     if (ident && !EMPTYSTR(ident->address) && !EMPTYSTR(ident->user_id)) {
  1341         pEp_identity *ident2;
  1342         status = get_identity(session, ident->address, ident->user_id, &ident2);
  1343         comm_type = ident2 ? ident2->comm_type : PEP_ct_unknown;
  1344         free_identity(ident2);
  1345 
  1346         if (status == PEP_STATUS_OK) {
  1347             if (comm_type == PEP_ct_compromised)
  1348                 comm_type = PEP_ct_compromised;
  1349             else if (comm_type == PEP_ct_mistrusted)
  1350                 comm_type = PEP_ct_mistrusted;
  1351             else
  1352                 comm_type = _MIN(max_comm_type, comm_type);
  1353         }
  1354         else {
  1355             comm_type = PEP_ct_unknown;
  1356         }
  1357     }
  1358     return comm_type;
  1359 }
  1360 
  1361 // static void free_bl_entry(bloblist_t *bl)
  1362 // {
  1363 //     if (bl) {
  1364 //         free(bl->value);
  1365 //         free(bl->mime_type);
  1366 //         free(bl->filename);
  1367 //         free(bl);
  1368 //     }
  1369 // }
  1370 
  1371 static bool is_key(const bloblist_t *bl)
  1372 {
  1373     return (// workaround for Apple Mail bugs
  1374             (is_mime_type(bl, "application/x-apple-msg-attachment") &&
  1375              is_fileending(bl, ".asc")) ||
  1376             // as binary, by file name
  1377             ((bl->mime_type == NULL ||
  1378               is_mime_type(bl, "application/octet-stream")) &&
  1379              (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
  1380                     is_fileending(bl, ".key") || is_fileending(bl, ".asc"))) ||
  1381             // explicit mime type
  1382             is_mime_type(bl, "application/pgp-keys") ||
  1383             // as text, by file name
  1384             (is_mime_type(bl, "text/plain") &&
  1385              (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
  1386                     is_fileending(bl, ".key") || is_fileending(bl, ".asc")))
  1387            );
  1388 }
  1389 
  1390 // static void remove_attached_keys(message *msg)
  1391 // {
  1392 //     if (msg) {
  1393 //         bloblist_t *last = NULL;
  1394 //         for (bloblist_t *bl = msg->attachments; bl && bl->value; ) {
  1395 //             bloblist_t *next = bl->next;
  1396 // 
  1397 //             if (is_key(bl)) {
  1398 //                 if (last) {
  1399 //                     last->next = next;
  1400 //                 }
  1401 //                 else {
  1402 //                     msg->attachments = next;
  1403 //                 }
  1404 //                 free_bl_entry(bl);
  1405 //             }
  1406 //             else {
  1407 //                 last = bl;
  1408 //             }
  1409 //             bl = next;
  1410 //         }
  1411 //     }
  1412 // }
  1413 
  1414 static bool compare_first_n_bytes(const char* first, const char* second, size_t n) {
  1415     int i;
  1416     for (i = 0; i < n; i++) {
  1417         char num1 = *first;
  1418         char num2 = *second;
  1419 
  1420         if (num1 != num2)
  1421             return false;
  1422                     
  1423         if (num1 == '\0') {
  1424             if (num2 == '\0')
  1425                 return true;
  1426         }   
  1427         first++;
  1428         second++;                     
  1429     }
  1430     return true;
  1431 }
  1432 
  1433 bool import_attached_keys(
  1434         PEP_SESSION session,
  1435         message *msg,
  1436         identity_list **private_idents
  1437     )
  1438 {
  1439     assert(session);
  1440     assert(msg);
  1441 
  1442     if (session == NULL || msg == NULL)
  1443         return false;
  1444 
  1445     bool remove = false;
  1446 
  1447     int i = 0;
  1448     
  1449     bloblist_t* prev = NULL;
  1450     
  1451     bool do_not_advance = false;
  1452     const char* pubkey_header = "-----BEGIN PGP PUBLIC KEY BLOCK-----";
  1453     const char* privkey_header = "-----BEGIN PGP PRIVATE KEY BLOCK-----";
  1454     // Hate my magic numbers at your peril, but I don't want a strlen each time
  1455     const size_t PUBKEY_HSIZE = 36;
  1456     const size_t PRIVKEY_HSIZE = 37;
  1457 
  1458     for (bloblist_t *bl = msg->attachments; i < MAX_KEYS_TO_IMPORT && bl && bl->value;
  1459          i++)
  1460     {
  1461         do_not_advance = false;
  1462         if (bl && bl->value && bl->size && bl->size < MAX_KEY_SIZE
  1463                 && is_key(bl))
  1464         {
  1465             char* blob_value = bl->value;
  1466             size_t blob_size = bl->size;
  1467             bool free_blobval = false;
  1468             
  1469             if (is_encrypted_attachment(bl)) {
  1470                     
  1471                 char* bl_ptext = NULL;
  1472                 size_t bl_psize = 0;
  1473                 stringlist_t* bl_keylist = NULL;
  1474                 PEP_STATUS _status = decrypt_and_verify(session, 
  1475                                                         blob_value, blob_size,
  1476                                                         NULL, 0,
  1477                                                         &bl_ptext, &bl_psize, 
  1478                                                         &bl_keylist,
  1479                                                         NULL);
  1480                 free_stringlist(bl_keylist); // we don't care about key encryption as long as we decrypt
  1481                 if (_status == PEP_DECRYPTED || _status == PEP_DECRYPTED_AND_VERIFIED) {
  1482                     free_blobval = true;
  1483                     blob_value = bl_ptext;
  1484                     blob_size = bl_psize;
  1485                 }
  1486                 else {
  1487                     // This is an encrypted attachment we can do nothing with.
  1488                     // We shouldn't delete it or import it, because we can't
  1489                     // do the latter.
  1490                     free(bl_ptext);
  1491                     prev = bl;
  1492                     bl = bl->next;
  1493                     continue;
  1494                 }
  1495             }
  1496             identity_list *local_private_idents = NULL;
  1497             PEP_STATUS import_status = import_key(session, blob_value, blob_size, &local_private_idents);
  1498             bloblist_t* to_delete = NULL;
  1499             switch (import_status) {
  1500                 case PEP_NO_KEY_IMPORTED:
  1501                     break;
  1502                 case PEP_KEY_IMPORT_STATUS_UNKNOWN:
  1503                     // We'll delete armoured stuff, at least
  1504                     if (blob_size <= PUBKEY_HSIZE)
  1505                         break;
  1506                     if ((!compare_first_n_bytes(pubkey_header, (const char*)blob_value, PUBKEY_HSIZE)) &&
  1507                        (!compare_first_n_bytes(privkey_header, (const char*)blob_value, PRIVKEY_HSIZE)))
  1508                         break;
  1509                     // else fall through and delete    
  1510                 case PEP_KEY_IMPORTED:
  1511                 case PEP_STATUS_OK:
  1512                     to_delete = bl;
  1513                     if (prev)
  1514                         prev->next = bl->next;
  1515                     else
  1516                         msg->attachments = bl->next;
  1517                     bl = bl->next;
  1518                     to_delete->next = NULL;
  1519                     free_bloblist(to_delete);
  1520                     do_not_advance = true;
  1521                     remove = true;
  1522                     break;
  1523                 default:  
  1524                     // bad stuff, but ok.
  1525                     break;
  1526             }
  1527             if (private_idents && *private_idents == NULL && local_private_idents != NULL)
  1528                 *private_idents = local_private_idents;
  1529             else
  1530                 free_identity_list(local_private_idents);
  1531             if (free_blobval)
  1532                 free(blob_value);
  1533         }
  1534         if (!do_not_advance) {
  1535             prev = bl;
  1536             bl = bl->next;
  1537         }
  1538     }
  1539     return remove;
  1540 }
  1541 
  1542 
  1543 PEP_STATUS _attach_key(PEP_SESSION session, const char* fpr, message *msg)
  1544 {
  1545     char *keydata = NULL;
  1546     size_t size = 0;
  1547 
  1548     PEP_STATUS status = export_key(session, fpr, &keydata, &size);
  1549     assert(status == PEP_STATUS_OK);
  1550     if (status != PEP_STATUS_OK)
  1551         return status;
  1552     assert(size);
  1553 
  1554     bloblist_t *bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
  1555                       "file://pEpkey.asc");
  1556 
  1557     if (msg->attachments == NULL && bl)
  1558         msg->attachments = bl;
  1559 
  1560     return PEP_STATUS_OK;
  1561 }
  1562 
  1563 #define ONE_WEEK (7*24*3600)
  1564 
  1565 void attach_own_key(PEP_SESSION session, message *msg)
  1566 {
  1567     assert(session);
  1568     assert(msg);
  1569 
  1570     if (msg->dir == PEP_dir_incoming)
  1571         return;
  1572 
  1573     assert(msg->from && msg->from->fpr);
  1574     if (msg->from == NULL || msg->from->fpr == NULL)
  1575         return;
  1576 
  1577     if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
  1578         return;
  1579 
  1580     char *revoked_fpr = NULL;
  1581     uint64_t revocation_date = 0;
  1582 
  1583     if(get_revoked(session, msg->from->fpr,
  1584                    &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
  1585        revoked_fpr != NULL)
  1586     {
  1587         time_t now = time(NULL);
  1588 
  1589         if (now < (time_t)revocation_date + ONE_WEEK)
  1590         {
  1591             _attach_key(session, revoked_fpr, msg);
  1592         }
  1593     }
  1594     free(revoked_fpr);
  1595 }
  1596 
  1597 PEP_cryptotech determine_encryption_format(message *msg)
  1598 {
  1599     assert(msg);
  1600 
  1601     if (is_PGP_message_text(msg->longmsg)) {
  1602         msg->enc_format = PEP_enc_inline;
  1603         return PEP_crypt_OpenPGP;
  1604     }
  1605     else if (msg->attachments && msg->attachments->next &&
  1606             is_mime_type(msg->attachments, "application/pgp-encrypted") &&
  1607             is_PGP_message_text(msg->attachments->next->value)
  1608         ) {
  1609         msg->enc_format = PEP_enc_PGP_MIME;
  1610         return PEP_crypt_OpenPGP;
  1611     }
  1612     else if (msg->attachments && msg->attachments->next &&
  1613             is_mime_type(msg->attachments->next, "application/pgp-encrypted") &&
  1614             is_PGP_message_text(msg->attachments->value)
  1615         ) {
  1616         msg->enc_format = PEP_enc_PGP_MIME_Outlook1;
  1617         return PEP_crypt_OpenPGP;
  1618     }
  1619     else {
  1620         msg->enc_format = PEP_enc_none;
  1621         return PEP_crypt_none;
  1622     }
  1623 }
  1624 
  1625 static void _cleanup_src(message* src, bool remove_attached_key) {
  1626     assert(src);
  1627     
  1628     if (!src)
  1629         return;
  1630         
  1631     char* longmsg = NULL;
  1632     char* shortmsg = NULL;
  1633     char* msg_wrap_info = NULL;
  1634     if (src->longmsg)
  1635         separate_short_and_long(src->longmsg, &shortmsg, &msg_wrap_info,
  1636                                 &longmsg);
  1637     if (longmsg) {                    
  1638         free(src->longmsg);
  1639         free(shortmsg);
  1640         free(msg_wrap_info);
  1641         src->longmsg = longmsg;
  1642     }
  1643     if (remove_attached_key) {
  1644         // End of the attachment list
  1645         if (src->attachments) {
  1646             bloblist_t* tmp = src->attachments;
  1647             while (tmp->next && tmp->next->next) {
  1648                 tmp = tmp->next;
  1649             }
  1650             free_bloblist(tmp->next);
  1651             tmp->next = NULL;
  1652         }    
  1653     }                   
  1654 }
  1655 
  1656 DYNAMIC_API PEP_STATUS encrypt_message(
  1657         PEP_SESSION session,
  1658         message *src,
  1659         stringlist_t * extra,
  1660         message **dst,
  1661         PEP_enc_format enc_format,
  1662         PEP_encrypt_flags_t flags
  1663     )
  1664 {
  1665     PEP_STATUS status = PEP_STATUS_OK;
  1666     message * msg = NULL;
  1667     stringlist_t * keys = NULL;
  1668     message* _src = src;
  1669 
  1670     bool added_key_to_real_src = false;
  1671     
  1672     assert(session);
  1673     assert(src && src->from);
  1674     assert(dst);
  1675 
  1676     if (!(session && src && src->from && dst))
  1677         return PEP_ILLEGAL_VALUE;
  1678 
  1679     if (src->dir == PEP_dir_incoming)
  1680         return PEP_ILLEGAL_VALUE;
  1681 
  1682     determine_encryption_format(src);
  1683     // TODO: change this for multi-encryption in message format 2.0
  1684     if (src->enc_format != PEP_enc_none)
  1685         return PEP_ILLEGAL_VALUE;
  1686 
  1687     bool force_v_1 = flags & PEP_encrypt_flag_force_version_1;
  1688     
  1689     *dst = NULL;
  1690 
  1691     if (!src->from->user_id || src->from->user_id[0] == '\0') {
  1692         char* own_id = NULL;
  1693         status = get_default_own_userid(session, &own_id);
  1694         if (own_id) {
  1695             free(src->from->user_id);
  1696             src->from->user_id = own_id; // ownership transfer
  1697         }
  1698     }
  1699     
  1700     status = myself(session, src->from);
  1701     if (status != PEP_STATUS_OK)
  1702         goto pEp_error;
  1703 
  1704     char* send_fpr = strdup(src->from->fpr ? src->from->fpr : "");
  1705     src->_sender_fpr = send_fpr;
  1706     
  1707     keys = new_stringlist(send_fpr);
  1708     if (keys == NULL)
  1709         goto enomem;
  1710 
  1711     stringlist_t *_k = keys;
  1712 
  1713     if (extra) {
  1714         _k = stringlist_append(_k, extra);
  1715         if (_k == NULL)
  1716             goto enomem;
  1717     }
  1718 
  1719     bool dest_keys_found = true;
  1720     bool has_pEp_user = false;
  1721     
  1722     PEP_comm_type max_comm_type = PEP_ct_pEp;
  1723     unsigned int max_version_major = 0;
  1724     unsigned int max_version_minor = 0;
  1725     pEp_version_major_minor(PEP_VERSION, &max_version_major, &max_version_minor);
  1726     
  1727     identity_list * _il = NULL;
  1728 
  1729     if (enc_format != PEP_enc_none && (_il = src->bcc) && _il->ident)
  1730     // BCC limited support:
  1731     {
  1732         //     - App splits mails with BCC in multiple mails.
  1733         //     - Each email is encrypted separately
  1734         if(_il->next || (src->to && src->to->ident) || (src->cc && src->cc->ident))
  1735         {
  1736             // Only one Bcc with no other recipient allowed for now
  1737             return PEP_ILLEGAL_VALUE;
  1738         }
  1739 
  1740         PEP_STATUS _status = PEP_STATUS_OK;
  1741         if (!is_me(session, _il->ident)) {
  1742             _status = update_identity(session, _il->ident);
  1743             if (_status == PEP_CANNOT_FIND_IDENTITY) {
  1744                 _il->ident->comm_type = PEP_ct_key_not_found;
  1745                 _status = PEP_STATUS_OK;
  1746             }
  1747             // 0 unless set, so safe.
  1748             
  1749             set_min_version( _il->ident->major_ver, _il->ident->minor_ver, 
  1750                              max_version_major, max_version_minor,
  1751                              &max_version_major, &max_version_minor);
  1752 
  1753             bool is_blacklisted = false;
  1754             if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
  1755                 _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
  1756                 if (_status != PEP_STATUS_OK) {
  1757                     // DB error
  1758                     status = PEP_UNENCRYPTED;
  1759                     goto pEp_error;
  1760                 }
  1761                 if (is_blacklisted) {
  1762                     bool user_default, ident_default, address_default; 
  1763                     _status = get_valid_pubkey(session, _il->ident,
  1764                                                &ident_default, &user_default,
  1765                                                &address_default,
  1766                                                true);
  1767                     if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
  1768                         _il->ident->comm_type = PEP_ct_key_not_found;
  1769                         _status = PEP_STATUS_OK;                        
  1770                     }
  1771                 }    
  1772             }
  1773             if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
  1774                 is_pEp_user(session, _il->ident, &has_pEp_user);
  1775         }
  1776         else
  1777             _status = myself(session, _il->ident);
  1778         
  1779         if (_status != PEP_STATUS_OK) {
  1780             status = PEP_UNENCRYPTED;
  1781             goto pEp_error;
  1782         }
  1783 
  1784         if (_il->ident->fpr && _il->ident->fpr[0]) {
  1785             _k = stringlist_add(_k, _il->ident->fpr);
  1786             if (_k == NULL)
  1787                 goto enomem;
  1788             max_comm_type = _get_comm_type(session, max_comm_type,
  1789                                            _il->ident);
  1790         }
  1791         else {
  1792             dest_keys_found = false;
  1793             status = PEP_KEY_NOT_FOUND;
  1794         }
  1795     }
  1796     else // Non BCC
  1797     {
  1798         for (_il = src->to; _il && _il->ident; _il = _il->next) {
  1799             PEP_STATUS _status = PEP_STATUS_OK;
  1800             if (!is_me(session, _il->ident)) {
  1801                 _status = update_identity(session, _il->ident);
  1802                 if (_status == PEP_CANNOT_FIND_IDENTITY) {
  1803                     _il->ident->comm_type = PEP_ct_key_not_found;
  1804                     _status = PEP_STATUS_OK;
  1805                 }
  1806                 // 0 unless set, so safe.
  1807                 set_min_version( _il->ident->major_ver, _il->ident->minor_ver, 
  1808                                  max_version_major, max_version_minor,
  1809                                  &max_version_major, &max_version_minor);
  1810                 
  1811                 bool is_blacklisted = false;
  1812                 if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
  1813                     _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
  1814                     if (_status != PEP_STATUS_OK) {
  1815                         // DB error
  1816                         status = PEP_UNENCRYPTED;
  1817                         goto pEp_error;
  1818                     }
  1819                     if (is_blacklisted) {
  1820                         bool user_default, ident_default, address_default; 
  1821                         _status = get_valid_pubkey(session, _il->ident,
  1822                                                    &ident_default, &user_default,
  1823                                                    &address_default,
  1824                                                    true);
  1825                         if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
  1826                             _il->ident->comm_type = PEP_ct_key_not_found;
  1827                             _status = PEP_STATUS_OK;                        
  1828                         }
  1829                     }    
  1830                 }
  1831                 if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
  1832                     is_pEp_user(session, _il->ident, &has_pEp_user);
  1833                 
  1834                 _status = bind_own_ident_with_contact_ident(session, src->from, _il->ident);
  1835                 if (_status != PEP_STATUS_OK) {
  1836                     status = PEP_UNKNOWN_DB_ERROR;
  1837                     goto pEp_error;
  1838                 }
  1839     
  1840             }
  1841             else
  1842                 _status = myself(session, _il->ident);
  1843                 
  1844             if (_status != PEP_STATUS_OK) {
  1845                 status = PEP_UNENCRYPTED;
  1846                 goto pEp_error;
  1847             }
  1848 
  1849             if (_il->ident->fpr && _il->ident->fpr[0]) {
  1850                 _k = stringlist_add(_k, _il->ident->fpr);
  1851                 if (_k == NULL)
  1852                     goto enomem;
  1853                 max_comm_type = _get_comm_type(session, max_comm_type,
  1854                                                _il->ident);
  1855             }
  1856             else {
  1857                 dest_keys_found = false;
  1858                 status = PEP_KEY_NOT_FOUND;
  1859             }
  1860         }
  1861 
  1862         for (_il = src->cc; _il && _il->ident; _il = _il->next) {
  1863             PEP_STATUS _status = PEP_STATUS_OK;
  1864             if (!is_me(session, _il->ident)) {
  1865                 _status = update_identity(session, _il->ident);
  1866                 if (_status == PEP_CANNOT_FIND_IDENTITY) {
  1867                     _il->ident->comm_type = PEP_ct_key_not_found;
  1868                     _status = PEP_STATUS_OK;
  1869                 }
  1870                 bool is_blacklisted = false;
  1871                 if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
  1872                     _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
  1873                     if (_status != PEP_STATUS_OK) {
  1874                         // DB error
  1875                         status = PEP_UNENCRYPTED;
  1876                         goto pEp_error;
  1877                     }
  1878                     if (is_blacklisted) {
  1879                         bool user_default, ident_default, address_default; 
  1880                         _status = get_valid_pubkey(session, _il->ident,
  1881                                                    &ident_default, &user_default,
  1882                                                    &address_default,
  1883                                                    true);
  1884                         if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
  1885                             _il->ident->comm_type = PEP_ct_key_not_found;
  1886                             _status = PEP_STATUS_OK;                        
  1887                         }
  1888                     }    
  1889                 }
  1890                 if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
  1891                     is_pEp_user(session, _il->ident, &has_pEp_user);
  1892             }
  1893             else
  1894                 _status = myself(session, _il->ident);
  1895             if (_status != PEP_STATUS_OK)
  1896             {
  1897                 status = PEP_UNENCRYPTED;
  1898                 goto pEp_error;
  1899             }
  1900 
  1901             if (_il->ident->fpr && _il->ident->fpr[0]) {
  1902                 _k = stringlist_add(_k, _il->ident->fpr);
  1903                 if (_k == NULL)
  1904                     goto enomem;
  1905                 max_comm_type = _get_comm_type(session, max_comm_type,
  1906                                                _il->ident);
  1907             }
  1908             else {
  1909                 dest_keys_found = false;
  1910             }
  1911         }
  1912     }
  1913     
  1914     if (max_version_major == 1)
  1915         force_v_1 = true;
  1916         
  1917     if (enc_format == PEP_enc_none || !dest_keys_found ||
  1918         stringlist_length(keys)  == 0 ||
  1919         _rating(max_comm_type) < PEP_rating_reliable)
  1920     {
  1921         free_stringlist(keys);
  1922         if ((has_pEp_user || !session->passive_mode) && 
  1923             !(flags & PEP_encrypt_flag_force_no_attached_key)) {
  1924             attach_own_key(session, src);
  1925             added_key_to_real_src = true;
  1926         }
  1927         decorate_message(src, PEP_rating_undefined, NULL, true, true);
  1928         return PEP_UNENCRYPTED;
  1929     }
  1930     else {
  1931         // FIXME - we need to deal with transport types (via flag)
  1932         message_wrap_type wrap_type = PEP_message_unwrapped;
  1933         if ((enc_format != PEP_enc_inline) && (!force_v_1) && ((max_comm_type | PEP_ct_confirmed) == PEP_ct_pEp)) {
  1934             wrap_type = ((flags & PEP_encrypt_flag_key_reset_only) ? PEP_message_key_reset : PEP_message_default);
  1935             _src = wrap_message_as_attachment(NULL, src, wrap_type, false, max_version_major, max_version_minor);
  1936             if (!_src)
  1937                 goto pEp_error;
  1938         }
  1939         else {
  1940             // hide subject
  1941             if (enc_format != PEP_enc_inline && !session->unencrypted_subject) {
  1942                 status = replace_subject(_src);
  1943                 if (status == PEP_OUT_OF_MEMORY)
  1944                     goto enomem;
  1945             }
  1946             if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  1947                 added_key_to_real_src = true;            
  1948         }
  1949         if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  1950             attach_own_key(session, _src);
  1951 
  1952         msg = clone_to_empty_message(_src);
  1953         if (msg == NULL)
  1954             goto enomem;
  1955 
  1956         switch (enc_format) {
  1957             case PEP_enc_PGP_MIME:
  1958             case PEP_enc_PEP: // BUG: should be implemented extra
  1959                 status = encrypt_PGP_MIME(session, _src, keys, msg, flags, wrap_type);
  1960                 break;
  1961 
  1962             case PEP_enc_inline:
  1963                 status = encrypt_PGP_inline(session, _src, keys, msg, flags);
  1964                 break;
  1965 
  1966             default:
  1967                 assert(0);
  1968                 status = PEP_ILLEGAL_VALUE;
  1969                 goto pEp_error;
  1970         }
  1971 
  1972         if (status == PEP_OUT_OF_MEMORY)
  1973             goto enomem;
  1974 
  1975         if (status != PEP_STATUS_OK)
  1976             goto pEp_error;
  1977     }
  1978 
  1979     free_stringlist(keys);
  1980 
  1981     if (msg && msg->shortmsg == NULL) {
  1982         msg->shortmsg = strdup("");
  1983         assert(msg->shortmsg);
  1984         if (msg->shortmsg == NULL)
  1985             goto enomem;
  1986     }
  1987 
  1988     if (msg) {
  1989         decorate_message(msg, PEP_rating_undefined, NULL, true, true);
  1990         if (_src->id) {
  1991             msg->id = strdup(_src->id);
  1992             assert(msg->id);
  1993             if (msg->id == NULL)
  1994                 goto enomem;
  1995         }
  1996     }
  1997 
  1998     *dst = msg;
  1999     
  2000     // ??? FIXME: Check to be sure we don't have references btw _src and msg. 
  2001     // I don't think we do.
  2002     if (_src && _src != src)
  2003         free_message(_src);
  2004     
  2005     _cleanup_src(src, added_key_to_real_src);
  2006         
  2007     return status;
  2008 
  2009 enomem:
  2010     status = PEP_OUT_OF_MEMORY;
  2011 
  2012 pEp_error:
  2013     free_stringlist(keys);
  2014     free_message(msg);
  2015     if (_src && _src != src)
  2016         free_message(_src);
  2017 
  2018     _cleanup_src(src, added_key_to_real_src);
  2019 
  2020     return status;
  2021 }
  2022 
  2023 DYNAMIC_API PEP_STATUS encrypt_message_and_add_priv_key(
  2024         PEP_SESSION session,
  2025         message *src,
  2026         message **dst,
  2027         const char* to_fpr,
  2028         PEP_enc_format enc_format,
  2029         PEP_encrypt_flags_t flags
  2030     )
  2031 {
  2032     assert(session);
  2033     assert(src);
  2034     assert(dst);
  2035     assert(to_fpr);
  2036         
  2037     if (!session || !src || !dst || !to_fpr)
  2038         return PEP_ILLEGAL_VALUE;
  2039         
  2040     if (enc_format == PEP_enc_none)
  2041         return PEP_ILLEGAL_VALUE;
  2042     
  2043     if (src->cc || src->bcc)
  2044         return PEP_ILLEGAL_VALUE;
  2045         
  2046     if (!src->to || src->to->next)
  2047         return PEP_ILLEGAL_VALUE;
  2048         
  2049     if (!src->from->address || !src->to->ident || !src->to->ident->address)
  2050         return PEP_ILLEGAL_VALUE;
  2051             
  2052     if (strcasecmp(src->from->address, src->to->ident->address) != 0)
  2053         return PEP_ILLEGAL_VALUE;
  2054     
  2055     stringlist_t* keys = NULL;
  2056 
  2057     char* own_id = NULL;
  2058     char* default_id = NULL;
  2059     
  2060     pEp_identity* own_identity = NULL;
  2061     char* own_private_fpr = NULL;
  2062 
  2063     char* priv_key_data = NULL;
  2064     
  2065     PEP_STATUS status = get_default_own_userid(session, &own_id);
  2066     
  2067     if (!own_id)
  2068         return PEP_UNKNOWN_ERROR; // Probably a DB error at this point
  2069         
  2070     if (src->from->user_id) {
  2071         if (strcmp(src->from->user_id, own_id) != 0) {
  2072             status = get_userid_alias_default(session, src->from->user_id, &default_id);
  2073             if (status != PEP_STATUS_OK || !default_id || strcmp(default_id, own_id) != 0) {
  2074                 status = PEP_ILLEGAL_VALUE;
  2075                 goto pEp_free;
  2076             }
  2077         }        
  2078     }
  2079     
  2080     // Ok, we are at least marginally sure the initial stuff is ok.
  2081         
  2082     // Let's get our own, normal identity
  2083     own_identity = identity_dup(src->from);
  2084     status = myself(session, own_identity);
  2085 
  2086     if (status != PEP_STATUS_OK)
  2087         goto pEp_free;
  2088 
  2089     // Ok, now we know the address is an own address. All good. Then...
  2090     own_private_fpr = own_identity->fpr;
  2091     own_identity->fpr = strdup(to_fpr);
  2092     
  2093     status = get_trust(session, own_identity);
  2094     
  2095     if (status != PEP_STATUS_OK) {
  2096         if (status == PEP_CANNOT_FIND_IDENTITY)
  2097             status = PEP_ILLEGAL_VALUE;
  2098         goto pEp_free;
  2099     }
  2100         
  2101     if ((own_identity->comm_type & PEP_ct_confirmed) != PEP_ct_confirmed) {
  2102         status = PEP_ILLEGAL_VALUE;
  2103         goto pEp_free;
  2104     }
  2105                 
  2106     // Ok, so all the things are now allowed.
  2107     // So let's get our own private key and roll with it.
  2108     size_t priv_key_size = 0;
  2109     
  2110     status = export_secret_key(session, own_private_fpr, &priv_key_data, 
  2111                                 &priv_key_size);
  2112 
  2113     if (status != PEP_STATUS_OK)
  2114         goto pEp_free;
  2115     
  2116     if (!priv_key_data) {
  2117         status = PEP_CANNOT_EXPORT_KEY;
  2118         goto pEp_free;
  2119     }
  2120     
  2121     // Ok, fine... let's encrypt yon blob
  2122     keys = new_stringlist(own_private_fpr);
  2123     if (!keys) {
  2124         status = PEP_OUT_OF_MEMORY;
  2125         goto pEp_free;
  2126     }
  2127     
  2128     stringlist_add(keys, to_fpr);
  2129     
  2130     char* encrypted_key_text = NULL;
  2131     size_t encrypted_key_size = 0;
  2132     
  2133     if (flags & PEP_encrypt_flag_force_unsigned)
  2134         status = encrypt_only(session, keys, priv_key_data, priv_key_size,
  2135                               &encrypted_key_text, &encrypted_key_size);
  2136     else
  2137         status = encrypt_and_sign(session, keys, priv_key_data, priv_key_size,
  2138                                   &encrypted_key_text, &encrypted_key_size);
  2139     
  2140     if (!encrypted_key_text) {
  2141         status = PEP_UNKNOWN_ERROR;
  2142         goto pEp_free;
  2143     }
  2144 
  2145     // We will have to delete this before returning, as we allocated it.
  2146     bloblist_t* created_bl = NULL;
  2147     bloblist_t* created_predecessor = NULL;
  2148     
  2149     bloblist_t* old_head = NULL;
  2150     
  2151     if (!src->attachments || src->attachments->value == NULL) {
  2152         if (src->attachments && src->attachments->value == NULL) {
  2153             old_head = src->attachments;
  2154             src->attachments = NULL;
  2155         }
  2156         src->attachments = new_bloblist(encrypted_key_text, encrypted_key_size,
  2157                                         "application/octet-stream", 
  2158                                         "file://pEpkey.asc.pgp");
  2159         created_bl = src->attachments;
  2160     } 
  2161     else {
  2162         bloblist_t* tmp = src->attachments;
  2163         while (tmp && tmp->next) {
  2164             tmp = tmp->next;
  2165         }
  2166         created_predecessor = tmp;                                    
  2167         created_bl = bloblist_add(tmp, 
  2168                                   encrypted_key_text, encrypted_key_size,
  2169                                   "application/octet-stream", 
  2170                                    "file://pEpkey.asc.pgp");
  2171     }
  2172     
  2173     if (!created_bl) {
  2174         status = PEP_OUT_OF_MEMORY;
  2175         goto pEp_free;
  2176     }
  2177             
  2178     // Ok, it's in there. Let's do this.        
  2179     status = encrypt_message(session, src, keys, dst, enc_format, flags);
  2180     
  2181     // Delete what we added to src
  2182     free_bloblist(created_bl);
  2183     if (created_predecessor)
  2184         created_predecessor->next = NULL;
  2185     else {
  2186         if (old_head)
  2187             src->attachments = old_head;
  2188         else
  2189             src->attachments = NULL;    
  2190     }
  2191     
  2192 pEp_free:
  2193     free(own_id);
  2194     free(default_id);
  2195     free(own_private_fpr);
  2196     free(priv_key_data);
  2197     free_identity(own_identity);
  2198     free_stringlist(keys);
  2199     return status;
  2200 }
  2201 
  2202 
  2203 DYNAMIC_API PEP_STATUS encrypt_message_for_self(
  2204         PEP_SESSION session,
  2205         pEp_identity* target_id,
  2206         message *src,
  2207         stringlist_t* extra,
  2208         message **dst,
  2209         PEP_enc_format enc_format,
  2210         PEP_encrypt_flags_t flags
  2211     )
  2212 {
  2213     PEP_STATUS status = PEP_STATUS_OK;
  2214     message * msg = NULL;
  2215     stringlist_t * keys = NULL;
  2216     message* _src = src;
  2217 
  2218     assert(session);
  2219     assert(target_id);
  2220     assert(src);
  2221     assert(dst);
  2222     assert(enc_format != PEP_enc_none);
  2223 
  2224     if (!(session && target_id && src && dst && enc_format != PEP_enc_none))
  2225         return PEP_ILLEGAL_VALUE;
  2226 
  2227     // if (src->dir == PEP_dir_incoming)
  2228     //     return PEP_ILLEGAL_VALUE;
  2229 
  2230     determine_encryption_format(src);
  2231     if (src->enc_format != PEP_enc_none)
  2232         return PEP_ILLEGAL_VALUE;
  2233 
  2234     if (!target_id->user_id || target_id->user_id[0] == '\0') {
  2235         char* own_id = NULL;
  2236         status = get_default_own_userid(session, &own_id);
  2237         if (own_id) {
  2238             free(target_id->user_id);
  2239             target_id->user_id = own_id; // ownership transfer
  2240         }
  2241     }
  2242 
  2243     if (!target_id->user_id || target_id->user_id[0] == '\0')
  2244         return PEP_CANNOT_FIND_IDENTITY;
  2245 
  2246     if (target_id->address) {
  2247         status = myself(session, target_id);
  2248         if (status != PEP_STATUS_OK)
  2249             goto pEp_error;
  2250     }
  2251     else if (!target_id->fpr) {
  2252         return PEP_ILLEGAL_VALUE;
  2253     }
  2254     
  2255     *dst = NULL;
  2256 
  2257     // PEP_STATUS _status = update_identity(session, target_id);
  2258     // if (_status != PEP_STATUS_OK) {
  2259     //     status = _status;
  2260     //     goto pEp_error;
  2261     // }
  2262 
  2263     char* target_fpr = target_id->fpr;
  2264     if (!target_fpr)
  2265         return PEP_KEY_NOT_FOUND; // FIXME: Error condition
  2266  
  2267     keys = new_stringlist(target_fpr);
  2268     
  2269     stringlist_t *_k = keys;
  2270 
  2271     if (extra) {
  2272         _k = stringlist_append(_k, extra);
  2273         if (_k == NULL)
  2274             goto enomem;
  2275     }
  2276 
  2277     /* KG: did we ever do this??? */
  2278     // if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  2279     //     _attach_key(session, target_fpr, src);
  2280 
  2281     unsigned int major_ver, minor_ver;
  2282     pEp_version_major_minor(PEP_VERSION, &major_ver, &minor_ver);
  2283     _src = wrap_message_as_attachment(NULL, src, PEP_message_default, false, major_ver, minor_ver);
  2284     if (!_src)
  2285         goto pEp_error;
  2286 
  2287     msg = clone_to_empty_message(_src);
  2288     if (msg == NULL)
  2289         goto enomem;
  2290 
  2291     switch (enc_format) {
  2292         case PEP_enc_PGP_MIME:
  2293         case PEP_enc_PEP: // BUG: should be implemented extra
  2294             status = encrypt_PGP_MIME(session, _src, keys, msg, flags, PEP_message_default);
  2295             if (status == PEP_STATUS_OK || (src->longmsg && strstr(src->longmsg, "INNER")))
  2296                 _cleanup_src(src, false);
  2297             break;
  2298 
  2299         case PEP_enc_inline:
  2300             status = encrypt_PGP_inline(session, _src, keys, msg, flags);
  2301             break;
  2302 
  2303         default:
  2304             assert(0);
  2305             status = PEP_ILLEGAL_VALUE;
  2306             goto pEp_error;
  2307     }
  2308 
  2309     if (status == PEP_OUT_OF_MEMORY)
  2310         goto enomem;
  2311 
  2312     if (status != PEP_STATUS_OK)
  2313         goto pEp_error;
  2314 
  2315      if (msg && msg->shortmsg == NULL) {
  2316          msg->shortmsg = _pEp_subj_copy();
  2317          assert(msg->shortmsg);
  2318          if (msg->shortmsg == NULL)
  2319              goto enomem;
  2320      }
  2321 
  2322      if (msg) {
  2323          if (_src->id) {
  2324              msg->id = strdup(_src->id);
  2325              assert(msg->id);
  2326              if (msg->id == NULL)
  2327                  goto enomem;
  2328          }
  2329          decorate_message(msg, PEP_rating_undefined, NULL, true, true);
  2330      }
  2331 
  2332     *dst = msg;
  2333     
  2334     if (src != _src)
  2335         free_message(_src);
  2336 
  2337     return status;
  2338 
  2339 enomem:
  2340     status = PEP_OUT_OF_MEMORY;
  2341 
  2342 pEp_error:
  2343     free_stringlist(keys);
  2344     free_message(msg);
  2345     if (src != _src)
  2346         free_message(_src);
  2347 
  2348     return status;
  2349 }
  2350 
  2351 // static PEP_STATUS _update_identity_for_incoming_message(
  2352 //         PEP_SESSION session,
  2353 //         const message *src
  2354 //     )
  2355 // {
  2356 //     PEP_STATUS status;
  2357 // 
  2358 //     if (src->from && src->from->address) {
  2359 //         if (!is_me(session, src->from))
  2360 //             status = update_identity(session, src->from);
  2361 //         else
  2362 //             status = myself(session, src->from);
  2363 //         if (status == PEP_STATUS_OK
  2364 //                 && is_a_pEpmessage(src)
  2365 //                 && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
  2366 //                 && src->from->comm_type != PEP_ct_pEp_unconfirmed
  2367 //                 && src->from->comm_type != PEP_ct_pEp)
  2368 //         {
  2369 //             src->from->comm_type |= PEP_ct_pEp_unconfirmed;
  2370 //             status = set_identity(session, src->from);
  2371 //         }
  2372 //         return status;
  2373 //     }
  2374 //     return PEP_ILLEGAL_VALUE;
  2375 // }
  2376 
  2377 
  2378 static PEP_STATUS _get_detached_signature(message* msg, 
  2379                                           bloblist_t** signature_blob) {
  2380     bloblist_t* attach_curr = msg->attachments;
  2381 
  2382     *signature_blob = NULL;
  2383 
  2384     while (attach_curr) {
  2385         if (attach_curr->mime_type &&
  2386             (strcasecmp(attach_curr->mime_type, "application/pgp-signature") == 0)) {
  2387             *signature_blob = attach_curr;
  2388             break;
  2389         }
  2390         attach_curr = attach_curr->next;
  2391     }
  2392 
  2393     return PEP_STATUS_OK;
  2394 }
  2395 
  2396 static PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
  2397                                    char** stext, size_t* ssize) {
  2398 
  2399     char* signed_boundary = NULL;
  2400     char* signpost = strstr(ptext, "Content-Type: multipart/signed");
  2401 
  2402     *ssize = 0;
  2403     *stext = NULL;
  2404 
  2405     if (!signpost)
  2406         return PEP_UNKNOWN_ERROR;
  2407 
  2408     char* curr_line = signpost;
  2409 //    const char* end_text = ptext + psize;
  2410     const char* boundary_key = "boundary=";
  2411     const size_t BOUNDARY_KEY_SIZE = 9;
  2412 
  2413     char* start_boundary = strstr(curr_line, boundary_key);
  2414     if (!start_boundary)
  2415         return PEP_UNKNOWN_ERROR;
  2416 
  2417     start_boundary += BOUNDARY_KEY_SIZE;
  2418 
  2419     bool quoted = (*start_boundary == '"');
  2420 
  2421     if (quoted)
  2422         start_boundary++;
  2423         
  2424     char* end_boundary = (quoted ? strstr(start_boundary, "\"") : strstr(start_boundary, ";")); // FIXME: third possiblity is CRLF, or?
  2425 
  2426     if (!end_boundary)
  2427         return PEP_UNKNOWN_ERROR;
  2428 
  2429     // Add space for the "--"
  2430     size_t boundary_strlen = (end_boundary - start_boundary) + 2;
  2431 
  2432     signed_boundary = calloc(boundary_strlen + 1, 1);
  2433     assert(signed_boundary);
  2434     if (!signed_boundary)
  2435         return PEP_OUT_OF_MEMORY;
  2436 
  2437     strlcpy(signed_boundary, "--", boundary_strlen + 1);
  2438     strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
  2439 
  2440     start_boundary = strstr(end_boundary, signed_boundary);
  2441 
  2442     if (!start_boundary)
  2443         return PEP_UNKNOWN_ERROR;
  2444 
  2445     start_boundary += boundary_strlen;
  2446 
  2447     if (*start_boundary == '\r') {
  2448         if (*(start_boundary + 1) == '\n')
  2449             start_boundary += 2;
  2450     }
  2451     else if (*start_boundary == '\n')
  2452         start_boundary++;
  2453 
  2454     end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
  2455 
  2456     if (!end_boundary)
  2457         return PEP_UNKNOWN_ERROR;
  2458 
  2459     // See RFC3156 section 5...
  2460     end_boundary--; 
  2461     if (*(end_boundary - 1) == '\r')
  2462         end_boundary--; 
  2463 
  2464     *ssize = end_boundary - start_boundary;
  2465     *stext = start_boundary;
  2466     free(signed_boundary);
  2467 
  2468     return PEP_STATUS_OK;
  2469 }
  2470 
  2471 static PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in, 
  2472                                    stringlist_t** keylist_in_out, 
  2473                                    pEp_identity* from) {
  2474     
  2475     if (!verify_in || !(*verify_in)) // this isn't really a problem.
  2476         return PEP_STATUS_OK;
  2477     
  2478     stringlist_t* orig_verify = *verify_in;
  2479     
  2480     stringlist_t* verify_curr = NULL;
  2481     stringlist_t* from_keys = NULL;
  2482     
  2483     /* FIXME: what to do if head needs to be null */
  2484     PEP_STATUS status = find_keys(session, from->address, &from_keys);
  2485     
  2486     stringlist_t* from_fpr_node = NULL;
  2487     stringlist_t* from_curr;
  2488     
  2489     for (from_curr = from_keys; from_curr; from_curr = from_curr->next) {
  2490         for (verify_curr = orig_verify; verify_curr; verify_curr = verify_curr->next) {
  2491             if (from_curr->value && verify_curr->value &&
  2492                 _same_fpr(from_curr->value, strlen(from_curr->value),
  2493                           verify_curr->value, strlen(verify_curr->value))) {
  2494                 from_fpr_node = from_curr;
  2495                 break;
  2496             }
  2497         }
  2498     }
  2499     
  2500     if (!from_fpr_node) {
  2501         status = PEP_KEY_NOT_FOUND;
  2502         goto free;
  2503     }
  2504 
  2505     verify_curr = orig_verify;
  2506     
  2507     /* put "from" signer at the beginning of the list */
  2508     if (!_same_fpr(orig_verify->value, strlen(orig_verify->value),
  2509                    from_fpr_node->value, strlen(from_fpr_node->value))) {
  2510         orig_verify = stringlist_delete(orig_verify, from_fpr_node->value);
  2511         verify_curr = new_stringlist(from_fpr_node->value);
  2512         verify_curr->next = orig_verify;
  2513     }
  2514 
  2515     if (keylist_in_out) {
  2516         /* append keylist to signers */
  2517         if (*keylist_in_out && (*keylist_in_out)->value) {
  2518             stringlist_t** tail_pp = &verify_curr->next;
  2519 
  2520             while (*tail_pp) {
  2521                 tail_pp = &((*tail_pp)->next);
  2522             }
  2523             stringlist_t* second_list = *keylist_in_out;
  2524             if (second_list) {
  2525                 char* listhead_val = second_list->value;
  2526                 if (!listhead_val || listhead_val[0] == '\0') {
  2527                     /* remove head, basically. This can happen when,
  2528                        for example, the signature is detached and
  2529                        verification is not seen directly after
  2530                        decryption, so no signer is presumed in
  2531                        the first construction of the keylist */
  2532                     *keylist_in_out = (*keylist_in_out)->next;
  2533                     second_list->next = NULL;
  2534                     free_stringlist(second_list);
  2535                 }
  2536             }
  2537             *tail_pp = *keylist_in_out;
  2538         }
  2539 
  2540         *keylist_in_out = verify_curr;
  2541     }
  2542 
  2543     status = PEP_STATUS_OK;
  2544     
  2545 free:
  2546     free_stringlist(from_keys);
  2547     return status;
  2548 }
  2549 
  2550 static PEP_STATUS amend_rating_according_to_sender_and_recipients(
  2551        PEP_SESSION session,
  2552        PEP_rating *rating,
  2553        pEp_identity *sender,
  2554        stringlist_t *recipients) {
  2555     
  2556     PEP_STATUS status = PEP_STATUS_OK;
  2557 
  2558     if (*rating > PEP_rating_mistrust) {
  2559 
  2560         if (recipients == NULL) {
  2561             *rating = PEP_rating_undefined;
  2562             return PEP_STATUS_OK;
  2563         }
  2564 
  2565         char *fpr = recipients->value;
  2566 
  2567         if (!(sender && sender->user_id && sender->user_id[0] && fpr && fpr[0])) {
  2568             *rating = PEP_rating_unreliable;
  2569         }
  2570         else {
  2571             pEp_identity *_sender = new_identity(sender->address, fpr,
  2572                                                  sender->user_id, sender->username);
  2573             if (_sender == NULL)
  2574                 return PEP_OUT_OF_MEMORY;
  2575 
  2576             status = get_trust(session, _sender);
  2577             if (_sender->comm_type == PEP_ct_unknown) {
  2578                 get_key_rating(session, fpr, &_sender->comm_type);
  2579             }
  2580             if (_sender->comm_type != PEP_ct_unknown) {
  2581                 *rating = keylist_rating(session, recipients, 
  2582                             fpr, _rating(_sender->comm_type));
  2583             }
  2584             
  2585             free_identity(_sender);
  2586             if (status == PEP_CANNOT_FIND_IDENTITY)
  2587                status = PEP_STATUS_OK;
  2588         }
  2589     }
  2590     return status;
  2591 }
  2592 
  2593 // FIXME: Do we need to remove the attachment? I think we do...
  2594 static bool pull_up_attached_main_msg(message* src) {
  2595     char* slong = src->longmsg;
  2596     char* sform = src->longmsg_formatted;
  2597     bloblist_t* satt = src->attachments;
  2598     
  2599     if ((!slong || slong[0] == '\0')
  2600          && (!sform || sform[0] == '\0')) {
  2601         const char* inner_mime_type = (satt ? satt->mime_type : NULL);     
  2602         if (inner_mime_type) {
  2603             if (strcasecmp(inner_mime_type, "text/plain") == 0) {
  2604                 free(slong); /* in case of "" */
  2605                 src->longmsg = strndup(satt->value, satt->size); 
  2606                 
  2607                 bloblist_t* next_node = satt->next;
  2608                 if (next_node) {
  2609                     inner_mime_type = next_node->mime_type;
  2610                     if (strcasecmp(inner_mime_type, "text/html") == 0) {
  2611                         free(sform);
  2612                         src->longmsg_formatted = strndup(next_node->value, next_node->size);
  2613                     }
  2614                 }
  2615             }
  2616             else if (strcasecmp(inner_mime_type, "text/html") == 0) {
  2617                 free(sform);
  2618                 src->longmsg_formatted = strndup(satt->value, satt->size);
  2619             }
  2620         }
  2621         return true;
  2622     }
  2623     return false;
  2624 }
  2625 
  2626 
  2627 
  2628 static PEP_STATUS unencapsulate_hidden_fields(message* src, message* msg,
  2629                                               char** msg_wrap_info) {
  2630     if (!src)
  2631         return PEP_ILLEGAL_VALUE;
  2632     unsigned char pEpstr[] = PEP_SUBJ_STRING;
  2633     PEP_STATUS status = PEP_STATUS_OK;
  2634 
  2635     bool change_source_in_place = (msg ? false : true);
  2636     
  2637     if (change_source_in_place)
  2638         msg = src;
  2639         
  2640     
  2641     switch (src->enc_format) {
  2642         case PEP_enc_PGP_MIME:
  2643         case PEP_enc_inline:
  2644         case PEP_enc_PGP_MIME_Outlook1:
  2645 //        case PEP_enc_none: // FIXME - this is wrong
  2646 
  2647             if (!change_source_in_place)
  2648                 status = copy_fields(msg, src);
  2649                 
  2650             if (status != PEP_STATUS_OK)
  2651                 return status;
  2652                 
  2653             // FIXME: This is a mess. Talk with VB about how far we go to identify
  2654             if (is_a_pEpmessage(src) || (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0 ||
  2655                 _unsigned_signed_strcmp(pEpstr, src->shortmsg, PEP_SUBJ_BYTELEN) == 0) ||
  2656                 (strcmp(src->shortmsg, "p=p") == 0))
  2657             {
  2658                 char * shortmsg = NULL;
  2659                 char * longmsg = NULL;
  2660         
  2661                 if (msg->longmsg) {
  2662                     int r = separate_short_and_long(msg->longmsg, 
  2663                                                     &shortmsg, 
  2664                                                     msg_wrap_info,
  2665                                                     &longmsg);
  2666                 
  2667                     if (r == -1)
  2668                         return PEP_OUT_OF_MEMORY;
  2669                 }
  2670 
  2671                 // We only use the shortmsg in version 1.0 messages; if it occurs where we
  2672                 // didn't replace the subject, we ignore this all
  2673                 if (!(*msg_wrap_info || change_source_in_place)) {
  2674                     if (!shortmsg || 
  2675                         (src->shortmsg != NULL && strcmp(src->shortmsg, "pEp") != 0 &&
  2676                          _unsigned_signed_strcmp(pEpstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0 &&
  2677                         strcmp(src->shortmsg, "p=p") != 0)) {
  2678                              
  2679                         if (shortmsg != NULL)
  2680                             free(shortmsg);                        
  2681                             
  2682                         if (src->shortmsg == NULL) {
  2683                             shortmsg = strdup("");
  2684                         }
  2685                         else {
  2686                             // FIXME: is msg->shortmsg always a copy of
  2687                             // src->shortmsg already?
  2688                             // if so, we need to change the logic so
  2689                             // that in this case, we don't free msg->shortmsg
  2690                             // and do this strdup, etc
  2691                             shortmsg = strdup(src->shortmsg);
  2692                         }        
  2693                     }
  2694                     free(msg->shortmsg);
  2695                     msg->shortmsg = shortmsg;
  2696                 }
  2697                 
  2698                 free(msg->longmsg);
  2699 
  2700                 msg->longmsg = longmsg;
  2701             }
  2702             else {
  2703                 if (!change_source_in_place) {
  2704                     msg->shortmsg = strdup(src->shortmsg);
  2705                     assert(msg->shortmsg);
  2706                     if (msg->shortmsg == NULL)
  2707                         return PEP_OUT_OF_MEMORY;
  2708                 }
  2709             }
  2710             break;
  2711         default:
  2712                 // BUG: must implement more
  2713                 NOT_IMPLEMENTED
  2714     }
  2715     return PEP_STATUS_OK;
  2716 
  2717 }
  2718 
  2719 static PEP_STATUS get_crypto_text(message* src, char** crypto_text, size_t* text_size) {
  2720                 
  2721     // this is only here because of how NOT_IMPLEMENTED works            
  2722     PEP_STATUS status = PEP_STATUS_OK;
  2723                     
  2724     switch (src->enc_format) {
  2725         case PEP_enc_PGP_MIME:
  2726             *crypto_text = src->attachments->next->value;
  2727             *text_size = src->attachments->next->size;
  2728             break;
  2729 
  2730         case PEP_enc_PGP_MIME_Outlook1:
  2731             *crypto_text = src->attachments->value;
  2732             *text_size = src->attachments->size;
  2733             break;
  2734 
  2735         case PEP_enc_inline:
  2736             *crypto_text = src->longmsg;
  2737             *text_size = strlen(*crypto_text);
  2738             break;
  2739 
  2740         default:
  2741             NOT_IMPLEMENTED
  2742     }
  2743     
  2744     return status;
  2745 }
  2746 
  2747 
  2748 static PEP_STATUS verify_decrypted(PEP_SESSION session,
  2749                                    message* src,
  2750                                    message* msg, 
  2751                                    char* plaintext, 
  2752                                    size_t plaintext_size,
  2753                                    stringlist_t** keylist,
  2754                                    PEP_STATUS* decrypt_status,
  2755                                    PEP_cryptotech crypto) {
  2756 
  2757     assert(src && src->from);
  2758     
  2759     if (!src && !src->from)
  2760         return PEP_ILLEGAL_VALUE;
  2761 
  2762     PEP_STATUS _cached_decrypt_status = *decrypt_status;
  2763         
  2764     pEp_identity* sender = src->from;
  2765 
  2766     bloblist_t* detached_sig = NULL;
  2767     PEP_STATUS status = _get_detached_signature(msg, &detached_sig);
  2768     stringlist_t *verify_keylist = NULL;
  2769     
  2770     
  2771     if (detached_sig) {
  2772         char* dsig_text = detached_sig->value;
  2773         size_t dsig_size = detached_sig->size;
  2774         size_t ssize = 0;
  2775         char* stext = NULL;
  2776 
  2777         status = _get_signed_text(plaintext, plaintext_size, &stext, &ssize);
  2778 
  2779         if (ssize > 0 && stext) {
  2780             status = cryptotech[crypto].verify_text(session, stext,
  2781                                                     ssize, dsig_text, dsig_size,
  2782                                                     &verify_keylist);
  2783         }
  2784         
  2785         if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
  2786         {
  2787             *decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
  2788         
  2789             status = combine_keylists(session, &verify_keylist, keylist, sender);
  2790         }
  2791     }
  2792     else {
  2793         size_t csize, psize;
  2794         char* ctext;
  2795         char* ptext;
  2796         get_crypto_text(src, &ctext, &csize);
  2797         // reverify - we may have imported a key in the meantime
  2798         // status = cryptotech[crypto].verify_text(session, ctext,
  2799         //                                         csize, NULL, 0,
  2800         //                                         &verify_keylist);
  2801         free_stringlist(*keylist);
  2802         *decrypt_status = decrypt_and_verify(session, ctext, csize,
  2803                                              NULL, 0,
  2804                                              &ptext, &psize, keylist,
  2805                                              NULL);
  2806         
  2807     }
  2808 
  2809     if (*decrypt_status != PEP_DECRYPTED_AND_VERIFIED)
  2810         *decrypt_status = _cached_decrypt_status;                                
  2811 
  2812     return PEP_STATUS_OK;
  2813 }
  2814 
  2815 static PEP_STATUS _decrypt_in_pieces(PEP_SESSION session, 
  2816                                      message* src, 
  2817                                      message** msg_ptr, 
  2818                                      char* ptext,
  2819                                      size_t psize) {
  2820                             
  2821     PEP_STATUS status = PEP_STATUS_OK;
  2822     
  2823     *msg_ptr = clone_to_empty_message(src);
  2824 
  2825     if (*msg_ptr == NULL)
  2826         return PEP_OUT_OF_MEMORY;
  2827 
  2828     message* msg = *msg_ptr;
  2829 
  2830     msg->longmsg = strdup(ptext);
  2831     ptext = NULL;
  2832 
  2833     bloblist_t *_m = msg->attachments;
  2834     if (_m == NULL && src->attachments && src->attachments->value) {
  2835         msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
  2836         _m = msg->attachments;
  2837     }
  2838 
  2839     bloblist_t *_s;
  2840     for (_s = src->attachments; _s && _s->value; _s = _s->next) {
  2841         if (_s->value == NULL && _s->size == 0){
  2842             _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
  2843             if (_m == NULL)
  2844                 return PEP_OUT_OF_MEMORY;
  2845 
  2846         }
  2847         else if (is_encrypted_attachment(_s)) {
  2848             stringlist_t *_keylist = NULL;
  2849             char *attctext  = _s->value;
  2850             size_t attcsize = _s->size;
  2851 
  2852             free(ptext);
  2853             ptext = NULL;
  2854 
  2855             char* pgp_filename = NULL;
  2856             status = decrypt_and_verify(session, attctext, attcsize,
  2857                                         NULL, 0,
  2858                                         &ptext, &psize, &_keylist,
  2859                                         &pgp_filename);
  2860                                         
  2861             free_stringlist(_keylist);
  2862 
  2863             char* filename_uri = NULL;
  2864 
  2865             bool has_uri_prefix = (pgp_filename ? (is_file_uri(pgp_filename) || is_cid_uri(pgp_filename)) :
  2866                                                   (_s->filename ? (is_file_uri(_s->filename) || is_cid_uri(_s->filename)) :
  2867                                                                   false
  2868                                                   )
  2869                                   );
  2870             
  2871 
  2872             if (ptext) {
  2873                 if (is_encrypted_html_attachment(_s)) {
  2874                     msg->longmsg_formatted = ptext;
  2875                     ptext = NULL;
  2876                 }
  2877                 else {
  2878                     static const char * const mime_type = "application/octet-stream";                    
  2879                     if (pgp_filename) {
  2880                         if (!has_uri_prefix)
  2881                             filename_uri = build_uri("file", pgp_filename);
  2882 
  2883                         _m = bloblist_add(_m, ptext, psize, mime_type,
  2884                              (filename_uri ? filename_uri : pgp_filename));
  2885 
  2886                         free(pgp_filename);
  2887                         free(filename_uri);
  2888                         if (_m == NULL)
  2889                             return PEP_OUT_OF_MEMORY;
  2890                     }
  2891                     else {
  2892                         char * const filename =
  2893                             without_double_ending(_s->filename);
  2894                         if (filename == NULL)
  2895                             return PEP_OUT_OF_MEMORY;
  2896 
  2897                         if (!has_uri_prefix)
  2898                             filename_uri = build_uri("file", filename);
  2899 
  2900                         _m = bloblist_add(_m, ptext, psize, mime_type,
  2901                              (filename_uri ? filename_uri : filename));
  2902                         free(filename);
  2903                         free(filename_uri);
  2904                         if (_m == NULL)
  2905                             return PEP_OUT_OF_MEMORY;
  2906                     }
  2907                     ptext = NULL;
  2908 
  2909                     if (msg->attachments == NULL)
  2910                         msg->attachments = _m;
  2911                 }
  2912             }
  2913             else {
  2914                 char *copy = malloc(_s->size);
  2915                 assert(copy);
  2916                 if (copy == NULL)
  2917                     return PEP_OUT_OF_MEMORY;
  2918                 memcpy(copy, _s->value, _s->size);
  2919 
  2920                 if (!has_uri_prefix && _s->filename)
  2921                     filename_uri = build_uri("file", _s->filename);
  2922 
  2923                 _m = bloblist_add(_m, copy, _s->size, _s->mime_type, 
  2924                         (filename_uri ? filename_uri : _s->filename));
  2925                 if (_m == NULL)
  2926                     return PEP_OUT_OF_MEMORY;
  2927             }
  2928         }
  2929         else {
  2930             char *copy = malloc(_s->size);
  2931             assert(copy);
  2932             if (copy == NULL)
  2933                 return PEP_OUT_OF_MEMORY;
  2934             memcpy(copy, _s->value, _s->size);
  2935 
  2936             char* filename_uri = NULL;
  2937 
  2938             _m = bloblist_add(_m, copy, _s->size, _s->mime_type, 
  2939                     ((_s->filename && !(is_file_uri(_s->filename) || is_cid_uri(_s->filename))) ?
  2940                          (filename_uri = build_uri("file", _s->filename)) : _s->filename));
  2941             free(filename_uri);
  2942             if (_m == NULL)
  2943                 return PEP_OUT_OF_MEMORY;
  2944         }
  2945     }
  2946 
  2947     return status;
  2948 }
  2949 
  2950 static PEP_STATUS import_priv_keys_from_decrypted_msg(PEP_SESSION session,
  2951                                                       message* msg,
  2952                                                       bool* imported_keys,
  2953                                                       bool* imported_private,
  2954                                                       identity_list** private_il)
  2955 {
  2956     assert(msg && imported_keys && imported_private);
  2957     if (!(msg && imported_keys && imported_private))
  2958         return PEP_ILLEGAL_VALUE;
  2959 
  2960     PEP_STATUS status = PEP_STATUS_OK;
  2961     *imported_keys = NULL;
  2962     *imported_private = false;
  2963     if (private_il)
  2964         *private_il = NULL;
  2965 
  2966     // check for private key in decrypted message attachment while importing
  2967     identity_list *_private_il = NULL;
  2968 
  2969     bool _imported_keys = import_attached_keys(session, msg, &_private_il);
  2970     bool _imported_private = false;
  2971     if (_private_il && _private_il->ident && _private_il->ident->address)
  2972         _imported_private = true;
  2973 
  2974     if (private_il && _imported_private) {
  2975         // the private identity list should NOT be subject to myself() or
  2976         // update_identity() at this point.
  2977         // If the receiving app wants them to be in the trust DB, it
  2978         // should call set_own_key() on them upon return.
  2979         // We do, however, prepare these so the app can use them
  2980         // directly in a set_own_key() call by putting the own_id on it.
  2981         char* own_id = NULL;
  2982         status = get_default_own_userid(session, &own_id);
  2983         
  2984         for (identity_list* il = _private_il; il; il = il->next) {
  2985             if (own_id) {
  2986                 free(il->ident->user_id);
  2987                 il->ident->user_id = strdup(own_id);
  2988                 assert(il->ident->user_id);
  2989                 if (!il->ident->user_id) {
  2990                     status = PEP_OUT_OF_MEMORY;
  2991                     break;
  2992                 }
  2993             }
  2994             il->ident->me = true;
  2995         }
  2996         free(own_id);
  2997         if (!status)
  2998             *private_il = _private_il;
  2999     }
  3000     else {
  3001         free_identity_list(_private_il);
  3002     }
  3003  
  3004     if (!status) {
  3005         *imported_keys = _imported_keys;
  3006         *imported_private = _imported_private;
  3007     }
  3008 
  3009     return status;
  3010 }
  3011 
  3012 // ident is in_only and should have been updated
  3013 static PEP_STATUS pEp_version_upgrade_or_ignore(
  3014         PEP_SESSION session,
  3015         pEp_identity* ident,
  3016         unsigned int major,
  3017         unsigned int minor) {
  3018             
  3019     PEP_STATUS status = PEP_STATUS_OK;        
  3020     int ver_compare = compare_versions(major, minor, ident->major_ver, ident->minor_ver);
  3021     if (ver_compare > 0)
  3022         status = set_pEp_version(session, ident, major, minor);        
  3023     
  3024     return status;    
  3025 }
  3026 
  3027 // FIXME: myself ??????
  3028 static PEP_STATUS update_sender_to_pEp_trust(
  3029         PEP_SESSION session, 
  3030         pEp_identity* sender, 
  3031         stringlist_t* keylist,
  3032         unsigned int major,
  3033         unsigned int minor) 
  3034 {
  3035     assert(session);
  3036     assert(sender);
  3037     assert(keylist && !EMPTYSTR(keylist->value));
  3038     
  3039     if (!session || !sender || !keylist || EMPTYSTR(keylist->value))
  3040         return PEP_ILLEGAL_VALUE;
  3041         
  3042     free(sender->fpr);
  3043     sender->fpr = NULL;
  3044 
  3045     PEP_STATUS status = PEP_STATUS_OK;
  3046 
  3047     // Seems status doesn't matter
  3048     is_me(session, sender) ? myself(session, sender) : update_identity(session, sender);
  3049 
  3050     if (EMPTYSTR(sender->fpr) || strcmp(sender->fpr, keylist->value) != 0) {
  3051         free(sender->fpr);
  3052         sender->fpr = strdup(keylist->value);
  3053         if (!sender->fpr)
  3054             return PEP_OUT_OF_MEMORY;
  3055         status = set_pgp_keypair(session, sender->fpr);
  3056         if (status != PEP_STATUS_OK)
  3057             return status;
  3058             
  3059         status = get_trust(session, sender);
  3060         
  3061         if (status == PEP_CANNOT_FIND_IDENTITY || sender->comm_type == PEP_ct_unknown) {
  3062             PEP_comm_type ct = PEP_ct_unknown;
  3063             status = get_key_rating(session, sender->fpr, &ct);
  3064             if (status != PEP_STATUS_OK)
  3065                 return status;
  3066                 
  3067             sender->comm_type = ct;    
  3068         }
  3069     }
  3070     
  3071     // Could be done elegantly, but we do this explicitly here for readability.
  3072     // This file's code is difficult enough to parse. But change at will.
  3073     switch (sender->comm_type) {            
  3074         case PEP_ct_OpenPGP_unconfirmed:
  3075         case PEP_ct_OpenPGP:
  3076             sender->comm_type = PEP_ct_pEp_unconfirmed | (sender->comm_type & PEP_ct_confirmed);
  3077             status = set_trust(session, sender);
  3078             if (status != PEP_STATUS_OK)
  3079                 break;
  3080         case PEP_ct_pEp:
  3081         case PEP_ct_pEp_unconfirmed:
  3082             // set version
  3083             if (major == 0) {
  3084                 major = 2;
  3085                 minor = 0;
  3086             }
  3087             status = pEp_version_upgrade_or_ignore(session, sender, major, minor);    
  3088             break;
  3089         default:
  3090             status = PEP_CANNOT_SET_TRUST;
  3091             break;
  3092     }
  3093     
  3094     return status;
  3095 }
  3096 
  3097 static PEP_STATUS reconcile_identity(pEp_identity* srcid,
  3098                                      pEp_identity* resultid) {
  3099     assert(srcid);
  3100     assert(resultid);
  3101 
  3102     if (!srcid || !resultid)
  3103         return PEP_ILLEGAL_VALUE;
  3104         
  3105     if (!EMPTYSTR(srcid->user_id)) {
  3106         if (EMPTYSTR(resultid->user_id) ||
  3107              strcmp(srcid->user_id, resultid->user_id) != 0) {
  3108             free(resultid->user_id);
  3109             resultid->user_id = strdup(srcid->user_id);
  3110         }
  3111     }
  3112     
  3113     resultid->lang[0] = srcid->lang[0];
  3114     resultid->lang[1] = srcid->lang[1];
  3115     resultid->lang[2] = 0;
  3116     resultid->me = srcid->me;
  3117     resultid->flags = srcid->flags;
  3118 
  3119     return PEP_STATUS_OK;
  3120 }
  3121 
  3122 static PEP_STATUS reconcile_identity_lists(identity_list* src_ids,
  3123                                            identity_list* result_ids) {
  3124                                            
  3125     identity_list* curr_id = result_ids;
  3126     
  3127     PEP_STATUS status = PEP_STATUS_OK;
  3128     
  3129     while (curr_id) {
  3130         identity_list* curr_src_id = src_ids;
  3131         pEp_identity* result_identity = curr_id->ident;
  3132         
  3133         while (curr_src_id) {
  3134             pEp_identity* source_identity = curr_src_id->ident;
  3135             
  3136             if (EMPTYSTR(source_identity->address) || EMPTYSTR(result_identity->address))
  3137                 return PEP_ILLEGAL_VALUE; // something went badly wrong
  3138             
  3139             if (strcasecmp(source_identity->address, result_identity->address) == 0) {
  3140                 status = reconcile_identity(source_identity, result_identity);
  3141                 if (status != PEP_STATUS_OK)
  3142                     return status;
  3143             }
  3144             curr_src_id = curr_src_id->next;        
  3145         }
  3146         curr_id = curr_id->next;
  3147     }
  3148     return status;    
  3149 }
  3150 
  3151 static PEP_STATUS reconcile_sent_and_recv_info(message* src, message* inner_message) {
  3152     if (!src || !inner_message)
  3153         return PEP_ILLEGAL_VALUE;
  3154         
  3155     if (!inner_message->sent)
  3156         inner_message->sent = timestamp_dup(src->sent);
  3157         
  3158     // This will never be set otherwise, since it's a transport header on the outside    
  3159     inner_message->recv = timestamp_dup(src->recv);
  3160     
  3161     return PEP_STATUS_OK;
  3162 }
  3163 
  3164 static PEP_STATUS reconcile_src_and_inner_messages(message* src, 
  3165                                              message* inner_message) {
  3166 
  3167     PEP_STATUS status = PEP_STATUS_OK;
  3168     
  3169     if (strcasecmp(src->from->address, inner_message->from->address) == 0)
  3170         status = reconcile_identity(src->from, inner_message->from);
  3171     
  3172     if (status == PEP_STATUS_OK && inner_message->to)
  3173         status = reconcile_identity_lists(src->to, inner_message->to);
  3174 
  3175     if (status == PEP_STATUS_OK && inner_message->cc)
  3176         status = reconcile_identity_lists(src->cc, inner_message->cc);
  3177 
  3178     if (status == PEP_STATUS_OK && inner_message->bcc)
  3179         status = reconcile_identity_lists(src->bcc, inner_message->bcc);
  3180 
  3181     if (status == PEP_STATUS_OK)
  3182         status = reconcile_sent_and_recv_info(src, inner_message);
  3183         
  3184     return status;
  3185     // FIXME - are there any flags or anything else we need to be sure are carried?
  3186 }
  3187 
  3188 static bool is_trusted_own_priv_fpr(PEP_SESSION session, 
  3189                        const char* own_id, 
  3190                        const char* fpr
  3191     ) 
  3192 {   
  3193     bool retval = false;
  3194     if (!EMPTYSTR(fpr)) {
  3195         pEp_identity* test_identity = new_identity(NULL, fpr, own_id, NULL);
  3196         if (test_identity) {
  3197             PEP_STATUS status = get_trust(session, test_identity);
  3198             if (status == PEP_STATUS_OK) {
  3199                 if (test_identity->comm_type & PEP_ct_confirmed) {
  3200                     bool has_priv = false;
  3201                     status = contains_priv_key(session, fpr, &has_priv);
  3202                     if (status == PEP_STATUS_OK && has_priv)
  3203                         retval = true;
  3204                 }
  3205             }
  3206             free(test_identity);
  3207         }
  3208     }
  3209     return retval;
  3210 }
  3211 
  3212 static bool reject_fpr(PEP_SESSION session, const char* fpr) {
  3213     bool reject = true;
  3214 
  3215     PEP_STATUS status = key_revoked(session, fpr, &reject);
  3216 
  3217     if (!reject) {
  3218         status = key_expired(session, fpr, time(NULL), &reject);
  3219         if (reject) {
  3220             timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
  3221             status = renew_key(session, fpr, ts);
  3222             free_timestamp(ts);
  3223             if (status == PEP_STATUS_OK)
  3224                 reject = false;
  3225         }
  3226     }
  3227     return reject;
  3228 }
  3229 
  3230 static char* seek_good_trusted_private_fpr(PEP_SESSION session, char* own_id, 
  3231                                            stringlist_t* keylist) {
  3232     if (!own_id || !keylist)
  3233         return NULL;
  3234         
  3235     stringlist_t* kl_curr = keylist;
  3236     while (kl_curr) {
  3237         char* fpr = kl_curr->value;
  3238         
  3239         if (is_trusted_own_priv_fpr(session, own_id, fpr)) { 
  3240             if (!reject_fpr(session, fpr))
  3241                 return strdup(fpr);
  3242         }
  3243             
  3244         kl_curr = kl_curr->next;
  3245     }
  3246 
  3247     char* target_own_fpr = NULL;
  3248     
  3249     // Last shot...
  3250     PEP_STATUS status = get_user_default_key(session, own_id, 
  3251                                              &target_own_fpr);
  3252 
  3253     if (status == PEP_STATUS_OK && !EMPTYSTR(target_own_fpr)) {
  3254         if (is_trusted_own_priv_fpr(session, own_id, target_own_fpr)) { 
  3255             if (!reject_fpr(session, target_own_fpr))
  3256                 return target_own_fpr;
  3257         }
  3258     }
  3259     
  3260     // TODO: We can also go through all of the other available fprs for the
  3261     // own identity, but then I submit this function requires a little refactoring
  3262         
  3263     return NULL;
  3264 }
  3265 
  3266 static bool import_header_keys(PEP_SESSION session, message* src) {
  3267     stringpair_list_t* header_keys = stringpair_list_find(src->opt_fields, "Autocrypt"); 
  3268     if (!header_keys || !header_keys->value)
  3269         return false;
  3270     const char* value = header_keys->value->value;
  3271     if (!value)
  3272         return false;
  3273     const char* start_key = strstr(value, "keydata=");
  3274     if (!start_key)
  3275         return false;
  3276     start_key += 8; // length of "keydata="
  3277     int length = strlen(start_key);
  3278     bloblist_t* the_key = base64_str_to_binary_blob(start_key, length);
  3279     if (!the_key)
  3280         return false;
  3281     PEP_STATUS status = import_key(session, the_key->value, the_key->size, NULL);
  3282     free_bloblist(the_key);
  3283     if (status == PEP_STATUS_OK || status == PEP_KEY_IMPORTED)
  3284         return true;
  3285     return false;
  3286 }
  3287 
  3288 PEP_STATUS check_for_own_revoked_key(
  3289         PEP_SESSION session, 
  3290         stringlist_t* keylist,
  3291         stringpair_list_t** revoked_fpr_pairs
  3292     ) 
  3293 {
  3294     if (!session || !revoked_fpr_pairs)
  3295         return PEP_ILLEGAL_VALUE;
  3296         
  3297     *revoked_fpr_pairs = NULL;
  3298 
  3299     PEP_STATUS status = PEP_STATUS_OK;
  3300     stringpair_list_t* _the_list = new_stringpair_list(NULL);
  3301         
  3302     stringlist_t* _k = keylist;
  3303     for ( ; _k; _k = _k->next) {
  3304 
  3305         if (EMPTYSTR(_k->value))
  3306             continue; // Maybe the right thing to do is choke. 
  3307                       // But we can have NULL-valued empty list heads.
  3308 
  3309         const char* recip_fpr = _k->value;
  3310         char* replace_fpr = NULL;
  3311         uint64_t revoke_date = 0; 
  3312         status = get_replacement_fpr(session, 
  3313                                      recip_fpr, 
  3314                                      &replace_fpr, 
  3315                                      &revoke_date);
  3316 
  3317         bool own_key = false;
  3318         
  3319         switch (status) {
  3320             case PEP_CANNOT_FIND_IDENTITY:
  3321                 status = PEP_STATUS_OK;
  3322                 continue;
  3323             case PEP_STATUS_OK:
  3324         
  3325                 status = is_own_key(session, recip_fpr, &own_key);
  3326                 
  3327                 if (status != PEP_STATUS_OK) {
  3328                     free(replace_fpr);
  3329                     return status;
  3330                 }
  3331                 
  3332                 if (own_key)
  3333                     stringpair_list_add(_the_list, new_stringpair(recip_fpr, replace_fpr));
  3334 
  3335                 free(replace_fpr);
  3336                 replace_fpr = NULL;
  3337                 break;
  3338             default:    
  3339                 goto pEp_free;    
  3340         }
  3341     }
  3342     
  3343     if (_the_list && _the_list->value) {
  3344         *revoked_fpr_pairs = _the_list;
  3345         _the_list = NULL;
  3346     }
  3347             
  3348 pEp_free:
  3349     free_stringpair_list(_the_list);
  3350     return status;
  3351 
  3352 }
  3353 
  3354 static PEP_STATUS _decrypt_message(
  3355         PEP_SESSION session,
  3356         message *src,
  3357         message **dst,
  3358         stringlist_t **keylist,
  3359         PEP_rating *rating,
  3360         PEP_decrypt_flags_t *flags,
  3361         identity_list **private_il
  3362     )
  3363 {
  3364     assert(session);
  3365     assert(src);
  3366     assert(dst);
  3367     assert(keylist);
  3368     assert(rating);
  3369     assert(flags);
  3370 
  3371     if (!(session && src && dst && keylist && rating && flags))
  3372         return PEP_ILLEGAL_VALUE;
  3373 
  3374     /*** Begin init ***/
  3375     PEP_STATUS status = PEP_STATUS_OK;
  3376     PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
  3377     PEP_STATUS _decrypt_in_pieces_status = PEP_CANNOT_DECRYPT_UNKNOWN;
  3378     message* msg = NULL;
  3379     message* calculated_src = src;
  3380     message* reset_msg = NULL;
  3381     
  3382     char *ctext;
  3383     size_t csize;
  3384     char *ptext = NULL;
  3385     size_t psize;
  3386     stringlist_t *_keylist = NULL;
  3387     char* signer_fpr = NULL;
  3388     bool is_pEp_msg = is_a_pEpmessage(src);
  3389     bool myself_read_only = (src->dir == PEP_dir_incoming);
  3390     unsigned int major_ver;
  3391     unsigned int minor_ver;
  3392     
  3393     // Grab input flags
  3394     bool reencrypt = (((*flags & PEP_decrypt_flag_untrusted_server) > 0) && *keylist && !EMPTYSTR((*keylist)->value));
  3395     
  3396     // We own this pointer, and we take control of *keylist if reencrypting.
  3397     stringlist_t* extra = NULL;
  3398     if (reencrypt) {
  3399         if (*keylist) {
  3400             extra = *keylist;
  3401         }
  3402     }
  3403             
  3404     *dst = NULL;
  3405     *keylist = NULL;
  3406     *rating = PEP_rating_undefined;
  3407 //    *flags = 0;
  3408 
  3409     /*** End init ***/
  3410 
  3411     // KB: FIXME - we should do this once we've seen an inner message in the case 
  3412     // of pEp users. Since we've not used 1.0 in a billion years (but will receive 
  3413     // 1.0 messages from pEp users who don't yet know WE are pEp users), we should 
  3414     // sort this out sanely, not upfront.
  3415     //
  3416     // Was: Ok, before we do anything, if it's a pEp message, regardless of whether it's
  3417     // encrypted or not, we set the sender as a pEp user. This has NOTHING to do
  3418     // with the key.
  3419     // if (src->from && !(is_me(session, src->from))) {
  3420     //     if (is_pEp_msg) {
  3421     //         pEp_identity* tmp_from = src->from;
  3422     // 
  3423     //         // Ensure there's a user id
  3424     //         if (EMPTYSTR(tmp_from->user_id) && tmp_from->address) {
  3425     //             status = update_identity(session, tmp_from);
  3426     //             if (status == PEP_CANNOT_FIND_IDENTITY) {
  3427     //                 tmp_from->user_id = calloc(1, strlen(tmp_from->address) + 6);
  3428     //                 if (!tmp_from->user_id)
  3429     //                     return PEP_OUT_OF_MEMORY;
  3430     //                 snprintf(tmp_from->user_id, strlen(tmp_from->address) + 6,
  3431     //                          "TOFU_%s", tmp_from->address);        
  3432     //                 status = PEP_STATUS_OK;
  3433     //             }
  3434     //         }
  3435     //         if (status == PEP_STATUS_OK) {
  3436     //             // Now set user as PEP (may also create an identity if none existed yet)
  3437     //             status = set_as_pEp_user(session, tmp_from);
  3438     //         }
  3439     //     }
  3440     // }
  3441     // We really need key used in signing to do anything further on the pEp comm_type.
  3442     // So we can't adjust the rating of the sender just yet.
  3443 
  3444     /*** Begin Import any attached public keys and update identities accordingly ***/
  3445     // Private key in unencrypted mail are ignored -> NULL
  3446     //
  3447     // This import is from the outermost message.
  3448     // We don't do this for PGP_mime.
  3449     bool imported_keys = false;
  3450     PEP_cryptotech enc_type = determine_encryption_format(src);
  3451     if (enc_type != PEP_crypt_OpenPGP || !(src->enc_format == PEP_enc_PGP_MIME || src->enc_format == PEP_enc_PGP_MIME_Outlook1))
  3452         imported_keys = import_attached_keys(session, src, NULL);
  3453             
  3454     import_header_keys(session, src);
  3455     
  3456     // FIXME: is this really necessary here?
  3457     // if (src->from) {
  3458     //     if (!is_me(session, src->from))
  3459     //         status = update_identity(session, src->from);
  3460     //     else
  3461     //         status = _myself(session, src->from, false, false, myself_read_only);
  3462     // 
  3463     //     // We absolutely should NOT be bailing here unless it's a serious error
  3464     //     if (status == PEP_OUT_OF_MEMORY)
  3465     //         return status;
  3466     // }
  3467     
  3468     /*** End Import any attached public keys and update identities accordingly ***/
  3469     
  3470     /*** Begin get detached signatures that are attached to the encrypted message ***/
  3471     // Get detached signature, if any
  3472     bloblist_t* detached_sig = NULL;
  3473     char* dsig_text = NULL;
  3474     size_t dsig_size = 0;
  3475     status = _get_detached_signature(src, &detached_sig);
  3476     if (detached_sig) {
  3477         dsig_text = detached_sig->value;
  3478         dsig_size = detached_sig->size;
  3479     }
  3480     /*** End get detached signatures that are attached to the encrypted message ***/
  3481 
  3482     /*** Determine encryption format ***/
  3483     PEP_cryptotech crypto = determine_encryption_format(src);
  3484 
  3485     // Check for and deal with unencrypted messages
  3486     if (src->enc_format == PEP_enc_none) {
  3487 
  3488         *rating = PEP_rating_unencrypted;
  3489 
  3490         // We remove these from the outermost source message
  3491         // if (imported_keys)
  3492         //     remove_attached_keys(src);
  3493                                     
  3494         pull_up_attached_main_msg(src);
  3495         
  3496         return PEP_UNENCRYPTED;
  3497     }
  3498 
  3499     status = get_crypto_text(src, &ctext, &csize);
  3500     if (status != PEP_STATUS_OK)
  3501         return status;
  3502         
  3503     /** Ok, we should be ready to decrypt. Try decrypt and verify first! **/
  3504     status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  3505                                                    csize, dsig_text, dsig_size,
  3506                                                    &ptext, &psize, &_keylist,
  3507                                                    NULL);
  3508 
  3509     if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
  3510         goto pEp_error;
  3511 
  3512     decrypt_status = status;
  3513     
  3514     bool imported_private_key_address = false;
  3515     bool has_inner = false;
  3516 
  3517     if (ptext) { 
  3518         /* we got a plaintext from decryption */
  3519         switch (src->enc_format) {
  3520             
  3521             case PEP_enc_PGP_MIME:
  3522             case PEP_enc_PGP_MIME_Outlook1:
  3523             
  3524                 status = mime_decode_message(ptext, psize, &msg, &has_inner);
  3525                 if (status != PEP_STATUS_OK)
  3526                     goto pEp_error;
  3527                 
  3528                 /* Ensure messages whose maintext is in the attachments
  3529                    move main text into message struct longmsg et al */
  3530                 /* KG: This IS a src modification of old - we're adding to it
  3531                    w/ memhole subject, but the question is whether or not
  3532                    this is OK overall... */
  3533                 pull_up_attached_main_msg(msg);
  3534                 if (msg->shortmsg) {
  3535                     free(src->shortmsg);
  3536                     src->shortmsg = strdup(msg->shortmsg);                    
  3537                 }
  3538 
  3539                 // check for private key in decrypted message attachment while importing
  3540                 // N.B. Apparently, we always import private keys into the keyring; however,
  3541                 // we do NOT always allow those to be used for encryption. THAT is controlled
  3542                 // by setting it as an own identity associated with the key in the DB.
  3543                 //
  3544                 // We are importing from the decrypted outermost message now.
  3545                 //
  3546                 status = import_priv_keys_from_decrypted_msg(session, msg,
  3547                                                              &imported_keys,
  3548                                                              &imported_private_key_address,
  3549                                                              private_il);
  3550                 if (status != PEP_STATUS_OK)
  3551                     goto pEp_error;            
  3552 
  3553                 /* if decrypted, but not verified... */
  3554                 if (decrypt_status == PEP_DECRYPTED) {
  3555                     
  3556                     if (src->from)                                                                 
  3557                         status = verify_decrypted(session,
  3558                                                   src, msg,
  3559                                                   ptext, psize,
  3560                                                   &_keylist,
  3561                                                   &decrypt_status,
  3562                                                   crypto);
  3563                 }
  3564                 break;
  3565 
  3566             case PEP_enc_inline:
  3567                 status = PEP_STATUS_OK;
  3568                 
  3569                 _decrypt_in_pieces_status = _decrypt_in_pieces(session, src, &msg, ptext, psize);
  3570             
  3571                 switch (_decrypt_in_pieces_status) {
  3572                     case PEP_DECRYPTED:
  3573                     case PEP_DECRYPTED_AND_VERIFIED:
  3574                         if (decrypt_status <= PEP_DECRYPTED_AND_VERIFIED)
  3575                             decrypt_status = MIN(decrypt_status, _decrypt_in_pieces_status);
  3576                         break;
  3577                     case PEP_STATUS_OK:
  3578                         break;    
  3579                     case PEP_OUT_OF_MEMORY:
  3580                         goto enomem;
  3581                     default:
  3582                         decrypt_status = _decrypt_in_pieces_status;
  3583                         break;
  3584                 }
  3585                 break;
  3586             default:
  3587                 // BUG: must implement more
  3588                 NOT_IMPLEMENTED
  3589         }
  3590 
  3591         if (status == PEP_OUT_OF_MEMORY)
  3592             goto enomem;
  3593             
  3594         if (status != PEP_STATUS_OK)
  3595             goto pEp_error;
  3596 
  3597         if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
  3598             char* wrap_info = NULL;
  3599             
  3600             if (!has_inner) {
  3601                 status = unencapsulate_hidden_fields(src, msg, &wrap_info);
  3602                 if (status == PEP_OUT_OF_MEMORY)
  3603                     goto enomem;                
  3604                 if (status != PEP_STATUS_OK)
  3605                     goto pEp_error;
  3606             }        
  3607 
  3608 //            bool is_transport_wrapper = false;
  3609             
  3610         
  3611             // FIXME: replace with enums, check status
  3612             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
  3613                 // if (strcmp(wrap_info, "OUTER") == 0) {
  3614                 //     // this only occurs in with a direct outer wrapper
  3615                 //     // where the actual content is in the inner wrapper
  3616                 message* inner_message = NULL;
  3617                     
  3618                 // For a wrapped message, this is ALWAYS the second attachment; the 
  3619                 // mime tree is:
  3620                 // multipart/mixed
  3621                 //     |
  3622                 //     |----- text/plain 
  3623                 //     |----- message/rfc822
  3624                 //     |----- ...
  3625                 //
  3626                 // We leave this in below, but once we're rid of 2.0 format,
  3627                 // we can dispense with the loop, as has_inner -> 1st message struct attachment is message/rfc822
  3628                 //                   
  3629 
  3630                 bloblist_t* message_blob = msg->attachments;
  3631                                     
  3632                 if (msg->attachments) {
  3633                     message_blob = msg->attachments;
  3634                     if (!has_inner && strcmp(message_blob->mime_type, "message/rfc822") != 0
  3635                                    && strcmp(message_blob->mime_type, "text/rfc822") != 0)
  3636                         message_blob = NULL;
  3637                 }
  3638                     
  3639                 if (!message_blob) {
  3640                     bloblist_t* actual_message = msg->attachments;
  3641                 
  3642                     while (actual_message) {
  3643                         char* mime_type = actual_message->mime_type;
  3644                         if (mime_type) {
  3645                         
  3646                             // libetpan appears to change the mime_type on this one.
  3647                             // *growl*
  3648                             if (strcmp("message/rfc822", mime_type) == 0 ||
  3649                                 strcmp("text/rfc822", mime_type) == 0) {
  3650                                 message_blob = actual_message;
  3651                                 break;
  3652                             }
  3653                         }
  3654                         actual_message = actual_message->next;
  3655                     }        
  3656                 }    
  3657                 if (message_blob) {              
  3658                     status = mime_decode_message(message_blob->value, 
  3659                                                  message_blob->size, 
  3660                                                  &inner_message,
  3661                                                  NULL);
  3662                     if (status != PEP_STATUS_OK)
  3663                         goto pEp_error;
  3664                                 
  3665                     if (inner_message) {
  3666                         is_pEp_msg = is_a_pEpmessage(inner_message);
  3667                         
  3668                         // Though this will strip any message info on the
  3669                         // attachment, this is safe, as we do not
  3670                         // produce more than one attachment-as-message,
  3671                         // and those are the only ones with such info.
  3672                         // Since we capture the information, this is ok.
  3673                         wrap_info = NULL;
  3674                         inner_message->enc_format = src->enc_format;
  3675 
  3676                         const stringpair_list_t* pEp_protocol_version = NULL;
  3677                         pEp_protocol_version = stringpair_list_find(inner_message->opt_fields, "X-pEp-Version");
  3678                         
  3679                         if (pEp_protocol_version && pEp_protocol_version->value)
  3680                             pEp_version_major_minor(pEp_protocol_version->value->value, &major_ver, &minor_ver);
  3681 
  3682                         // Sort out pEp user status and version number based on INNER message.
  3683                         
  3684                         bool is_inner = false;
  3685                         bool is_key_reset = false;
  3686 
  3687                         // Deal with plaintext modification in 1.0 and 2.0 messages
  3688                         status = unencapsulate_hidden_fields(inner_message, NULL, &wrap_info);   
  3689                         
  3690                         if (status == PEP_OUT_OF_MEMORY)
  3691                             goto enomem;                
  3692                         if (status != PEP_STATUS_OK)
  3693                             goto pEp_error;                                         
  3694                             
  3695                         if (major_ver > 2 || (major_ver == 2 && minor_ver > 0)) {
  3696                             stringpair_list_t* searched = stringpair_list_find(inner_message->opt_fields, "X-pEp-Sender-FPR");                             
  3697                             inner_message->_sender_fpr = ((searched && searched->value && searched->value->value) ? strdup(searched->value->value) : NULL);
  3698                             searched = stringpair_list_find(inner_message->opt_fields, X_PEP_MSG_WRAP_KEY);
  3699                             if (searched && searched->value && searched->value->value) {
  3700                                 is_inner = (strcmp(searched->value->value, "INNER") == 0);
  3701                                 if (!is_inner)
  3702                                     is_key_reset = (strcmp(searched->value->value, "KEY_RESET") == 0);
  3703                                 if (is_inner || is_key_reset)
  3704                                     inner_message->opt_fields = stringpair_list_delete_by_key(inner_message->opt_fields, X_PEP_MSG_WRAP_KEY);
  3705                             }
  3706                         }
  3707                         else {
  3708                             is_inner = (strcmp(wrap_info, "INNER") == 0);
  3709                             if (!is_inner)
  3710                                 is_key_reset = (strcmp(wrap_info, "KEY_RESET") == 0);
  3711                         }
  3712                             
  3713 
  3714                         if (is_key_reset) {
  3715                             if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
  3716                                 status = receive_key_reset(session,
  3717                                                            inner_message);
  3718                                 if (status != PEP_STATUS_OK) {
  3719                                     free_message(inner_message);
  3720                                     goto pEp_error;
  3721                                 }
  3722                                 *flags |= PEP_decrypt_flag_consume;
  3723                             }
  3724                         }
  3725                         else if (is_inner) {
  3726 
  3727                             // check for private key in decrypted message attachment while importing
  3728                             // N.B. Apparently, we always import private keys into the keyring; however,
  3729                             // we do NOT always allow those to be used for encryption. THAT is controlled
  3730                             // by setting it as an own identity associated with the key in the DB.
  3731                             
  3732                             // If we have a message 2.0 message, we are ONLY going to be ok with keys
  3733                             // we imported from THIS part of the message.
  3734                             imported_private_key_address = false;
  3735                             free(private_il); 
  3736                             private_il = NULL;
  3737                             
  3738                             // import keys from decrypted INNER source
  3739                             status = import_priv_keys_from_decrypted_msg(session, inner_message,
  3740                                                                          &imported_keys,
  3741                                                                          &imported_private_key_address,
  3742                                                                          private_il);
  3743                             if (status != PEP_STATUS_OK)
  3744                                 goto pEp_error;            
  3745 
  3746                             // THIS is our message
  3747                             // Now, let's make sure we've copied in 
  3748                             // any information sent in by the app if
  3749                             // needed...
  3750                             reconcile_src_and_inner_messages(src, inner_message);
  3751                             
  3752 
  3753                             // FIXME: free msg, but check references
  3754                             //src = msg = inner_message;
  3755                             calculated_src = msg = inner_message;
  3756                             
  3757                         }
  3758                         else { // should never happen
  3759                             status = PEP_UNKNOWN_ERROR;
  3760                             free_message(inner_message);
  3761                             goto pEp_error;
  3762                         }
  3763                         inner_message->enc_format = PEP_enc_none;
  3764                     }
  3765                     else { // forwarded message, leave it alone
  3766                         free_message(inner_message);
  3767                     }
  3768                 } // end if (message_blob)
  3769                 
  3770                 //  else if (strcmp(wrap_info, "TRANSPORT") == 0) {
  3771                 //      // FIXME: this gets even messier.
  3772                 //      // (TBI in ENGINE-278)
  3773                 //  }
  3774                 //  else {} // shouldn't be anything to be done here
  3775     
  3776             } // end if (has_inner || wrap_info)
  3777             else {
  3778                 
  3779             } // this we do if this isn't an inner message
  3780             
  3781             pEp_identity* cs_from = calculated_src->from;
  3782             if (cs_from && !EMPTYSTR(cs_from->address)) {
  3783                 if (!is_me(session, cs_from)) {
  3784                     status = update_identity(session, cs_from);
  3785                     if (status == PEP_CANNOT_FIND_IDENTITY) {
  3786                         cs_from->user_id = calloc(1, strlen(cs_from->address) + 6);
  3787                         if (!cs_from->user_id)
  3788                             return PEP_OUT_OF_MEMORY;
  3789                         snprintf(cs_from->user_id, strlen(cs_from->address) + 6,
  3790                                  "TOFU_%s", cs_from->address);        
  3791                         status = PEP_STATUS_OK;
  3792                     }
  3793                 }
  3794                 else
  3795                     status = _myself(session, cs_from, false, false, myself_read_only);
  3796             }                                                                        
  3797         } // end if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
  3798         
  3799         *rating = decrypt_rating(decrypt_status);
  3800         
  3801         // Ok, so if it was signed and it's all verified, we can update
  3802         // eligible signer comm_types to PEP_ct_pEp_*
  3803         // This also sets and upgrades pEp version
  3804         if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && is_pEp_msg && calculated_src->from)
  3805             status = update_sender_to_pEp_trust(session, calculated_src->from, _keylist, major_ver, minor_ver);
  3806 
  3807         /* Ok, now we have a keylist used for decryption/verification.
  3808            now we need to update the message rating with the 
  3809            sender and recipients in mind */
  3810         status = amend_rating_according_to_sender_and_recipients(session,
  3811                  rating, calculated_src->from, _keylist);
  3812 
  3813         if (status != PEP_STATUS_OK)
  3814             goto pEp_error;
  3815         
  3816         /* We decrypted ok, hallelujah. */
  3817         msg->enc_format = PEP_enc_none;    
  3818     } 
  3819     else {
  3820         // We did not get a plaintext out of the decryption process.
  3821         // Abort and return error.
  3822         *rating = decrypt_rating(decrypt_status);
  3823         goto pEp_error;
  3824     }
  3825 
  3826     /* 
  3827        Ok, at this point, we know we have a reliably decrypted message.
  3828        Prepare the output message for return.
  3829     */
  3830     
  3831     // 1. Check to see if this message is to us and contains an own key imported 
  3832     // from own trusted message
  3833     if (*rating >= PEP_rating_trusted && imported_private_key_address) {
  3834 
  3835         if (msg && msg->to && msg->to->ident) {            
  3836             // This will only happen rarely, so we can do this.
  3837             PEP_STATUS _tmp_status = PEP_STATUS_OK;
  3838             
  3839             if (!is_me(session, msg->to->ident))
  3840                 _tmp_status = update_identity(session, msg->to->ident);
  3841             
  3842             if (_tmp_status == PEP_STATUS_OK && is_me(session, msg->to->ident)) {
  3843                 // flag it as such
  3844                 *flags |= PEP_decrypt_flag_own_private_key;
  3845             }
  3846         }
  3847     }
  3848 
  3849     // 2. Clean up message and prepare for return 
  3850     if (msg) {
  3851         
  3852         /* add pEp-related status flags to header */
  3853         decorate_message(msg, *rating, _keylist, false, false);
  3854 
  3855         // Maybe unnecessary
  3856         // if (imported_keys)
  3857         //     remove_attached_keys(msg);
  3858                     
  3859         if (calculated_src->id && calculated_src != msg) {
  3860             msg->id = strdup(calculated_src->id);
  3861             assert(msg->id);
  3862             if (msg->id == NULL)
  3863                 goto enomem;
  3864         }
  3865     } // End prepare output message for return
  3866 
  3867     // 3. Check to see if the sender used any of our revoked keys
  3868     stringpair_list_t* revoke_replace_pairs = NULL;
  3869     status = check_for_own_revoked_key(session, _keylist, &revoke_replace_pairs);
  3870 
  3871     //assert(status != PEP_STATUS_OK); // FIXME: FOR DEBUGGING ONLY DO NOT LEAVE IN    
  3872     if (status != PEP_STATUS_OK) {
  3873         // This should really never choke unless the DB is broken.
  3874         status = PEP_UNKNOWN_DB_ERROR;
  3875         goto pEp_error;
  3876     }
  3877     
  3878     if (msg) {
  3879         stringpair_list_t* curr_pair_node;
  3880         stringpair_t* curr_pair;
  3881 
  3882         for (curr_pair_node = revoke_replace_pairs; curr_pair_node; curr_pair_node = curr_pair_node->next) {
  3883             curr_pair = curr_pair_node->value;
  3884 
  3885             if (!curr_pair)
  3886                 continue; // Again, shouldn't occur
  3887 
  3888             if (curr_pair->key && curr_pair->value) {
  3889                 status = create_standalone_key_reset_message(session,
  3890                     &reset_msg,
  3891                     msg->from,
  3892                     curr_pair->key,
  3893                     curr_pair->value);
  3894 
  3895                 // If we can't find the identity, this is someone we've never mailed, so we just
  3896                 // go on letting them use the wrong key until we mail them ourselves. (Spammers, etc)
  3897                 if (status != PEP_CANNOT_FIND_IDENTITY) {
  3898                     if (status != PEP_STATUS_OK)
  3899                         goto pEp_error;
  3900 
  3901                     if (!reset_msg) {
  3902                         status = PEP_OUT_OF_MEMORY;
  3903                         goto pEp_error;
  3904                     }
  3905                     // insert into queue
  3906                     if (session->messageToSend)
  3907                         status = session->messageToSend(reset_msg);
  3908                     else
  3909                         status = PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
  3910 
  3911 
  3912                     if (status == PEP_STATUS_OK) {
  3913                         // Put into notified DB
  3914                         status = set_reset_contact_notified(session, curr_pair->key, msg->from->user_id);
  3915                         if (status != PEP_STATUS_OK) // It's ok to barf because it's a DB problem??
  3916                             goto pEp_error;
  3917                     }
  3918                     else {
  3919                         // According to Volker, this would only be a fatal error, so...
  3920                         free_message(reset_msg); // ??
  3921                         reset_msg = NULL; // ??
  3922                         goto pEp_error;
  3923                     }
  3924                 }
  3925             }
  3926         }
  3927     }
  3928     
  3929     // 4. Set up return values
  3930     *dst = msg;
  3931     *keylist = _keylist;
  3932 
  3933     // 5. Reencrypt if necessary
  3934     if (reencrypt) {
  3935         if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
  3936             message* reencrypt_msg = NULL;
  3937             PEP_STATUS reencrypt_status = PEP_CANNOT_REENCRYPT;
  3938             char* own_id = NULL;
  3939             status = get_default_own_userid(session, &own_id);
  3940             if (own_id) {
  3941                 char* target_own_fpr = seek_good_trusted_private_fpr(session,
  3942                                                                      own_id,
  3943                                                                      _keylist);
  3944                 if (target_own_fpr) {
  3945                     pEp_identity* target_id = new_identity(NULL, target_own_fpr, 
  3946                                                            own_id, NULL);
  3947                     if (target_id) {
  3948                         reencrypt_status = encrypt_message_for_self(session, target_id, msg,
  3949                                                                     extra, &reencrypt_msg, PEP_enc_PGP_MIME,
  3950                                                                     0);
  3951                         if (reencrypt_status != PEP_STATUS_OK)
  3952                             reencrypt_status = PEP_CANNOT_REENCRYPT;
  3953                         
  3954                         free_identity(target_id);
  3955                     }
  3956                     free(target_own_fpr);
  3957                 }     
  3958                 free(own_id);
  3959             }
  3960             free_stringlist(extra); // This was an input variable for us. Keylist is overwritten above.
  3961             
  3962             if (reencrypt_status != PEP_CANNOT_REENCRYPT && reencrypt_msg) {
  3963                 message_transfer(src, reencrypt_msg);
  3964                 *flags |= PEP_decrypt_flag_src_modified;
  3965                 free_message(reencrypt_msg);
  3966             }
  3967             else
  3968                 decrypt_status = PEP_CANNOT_REENCRYPT;
  3969         }
  3970     }
  3971         
  3972     if(decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
  3973         return PEP_STATUS_OK;
  3974     else
  3975         return decrypt_status;
  3976 
  3977 enomem:
  3978     status = PEP_OUT_OF_MEMORY;
  3979 
  3980 pEp_error:
  3981     free(ptext);
  3982     free(signer_fpr);
  3983     free_message(msg);
  3984     free_message(reset_msg);
  3985     free_stringlist(_keylist);
  3986 
  3987     return status;
  3988 }
  3989 
  3990 DYNAMIC_API PEP_STATUS decrypt_message(
  3991         PEP_SESSION session,
  3992         message *src,
  3993         message **dst,
  3994         stringlist_t **keylist,
  3995         PEP_rating *rating,
  3996         PEP_decrypt_flags_t *flags
  3997     )
  3998 {
  3999     assert(session);
  4000     assert(src);
  4001     assert(dst);
  4002     assert(keylist);
  4003     assert(rating);
  4004     assert(flags);
  4005 
  4006     if (!(session && src && dst && keylist && rating && flags))
  4007         return PEP_ILLEGAL_VALUE;
  4008 
  4009     if (!(*flags & PEP_decrypt_flag_untrusted_server))
  4010         *keylist = NULL;
  4011     //*keylist = NULL; // NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!!!!!! This fucks up reencryption
  4012     PEP_STATUS status = _decrypt_message(session, src, dst, keylist, rating, flags, NULL);
  4013 
  4014     message *msg = *dst ? *dst : src;
  4015 
  4016     if (session->inject_sync_event && msg && msg->from &&
  4017             !(*flags & PEP_decrypt_flag_dont_trigger_sync)) {
  4018         size_t size;
  4019         const char *data;
  4020         char *sender_fpr = NULL;
  4021         PEP_STATUS tmpstatus = base_extract_message(session, msg, &size, &data, &sender_fpr);
  4022         if (!tmpstatus && size && data) {
  4023             if (sender_fpr)
  4024                 signal_Sync_message(session, *rating, data, size, msg->from, sender_fpr);
  4025             // FIXME: this must be changed to sender_fpr
  4026             else if (*keylist)
  4027                 signal_Sync_message(session, *rating, data, size, msg->from, (*keylist)->value);
  4028         }
  4029         free(sender_fpr);
  4030     }
  4031 
  4032     return status;
  4033 }
  4034 
  4035 DYNAMIC_API PEP_STATUS own_message_private_key_details(
  4036         PEP_SESSION session,
  4037         message *msg,
  4038         pEp_identity **ident
  4039     )
  4040 {
  4041     assert(session);
  4042     assert(msg);
  4043     assert(ident);
  4044 
  4045     if (!(session && msg && ident))
  4046         return PEP_ILLEGAL_VALUE;
  4047 
  4048     message *dst = NULL;
  4049     stringlist_t *keylist = NULL;
  4050     PEP_rating rating;
  4051     PEP_decrypt_flags_t flags;
  4052 
  4053     *ident = NULL;
  4054 
  4055     identity_list *private_il = NULL;
  4056     PEP_STATUS status = _decrypt_message(session, msg,  &dst, &keylist, &rating, &flags, &private_il);
  4057     free_message(dst);
  4058     free_stringlist(keylist);
  4059 
  4060     if (status == PEP_STATUS_OK &&
  4061         flags & PEP_decrypt_flag_own_private_key &&
  4062         private_il)
  4063     {
  4064         *ident = identity_dup(private_il->ident);
  4065     }
  4066 
  4067     free_identity_list(private_il);
  4068 
  4069     return status;
  4070 }
  4071 
  4072 // Note: if comm_type_determine is false, it generally means that
  4073 // we were unable to get key information for anyone in the list,
  4074 // likely because a key is missing.
  4075 static void _max_comm_type_from_identity_list(
  4076         identity_list *identities,
  4077         PEP_SESSION session,
  4078         PEP_comm_type *max_comm_type,
  4079         bool *comm_type_determined
  4080     )
  4081 {
  4082     identity_list * il;
  4083     for (il = identities; il != NULL; il = il->next)
  4084     {
  4085         if (il->ident)
  4086         {   
  4087             PEP_STATUS status = PEP_STATUS_OK;
  4088             *max_comm_type = _get_comm_type(session, *max_comm_type,
  4089                 il->ident);
  4090             *comm_type_determined = true;
  4091             
  4092             bool is_blacklisted = false;
  4093             if (il->ident->fpr && IS_PGP_CT(il->ident->comm_type)) {
  4094                 status = blacklist_is_listed(session, il->ident->fpr, &is_blacklisted);
  4095                 if (is_blacklisted) {
  4096                     bool user_default, ident_default, address_default; 
  4097                     status = get_valid_pubkey(session, il->ident,
  4098                                               &ident_default, &user_default,
  4099                                               &address_default,
  4100                                               true);
  4101                     if (status != PEP_STATUS_OK || il->ident->fpr == NULL) {
  4102                         il->ident->comm_type = PEP_ct_key_not_found;
  4103                         if (*max_comm_type > PEP_ct_no_encryption)
  4104                             *max_comm_type = PEP_ct_no_encryption;
  4105                     }
  4106                 }    
  4107             }
  4108     
  4109             // check for the return statuses which might not a representative
  4110             // value in the comm_type
  4111             if (status == PEP_ILLEGAL_VALUE || status == PEP_CANNOT_SET_PERSON ||
  4112                 status == PEP_CANNOT_FIND_IDENTITY) {
  4113                 // PEP_CANNOT_FIND_IDENTITY only comes back when we've really
  4114                 // got nothing from update_identity after applying the whole
  4115                 // heuristic
  4116                 *max_comm_type = PEP_ct_no_encryption;
  4117                 *comm_type_determined = true;
  4118             }
  4119         }
  4120     }
  4121 }
  4122 
  4123 static void _max_comm_type_from_identity_list_preview(
  4124         identity_list *identities,
  4125         PEP_SESSION session,
  4126         PEP_comm_type *max_comm_type
  4127     )
  4128 {
  4129     identity_list * il;
  4130     for (il = identities; il != NULL; il = il->next)
  4131     {
  4132         if (il->ident)
  4133         {   
  4134             *max_comm_type = _get_comm_type_preview(session, *max_comm_type,
  4135                 il->ident);
  4136         }
  4137     }
  4138 }
  4139 
  4140 DYNAMIC_API PEP_STATUS outgoing_message_rating(
  4141         PEP_SESSION session,
  4142         message *msg,
  4143         PEP_rating *rating
  4144     )
  4145 {
  4146     PEP_comm_type max_comm_type = PEP_ct_pEp;
  4147     bool comm_type_determined = false;
  4148 
  4149     assert(session);
  4150     assert(msg);
  4151     assert(msg->dir == PEP_dir_outgoing);
  4152     assert(rating);
  4153 
  4154     if (!(session && msg && rating))
  4155         return PEP_ILLEGAL_VALUE;
  4156 
  4157     if (msg->dir != PEP_dir_outgoing)
  4158         return PEP_ILLEGAL_VALUE;
  4159 
  4160     *rating = PEP_rating_undefined;
  4161 
  4162     _max_comm_type_from_identity_list(msg->to, session,
  4163                                       &max_comm_type, &comm_type_determined);
  4164 
  4165     _max_comm_type_from_identity_list(msg->cc, session,
  4166                                       &max_comm_type, &comm_type_determined);
  4167 
  4168     _max_comm_type_from_identity_list(msg->bcc, session,
  4169                                       &max_comm_type, &comm_type_determined);
  4170 
  4171     if (comm_type_determined == false) {
  4172         // likely means there was a massive screwup with no sender or recipient
  4173         // keys
  4174         *rating = PEP_rating_undefined;
  4175     }
  4176     else
  4177         *rating = _MAX(_rating(max_comm_type), PEP_rating_unencrypted);
  4178 
  4179     return PEP_STATUS_OK;
  4180 }
  4181 
  4182 DYNAMIC_API PEP_STATUS outgoing_message_rating_preview(
  4183         PEP_SESSION session,
  4184         message *msg,
  4185         PEP_rating *rating
  4186     )
  4187 {
  4188     PEP_comm_type max_comm_type = PEP_ct_pEp;
  4189 
  4190     assert(session);
  4191     assert(msg);
  4192     assert(msg->dir == PEP_dir_outgoing);
  4193     assert(rating);
  4194 
  4195     if (!(session && msg && rating))
  4196         return PEP_ILLEGAL_VALUE;
  4197 
  4198     if (msg->dir != PEP_dir_outgoing)
  4199         return PEP_ILLEGAL_VALUE;
  4200 
  4201     *rating = PEP_rating_undefined;
  4202 
  4203     _max_comm_type_from_identity_list_preview(msg->to, session,
  4204             &max_comm_type);
  4205 
  4206     _max_comm_type_from_identity_list_preview(msg->cc, session,
  4207             &max_comm_type);
  4208 
  4209     _max_comm_type_from_identity_list_preview(msg->bcc, session,
  4210             &max_comm_type);
  4211 
  4212     *rating = _MAX(_rating(max_comm_type), PEP_rating_unencrypted);
  4213 
  4214     return PEP_STATUS_OK;
  4215 }
  4216 
  4217 DYNAMIC_API PEP_STATUS identity_rating(
  4218         PEP_SESSION session,
  4219         pEp_identity *ident,
  4220         PEP_rating *rating
  4221     )
  4222 {
  4223     PEP_STATUS status = PEP_STATUS_OK;
  4224 
  4225     assert(session);
  4226     assert(ident);
  4227     assert(rating);
  4228 
  4229     if (!(session && ident && rating))
  4230         return PEP_ILLEGAL_VALUE;
  4231 
  4232     *rating = PEP_rating_undefined;
  4233 
  4234     if (ident->me)
  4235         status = _myself(session, ident, false, true, true);
  4236     else
  4237         status = update_identity(session, ident);
  4238 
  4239     bool is_blacklisted = false;
  4240     
  4241     if (ident->fpr && IS_PGP_CT(ident->comm_type)) {
  4242         status = blacklist_is_listed(session, ident->fpr, &is_blacklisted);
  4243         if (status != PEP_STATUS_OK) {
  4244             return status; // DB ERROR
  4245         }
  4246         if (is_blacklisted) {
  4247             bool user_default, ident_default, address_default; 
  4248             status = get_valid_pubkey(session, ident,
  4249                                        &ident_default, &user_default,
  4250                                        &address_default,
  4251                                        true);
  4252             if (status != PEP_STATUS_OK || ident->fpr == NULL) {
  4253                 ident->comm_type = PEP_ct_key_not_found;
  4254                 status = PEP_STATUS_OK;                        
  4255             }
  4256         }    
  4257     }
  4258 
  4259     if (status == PEP_STATUS_OK)
  4260         *rating = _rating(ident->comm_type);
  4261 
  4262     return status;
  4263 }
  4264 
  4265 DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
  4266 {
  4267     PEP_STATUS status = PEP_STATUS_OK;
  4268 
  4269     assert(path);
  4270     if (path == NULL)
  4271         return PEP_ILLEGAL_VALUE;
  4272 
  4273     if (cryptotech[tech].binary_path == NULL)
  4274         *path = NULL;
  4275     else
  4276         status = cryptotech[tech].binary_path(path);
  4277 
  4278     return status;
  4279 }
  4280 
  4281 
  4282 DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
  4283 {
  4284     if (rating == PEP_rating_b0rken || rating == PEP_rating_have_no_key)
  4285         return PEP_color_no_color;
  4286 
  4287     if (rating < PEP_rating_undefined)
  4288         return PEP_color_red;
  4289 
  4290     if (rating < PEP_rating_reliable)
  4291         return PEP_color_no_color;
  4292 
  4293     if (rating < PEP_rating_trusted)
  4294         return PEP_color_yellow;
  4295 
  4296     if (rating >= PEP_rating_trusted)
  4297         return PEP_color_green;
  4298 
  4299     // this should never happen
  4300     assert(false);
  4301     return PEP_color_no_color;
  4302 }
  4303 
  4304 /* [0-9]: 0x30 - 0x39; [A-F] = 0x41 - 0x46; [a-f] = 0x61 - 0x66 */
  4305 static short asciihex_to_num(char a) {
  4306     short conv_num = -1;
  4307     if (a >= 0x30 && a <= 0x39)
  4308         conv_num = a - 0x30;
  4309     else {
  4310         // convert case, subtract offset, get number
  4311         conv_num = ((a | 0x20) - 0x61) + 10;
  4312         if (conv_num < 0xa || conv_num > 0xf)
  4313             conv_num = -1;
  4314     }
  4315     return conv_num;
  4316 }
  4317 
  4318 static char num_to_asciihex(short h) {
  4319     if (h < 0 || h > 16)
  4320         return '\0';
  4321     if (h < 10)
  4322         return (char)(h + 0x30);
  4323     return (char)((h - 10) + 0x41); // for readability
  4324 }
  4325 
  4326 static char xor_hex_chars(char a, char b) {
  4327     short a_num = asciihex_to_num(a);
  4328     short b_num = asciihex_to_num(b);
  4329     if (a_num < 0 || b_num < 0)
  4330         return '\0';
  4331     short xor_num = a_num^b_num;
  4332     return num_to_asciihex(xor_num);
  4333 }
  4334 
  4335 static const char* skip_separators(const char* current, const char* begin) {
  4336     while (current >= begin) {
  4337         /* .:,;-_ ' ' - [2c-2e] [3a-3b] [20] [5f] */
  4338         char check_char = *current;
  4339         switch (check_char) {
  4340             case '.':
  4341             case ':':
  4342             case ',':
  4343             case ';':
  4344             case '-':
  4345             case '_':
  4346             case ' ':
  4347                 current--;
  4348                 continue;
  4349             default:
  4350                 break;
  4351         }
  4352         break;
  4353     }
  4354     return current;
  4355 }
  4356 
  4357 PEP_STATUS check_for_zero_fpr(char* fpr) {
  4358     PEP_STATUS status = PEP_TRUSTWORDS_DUPLICATE_FPR;
  4359     
  4360     while (*fpr) {
  4361         if (*fpr != '0') {
  4362             status = PEP_STATUS_OK;
  4363             break;
  4364         }
  4365         fpr++;    
  4366     }
  4367     
  4368     return status;
  4369     
  4370 }
  4371 
  4372 DYNAMIC_API PEP_STATUS get_trustwords(
  4373         PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
  4374         const char* lang, char **words, size_t *wsize, bool full
  4375     )
  4376 {
  4377     assert(session && id1 && id1->fpr && id2 && id2->fpr&& lang && words &&
  4378             wsize);
  4379     if (!(session && id1 && id1->fpr && id2 && id2->fpr&& lang && words &&
  4380                 wsize))
  4381         return PEP_ILLEGAL_VALUE;
  4382 
  4383     return get_trustwords_for_fprs(session, id1->fpr, id2->fpr, lang, words,
  4384             wsize, full);
  4385 }
  4386 
  4387 DYNAMIC_API PEP_STATUS get_trustwords_for_fprs(
  4388         PEP_SESSION session, const char* fpr1, const char* fpr2,
  4389         const char* lang, char **words, size_t *wsize, bool full
  4390     )
  4391 {
  4392     assert(session && fpr1 && fpr2 && words && wsize);
  4393     if (!(session && fpr1 && fpr2 && words && wsize))
  4394         return PEP_ILLEGAL_VALUE;
  4395 
  4396     const int SHORT_NUM_TWORDS = 5; 
  4397     PEP_STATUS status = PEP_STATUS_OK;
  4398     
  4399     *words = NULL;    
  4400     *wsize = 0;
  4401 
  4402     int fpr1_len = strlen(fpr1);
  4403     int fpr2_len = strlen(fpr2);
  4404         
  4405     int max_len = (fpr1_len > fpr2_len ? fpr1_len : fpr2_len);
  4406     
  4407     char* XORed_fpr = (char*)(calloc(max_len + 1, 1));
  4408     *(XORed_fpr + max_len) = '\0';
  4409     char* result_curr = XORed_fpr + max_len - 1;
  4410     const char* fpr1_curr = fpr1 + fpr1_len - 1;
  4411     const char* fpr2_curr = fpr2 + fpr2_len - 1;
  4412 
  4413     while (fpr1 <= fpr1_curr && fpr2 <= fpr2_curr) {
  4414         fpr1_curr = skip_separators(fpr1_curr, fpr1);
  4415         fpr2_curr = skip_separators(fpr2_curr, fpr2);
  4416         
  4417         if (fpr1_curr < fpr1 || fpr2_curr < fpr2)
  4418             break;
  4419             
  4420         char xor_hex = xor_hex_chars(*fpr1_curr, *fpr2_curr);
  4421         if (xor_hex == '\0') {
  4422             status = PEP_ILLEGAL_VALUE;
  4423             goto error_release;
  4424         }
  4425         
  4426         *result_curr = xor_hex;
  4427         result_curr--; fpr1_curr--; fpr2_curr--;
  4428     }
  4429 
  4430     const char* remainder_start = NULL;
  4431     const char* remainder_curr = NULL;
  4432     
  4433     if (fpr1 <= fpr1_curr) {
  4434         remainder_start = fpr1;
  4435         remainder_curr = fpr1_curr;
  4436     }
  4437     else if (fpr2 <= fpr2_curr) {
  4438         remainder_start = fpr2;
  4439         remainder_curr = fpr2_curr;
  4440     }
  4441     if (remainder_curr) {
  4442         while (remainder_start <= remainder_curr) {
  4443             remainder_curr = skip_separators(remainder_curr, remainder_start);
  4444             
  4445             if (remainder_curr < remainder_start)
  4446                 break;
  4447             
  4448             char the_char = *remainder_curr;
  4449             
  4450             if (asciihex_to_num(the_char) < 0) {
  4451                 status = PEP_ILLEGAL_VALUE;
  4452                 goto error_release;
  4453             }
  4454             
  4455             *result_curr = the_char;                
  4456             result_curr--;
  4457             remainder_curr--;
  4458         }
  4459     }
  4460     
  4461     result_curr++;
  4462 
  4463     if (result_curr > XORed_fpr) {
  4464         char* tempstr = strdup(result_curr);
  4465         free(XORed_fpr);
  4466         XORed_fpr = tempstr;
  4467     }
  4468     
  4469     status = check_for_zero_fpr(XORed_fpr);
  4470     
  4471     if (status != PEP_STATUS_OK)
  4472         goto error_release;
  4473     
  4474     size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
  4475 
  4476     char* the_words = NULL;
  4477     size_t the_size = 0;
  4478 
  4479     status = trustwords(session, XORed_fpr, lang, &the_words, &the_size, max_words_per_id);
  4480     if (status != PEP_STATUS_OK)
  4481         goto error_release;
  4482 
  4483     *words = the_words;
  4484     *wsize = the_size;
  4485     
  4486     status = PEP_STATUS_OK;
  4487 
  4488     goto the_end;
  4489 
  4490     error_release:
  4491         free (XORed_fpr);
  4492         
  4493     the_end:
  4494     return status;
  4495 }
  4496 
  4497 DYNAMIC_API PEP_STATUS get_message_trustwords(
  4498     PEP_SESSION session, 
  4499     message *msg,
  4500     stringlist_t *keylist,
  4501     pEp_identity* received_by,
  4502     const char* lang, char **words, bool full
  4503 )
  4504 {
  4505     assert(session);
  4506     assert(msg);
  4507     assert(received_by);
  4508     assert(received_by->address);
  4509     assert(lang);
  4510     assert(words);
  4511 
  4512     if (!(session && 
  4513           msg &&
  4514           received_by && 
  4515           received_by->address && 
  4516           lang && 
  4517           words))
  4518         return PEP_ILLEGAL_VALUE;
  4519     
  4520     pEp_identity* partner = NULL;
  4521      
  4522     PEP_STATUS status = PEP_STATUS_OK;
  4523     
  4524     *words = NULL;
  4525 
  4526     // We want fingerprint of key that did sign the message
  4527 
  4528     if (keylist == NULL) {
  4529 
  4530         // Message is to be decrypted
  4531         message *dst = NULL;
  4532         stringlist_t *_keylist = keylist;
  4533         PEP_rating rating;
  4534         PEP_decrypt_flags_t flags;
  4535         status = decrypt_message( session, msg, &dst, &_keylist, &rating, &flags);
  4536 
  4537         if (status != PEP_STATUS_OK) {
  4538             free_message(dst);
  4539             free_stringlist(_keylist);
  4540             return status;
  4541         }
  4542 
  4543         if (dst && dst->from && _keylist) {
  4544             partner = identity_dup(dst->from); 
  4545             if(partner){
  4546                 free(partner->fpr);
  4547                 partner->fpr = strdup(_keylist->value);
  4548                 if (partner->fpr == NULL)
  4549                     status = PEP_OUT_OF_MEMORY;
  4550             } else {
  4551                 status = PEP_OUT_OF_MEMORY;
  4552             }
  4553         } else {
  4554             status = PEP_UNKNOWN_ERROR;
  4555         }
  4556 
  4557         free_message(dst);
  4558         free_stringlist(_keylist);
  4559 
  4560     } else {
  4561 
  4562         // Message already decrypted
  4563         if (keylist->value) {
  4564             partner = identity_dup(msg->from); 
  4565             if(partner){
  4566                 free(partner->fpr);
  4567                 partner->fpr = strdup(keylist->value);
  4568                 if (partner->fpr == NULL)
  4569                     status = PEP_OUT_OF_MEMORY;
  4570             } else {
  4571                 status = PEP_OUT_OF_MEMORY;
  4572             }
  4573         } else {
  4574             status = PEP_ILLEGAL_VALUE;
  4575         }
  4576     }
  4577 
  4578     if (status != PEP_STATUS_OK) {
  4579         free_identity(partner);
  4580         return status;
  4581     }
  4582    
  4583     // Find own identity corresponding to given account address.
  4584     // In that case we want default key attached to own identity
  4585     pEp_identity *stored_identity = NULL;
  4586     
  4587     char* own_id = NULL;
  4588     status = get_default_own_userid(session, &own_id);
  4589 
  4590     if (!(status == PEP_STATUS_OK && own_id)) {
  4591         free(own_id);
  4592         return PEP_CANNOT_FIND_IDENTITY;
  4593     }
  4594     
  4595     status = get_identity(session,
  4596                           received_by->address,
  4597                           own_id,
  4598                           &stored_identity);
  4599     free(own_id);
  4600     own_id = NULL;                      
  4601 
  4602     if (status != PEP_STATUS_OK) {
  4603         free_identity(stored_identity);
  4604         return status;
  4605     }
  4606 
  4607     // get the trustwords
  4608     size_t wsize;
  4609     status = get_trustwords(session, 
  4610                             partner, received_by, 
  4611                             lang, words, &wsize, full);
  4612 
  4613     return status;
  4614 }
  4615 
  4616 static PEP_rating string_to_rating(const char * rating)
  4617 {
  4618     if (rating == NULL)
  4619         return PEP_rating_undefined;
  4620     if (strcmp(rating, "cannot_decrypt") == 0)
  4621         return PEP_rating_cannot_decrypt;
  4622     if (strcmp(rating, "have_no_key") == 0)
  4623         return PEP_rating_have_no_key;
  4624     if (strcmp(rating, "unencrypted") == 0)
  4625         return PEP_rating_unencrypted;
  4626     if (strcmp(rating, "unencrypted_for_some") == 0)
  4627         return PEP_rating_undefined; // don't use this any more
  4628     if (strcmp(rating, "unreliable") == 0)
  4629         return PEP_rating_unreliable;
  4630     if (strcmp(rating, "reliable") == 0)
  4631         return PEP_rating_reliable;
  4632     if (strcmp(rating, "trusted") == 0)
  4633         return PEP_rating_trusted;
  4634     if (strcmp(rating, "trusted_and_anonymized") == 0)
  4635         return PEP_rating_trusted_and_anonymized;
  4636     if (strcmp(rating, "fully_anonymous") == 0)
  4637         return PEP_rating_fully_anonymous;
  4638     if (strcmp(rating, "mistrust") == 0)
  4639         return PEP_rating_mistrust;
  4640     if (strcmp(rating, "b0rken") == 0)
  4641         return PEP_rating_b0rken;
  4642     if (strcmp(rating, "under_attack") == 0)
  4643         return PEP_rating_under_attack;
  4644     return PEP_rating_undefined;
  4645 }
  4646 
  4647 static PEP_STATUS string_to_keylist(const char * skeylist, stringlist_t **keylist)
  4648 {
  4649     if (skeylist == NULL || keylist == NULL)
  4650         return PEP_ILLEGAL_VALUE;
  4651 
  4652     stringlist_t *rkeylist = NULL;
  4653     stringlist_t *_kcurr = NULL;
  4654     const char * fpr_begin = skeylist;
  4655     const char * fpr_end = NULL;
  4656 
  4657     do {
  4658         fpr_end = strstr(fpr_begin, ",");
  4659         
  4660         char * fpr = strndup(
  4661             fpr_begin,
  4662             (fpr_end == NULL) ? strlen(fpr_begin) : fpr_end - fpr_begin);
  4663         
  4664         if (fpr == NULL)
  4665             goto enomem;
  4666         
  4667         _kcurr = stringlist_add(_kcurr, fpr);
  4668         if (_kcurr == NULL) {
  4669             free(fpr);
  4670             goto enomem;
  4671         }
  4672         
  4673         if (rkeylist == NULL)
  4674             rkeylist = _kcurr;
  4675         
  4676         fpr_begin = fpr_end ? fpr_end + 1 : NULL;
  4677         
  4678     } while (fpr_begin);
  4679     
  4680     *keylist = rkeylist;
  4681     return PEP_STATUS_OK;
  4682     
  4683 enomem:
  4684     free_stringlist(rkeylist);
  4685     return PEP_OUT_OF_MEMORY;
  4686 }
  4687 
  4688 DYNAMIC_API PEP_STATUS re_evaluate_message_rating(
  4689     PEP_SESSION session,
  4690     message *msg,
  4691     stringlist_t *x_keylist,
  4692     PEP_rating x_enc_status,
  4693     PEP_rating *rating
  4694 )
  4695 {
  4696     PEP_STATUS status = PEP_STATUS_OK;
  4697     stringlist_t *_keylist = x_keylist;
  4698     bool must_free_keylist = false;
  4699     PEP_rating _rating;
  4700 
  4701     assert(session);
  4702     assert(msg);
  4703     assert(rating);
  4704 
  4705     if (!(session && msg && rating))
  4706         return PEP_ILLEGAL_VALUE;
  4707 
  4708     *rating = PEP_rating_undefined;
  4709 
  4710     if (x_enc_status == PEP_rating_undefined){
  4711         for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
  4712             if (strcasecmp(i->value->key, "X-EncStatus") == 0){
  4713                 x_enc_status = string_to_rating(i->value->value);
  4714                 goto got_rating;
  4715             }
  4716         }
  4717         return PEP_ILLEGAL_VALUE;
  4718     }
  4719 
  4720 got_rating:
  4721 
  4722     _rating = x_enc_status;
  4723 
  4724     if (_keylist == NULL){
  4725         for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
  4726             if (strcasecmp(i->value->key, "X-KeyList") == 0){
  4727                 status = string_to_keylist(i->value->value, &_keylist);
  4728                 if (status != PEP_STATUS_OK)
  4729                     goto pEp_error;
  4730                 must_free_keylist = true;
  4731                 goto got_keylist;
  4732             }
  4733         }
  4734 
  4735         // there was no rcpt fpr, it could be an unencrypted mail
  4736         if(_rating == PEP_rating_unencrypted) {
  4737             *rating = _rating;
  4738             return PEP_STATUS_OK;
  4739         }
  4740 
  4741         return PEP_ILLEGAL_VALUE;
  4742     }
  4743 got_keylist:
  4744 
  4745     if (!is_me(session, msg->from))
  4746         status = update_identity(session, msg->from);
  4747     else
  4748         status = _myself(session, msg->from, false, false, true);
  4749 
  4750     switch (status) {
  4751         case PEP_KEY_NOT_FOUND:
  4752         case PEP_KEY_UNSUITABLE:
  4753         case PEP_KEY_BLACKLISTED:
  4754         case PEP_CANNOT_FIND_IDENTITY:
  4755         case PEP_CANNOT_FIND_ALIAS:
  4756             status = PEP_STATUS_OK;
  4757         case PEP_STATUS_OK:
  4758             break;
  4759         default:
  4760             goto pEp_error;
  4761     }
  4762 
  4763     status = amend_rating_according_to_sender_and_recipients(session, &_rating,
  4764             msg->from, _keylist);
  4765     if (status == PEP_STATUS_OK)
  4766         *rating = _rating;
  4767     
  4768 pEp_error:
  4769     if (must_free_keylist)
  4770         free_stringlist(_keylist);
  4771 
  4772     return status;
  4773 }
  4774 
  4775 DYNAMIC_API PEP_STATUS get_key_rating_for_user(
  4776         PEP_SESSION session,
  4777         const char *user_id,
  4778         const char *fpr,
  4779         PEP_rating *rating
  4780     )
  4781 {
  4782     assert(session && user_id && user_id[0] && fpr && fpr[0] && rating);
  4783     if (!(session && user_id && user_id[0] && fpr && fpr[0] && rating))
  4784         return PEP_ILLEGAL_VALUE;
  4785 
  4786     *rating = PEP_rating_undefined;
  4787 
  4788     pEp_identity *ident = new_identity(NULL, fpr, user_id, NULL);
  4789     if (!ident)
  4790         return PEP_OUT_OF_MEMORY;
  4791 
  4792     PEP_STATUS status = get_trust(session, ident);
  4793     if (status)
  4794         goto the_end;
  4795 
  4796     if (!ident->comm_type) {
  4797         status = PEP_RECORD_NOT_FOUND;
  4798         goto the_end;
  4799     }
  4800 
  4801     *rating = _rating(ident->comm_type);
  4802 
  4803 the_end:
  4804     free_identity(ident);
  4805     return status;
  4806 }