merged in default message-2.0
authorKrista Bennett <krista@pep-project.org>
Wed, 28 Jun 2017 11:21:52 +0200
branchmessage-2.0
changeset 18902f85b57d9964
parent 1855 18dce9e2977a
parent 1888 49612a614567
child 1906 104b801dc351
merged in default
     1.1 --- a/src/keymanagement.c	Tue Jun 13 13:00:37 2017 +0200
     1.2 +++ b/src/keymanagement.c	Wed Jun 28 11:21:52 2017 +0200
     1.3 @@ -91,7 +91,7 @@
     1.4      assert(!EMPTYSTR(identity->address));
     1.5  
     1.6      if (!(session && identity && !EMPTYSTR(identity->address)))
     1.7 -        return ERROR(PEP_ILLEGAL_VALUE);
     1.8 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
     1.9  
    1.10      if (identity->me || (identity->user_id && strcmp(identity->user_id, PEP_OWN_USERID) == 0)) {
    1.11          identity->me = true;
    1.12 @@ -326,7 +326,7 @@
    1.13      free_identity(stored_identity);
    1.14      free_identity(temp_id);
    1.15      
    1.16 -    return ERROR(status);
    1.17 +    return ADD_TO_LOG(status);
    1.18  }
    1.19  
    1.20  PEP_STATUS elect_ownkey(
    1.21 @@ -416,7 +416,7 @@
    1.22      
    1.23      *is_usable = !dont_use_fpr;
    1.24      
    1.25 -    return ERROR(status);
    1.26 +    return ADD_TO_LOG(status);
    1.27  }
    1.28  
    1.29  PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags)
    1.30 @@ -434,7 +434,7 @@
    1.31      if (!(session && identity && !EMPTYSTR(identity->address) &&
    1.32              (EMPTYSTR(identity->user_id) ||
    1.33              strcmp(identity->user_id, PEP_OWN_USERID) == 0)))
    1.34 -        return ERROR(PEP_ILLEGAL_VALUE);
    1.35 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
    1.36  
    1.37      identity->comm_type = PEP_ct_pEp;
    1.38      identity->me = true;
    1.39 @@ -522,7 +522,7 @@
    1.40          status = elect_ownkey(session, identity);
    1.41          assert(status == PEP_STATUS_OK);
    1.42          if (status != PEP_STATUS_OK) {
    1.43 -            return ERROR(status);
    1.44 +            return ADD_TO_LOG(status);
    1.45          }
    1.46  
    1.47          bool has_private = false;
    1.48 @@ -554,7 +554,7 @@
    1.49  
    1.50          if (status != PEP_STATUS_OK) 
    1.51          {
    1.52 -            return ERROR(status);
    1.53 +            return ADD_TO_LOG(status);
    1.54          }
    1.55      }
    1.56     
    1.57 @@ -563,7 +563,7 @@
    1.58      if (EMPTYSTR(identity->fpr) || revoked)
    1.59      {
    1.60          if(!do_keygen){
    1.61 -            return ERROR(PEP_GET_KEY_FAILED);
    1.62 +            return ADD_TO_LOG(PEP_GET_KEY_FAILED);
    1.63          }
    1.64  
    1.65          if(revoked)
    1.66 @@ -581,7 +581,7 @@
    1.67              DEBUG_LOG("generating key pair failed", "debug", buf);
    1.68              if(revoked && r_fpr)
    1.69                  free(r_fpr);
    1.70 -            return ERROR(status);
    1.71 +            return ADD_TO_LOG(status);
    1.72          }
    1.73  
    1.74          new_key_generated = true;
    1.75 @@ -592,7 +592,7 @@
    1.76                                   identity->fpr, time(NULL));
    1.77              free(r_fpr);
    1.78              if (status != PEP_STATUS_OK) {
    1.79 -                return ERROR(status);
    1.80 +                return ADD_TO_LOG(status);
    1.81              }
    1.82          }
    1.83      }
    1.84 @@ -605,7 +605,7 @@
    1.85  
    1.86          assert(status == PEP_STATUS_OK);
    1.87          if (status != PEP_STATUS_OK) {
    1.88 -            return ERROR(status);
    1.89 +            return ADD_TO_LOG(status);
    1.90          }
    1.91  
    1.92          if (status == PEP_STATUS_OK && expired) {
    1.93 @@ -633,12 +633,12 @@
    1.94          }
    1.95      }
    1.96  
    1.97 -    return ERROR(PEP_STATUS_OK);
    1.98 +    return ADD_TO_LOG(PEP_STATUS_OK);
    1.99  }
   1.100  
   1.101  DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
   1.102  {
   1.103 -    return ERROR(_myself(session, identity, true, false));
   1.104 +    return ADD_TO_LOG(_myself(session, identity, true, false));
   1.105  }
   1.106  
   1.107  DYNAMIC_API PEP_STATUS register_examine_function(
     2.1 --- a/src/message_api.c	Tue Jun 13 13:00:37 2017 +0200
     2.2 +++ b/src/message_api.c	Wed Jun 28 11:21:52 2017 +0200
     2.3 @@ -826,69 +826,61 @@
     2.4  
     2.5  
     2.6      PEP_comm_type bare_comm_type = PEP_ct_unknown;
     2.7 +    PEP_comm_type resulting_comm_type = PEP_ct_unknown;
     2.8      PEP_STATUS status = get_key_rating(session, fpr, &bare_comm_type);
     2.9      if (status != PEP_STATUS_OK)
    2.10          return PEP_rating_undefined;
    2.11  
    2.12 -    PEP_comm_type least_trust_type = PEP_ct_unknown;
    2.13 -    least_trust(session, fpr, &least_trust_type);
    2.14 -
    2.15 -    if (least_trust_type == PEP_ct_unknown) {
    2.16 -        return _rating(bare_comm_type, PEP_rating_undefined);
    2.17 +    PEP_comm_type least_comm_type = PEP_ct_unknown;
    2.18 +    least_trust(session, fpr, &least_comm_type);
    2.19 +
    2.20 +    if (least_comm_type == PEP_ct_unknown) {
    2.21 +        resulting_comm_type = bare_comm_type;
    2.22 +    } else if (least_comm_type < PEP_ct_strong_but_unconfirmed ||
    2.23 +               bare_comm_type < PEP_ct_strong_but_unconfirmed) {
    2.24 +        // take minimum if anything bad
    2.25 +        resulting_comm_type = least_comm_type < bare_comm_type ? 
    2.26 +                              least_comm_type : 
    2.27 +                              bare_comm_type;
    2.28      } else {
    2.29 -        return _rating(least_trust_type, PEP_rating_undefined);
    2.30 +        resulting_comm_type = least_comm_type;
    2.31      }
    2.32 +    return _rating(resulting_comm_type, PEP_rating_undefined);
    2.33  }
    2.34  
    2.35  static PEP_rating worst_rating(PEP_rating rating1, PEP_rating rating2) {
    2.36      return ((rating1 < rating2) ? rating1 : rating2);
    2.37  }
    2.38  
    2.39 -static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist)
    2.40 +static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist, char* sender_fpr, PEP_rating sender_rating)
    2.41  {
    2.42 -    PEP_rating rating = PEP_rating_undefined;
    2.43 +    PEP_rating rating = sender_rating;
    2.44  
    2.45      assert(keylist && keylist->value);
    2.46      if (keylist == NULL || keylist->value == NULL)
    2.47          return PEP_rating_undefined;
    2.48  
    2.49      stringlist_t *_kl;
    2.50 -    bool first = true;
    2.51      for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
    2.52 -        PEP_comm_type ct;
    2.53 -        PEP_STATUS status;
    2.54 +
    2.55 +        // Ignore own fpr
    2.56 +        if(_same_fpr(sender_fpr, strlen(sender_fpr), _kl->value, strlen(_kl->value)))
    2.57 +            continue;
    2.58  
    2.59          PEP_rating _rating_ = key_rating(session, _kl->value);
    2.60           
    2.61          if (_rating_ <= PEP_rating_mistrust)
    2.62              return _rating_;
    2.63              
    2.64 -        if (first) {
    2.65 -            rating = _rating_;
    2.66 -            first = false;
    2.67 -        }
    2.68 -        else if (rating == PEP_rating_undefined)
    2.69 -            rating = worst_rating(rating, _rating_);
    2.70 -
    2.71 -        if (_rating_ >= PEP_rating_reliable) {
    2.72 -            status = least_trust(session, _kl->value, &ct);
    2.73 -            if (status != PEP_STATUS_OK)
    2.74 -                return PEP_rating_undefined;
    2.75 -            if (ct == PEP_ct_unknown){
    2.76 -                /* per edouard, we reduce reliable+ ratings to reliable because
    2.77 -                   ct unknown */
    2.78 -                if (rating >= PEP_rating_reliable){
    2.79 -                    rating = PEP_rating_reliable; 
    2.80 -                }
    2.81 -            }
    2.82 -            else{
    2.83 -                rating = worst_rating(rating, _rating(ct, rating));
    2.84 -            }
    2.85 -        }
    2.86 -        else if (_rating_ == PEP_rating_unencrypted) {
    2.87 +        if (_rating_ == PEP_rating_unencrypted)
    2.88 +        {
    2.89              if (rating > PEP_rating_unencrypted_for_some)
    2.90                  rating = worst_rating(rating, PEP_rating_unencrypted_for_some);
    2.91          }
    2.92 +        else
    2.93 +        {
    2.94 +            rating = worst_rating(rating, _rating_);
    2.95 +        }
    2.96      }
    2.97  
    2.98      return rating;
    2.99 @@ -995,8 +987,13 @@
   2.100          if (bl && bl->value && bl->size && bl->size < MAX_KEY_SIZE
   2.101                  && is_key(bl))
   2.102          {
   2.103 -            import_key(session, bl->value, bl->size, private_idents);
   2.104 +            identity_list *local_private_idents = NULL;
   2.105 +            import_key(session, bl->value, bl->size, &local_private_idents);
   2.106              remove = true;
   2.107 +            if (private_idents && *private_idents == NULL && local_private_idents != NULL)
   2.108 +                *private_idents = local_private_idents;
   2.109 +            else
   2.110 +                free_identity_list(local_private_idents);
   2.111          }
   2.112      }
   2.113      return remove;
   2.114 @@ -1104,14 +1101,14 @@
   2.115      assert(enc_format != PEP_enc_none);
   2.116  
   2.117      if (!(session && src && dst && enc_format != PEP_enc_none))
   2.118 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.119 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.120  
   2.121      if (src->dir == PEP_dir_incoming)
   2.122 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.123 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.124  
   2.125      determine_encryption_format(src);
   2.126      if (src->enc_format != PEP_enc_none)
   2.127 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.128 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.129  
   2.130      *dst = NULL;
   2.131  
   2.132 @@ -1218,7 +1215,7 @@
   2.133          free_stringlist(keys);
   2.134          if (!session->passive_mode && !(flags & PEP_encrypt_flag_force_no_attached_key))
   2.135              attach_own_key(session, src);
   2.136 -        return ERROR(PEP_UNENCRYPTED);
   2.137 +        return ADD_TO_LOG(PEP_UNENCRYPTED);
   2.138      }
   2.139      else {
   2.140          msg = clone_to_empty_message(src);
   2.141 @@ -1275,7 +1272,7 @@
   2.142      }
   2.143  
   2.144      *dst = msg;
   2.145 -    return ERROR(status);
   2.146 +    return ADD_TO_LOG(status);
   2.147  
   2.148  enomem:
   2.149      status = PEP_OUT_OF_MEMORY;
   2.150 @@ -1284,7 +1281,7 @@
   2.151      free_stringlist(keys);
   2.152      free_message(msg);
   2.153  
   2.154 -    return ERROR(status);
   2.155 +    return ADD_TO_LOG(status);
   2.156  }
   2.157  
   2.158  DYNAMIC_API PEP_STATUS encrypt_message_for_self(
   2.159 @@ -1306,14 +1303,14 @@
   2.160      assert(enc_format != PEP_enc_none);
   2.161  
   2.162      if (!(session && src && dst && enc_format != PEP_enc_none))
   2.163 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.164 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.165  
   2.166      if (src->dir == PEP_dir_incoming)
   2.167 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.168 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.169  
   2.170      determine_encryption_format(src);
   2.171      if (src->enc_format != PEP_enc_none)
   2.172 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.173 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.174  
   2.175      status = myself(session, target_id);
   2.176      if (status != PEP_STATUS_OK)
   2.177 @@ -1394,7 +1391,7 @@
   2.178      free_stringlist(keys);
   2.179      free_message(msg);
   2.180  
   2.181 -    return ERROR(status);
   2.182 +    return ADD_TO_LOG(status);
   2.183  }
   2.184  
   2.185  static bool is_a_pEpmessage(const message *msg)
   2.186 @@ -1604,38 +1601,32 @@
   2.187      PEP_STATUS status = PEP_STATUS_OK;
   2.188  
   2.189      if (*rating > PEP_rating_mistrust) {
   2.190 -        PEP_rating kl_rating = PEP_rating_undefined;
   2.191 -
   2.192 -        if (recipients)
   2.193 -            kl_rating = keylist_rating(session, recipients);
   2.194 -
   2.195 -        if (kl_rating <= PEP_rating_mistrust) {
   2.196 -            *rating = kl_rating;
   2.197 +
   2.198 +        if (recipients == NULL) {
   2.199 +            *rating = PEP_rating_undefined;
   2.200 +            return PEP_STATUS_OK;
   2.201          }
   2.202 -        else if (*rating >= PEP_rating_reliable &&
   2.203 -                 kl_rating < PEP_rating_reliable) {
   2.204 +
   2.205 +        char *fpr = recipients->value;
   2.206 +
   2.207 +        if (!(sender && sender->user_id && sender->user_id[0] && fpr && fpr[0])) {
   2.208              *rating = PEP_rating_unreliable;
   2.209          }
   2.210 -        else if (*rating >= PEP_rating_reliable &&
   2.211 -                 kl_rating >= PEP_rating_reliable) {
   2.212 -            if (!(sender && sender->user_id && sender->user_id[0])) {
   2.213 -                *rating = PEP_rating_unreliable;
   2.214 +        else {
   2.215 +            pEp_identity *_sender = new_identity(sender->address, fpr,
   2.216 +                                               sender->user_id, sender->username);
   2.217 +            if (_sender == NULL)
   2.218 +                return PEP_OUT_OF_MEMORY;
   2.219 +
   2.220 +            status = get_trust(session, _sender);
   2.221 +            if (_sender->comm_type != PEP_ct_unknown) {
   2.222 +                *rating = keylist_rating(session, recipients, 
   2.223 +                            fpr, _rating(_sender->comm_type, 
   2.224 +                                          PEP_rating_undefined));
   2.225              }
   2.226 -            else {
   2.227 -                char *fpr = recipients->value;
   2.228 -                pEp_identity *_sender = new_identity(sender->address, fpr,
   2.229 -                                                   sender->user_id, sender->username);
   2.230 -                if (_sender == NULL)
   2.231 -                    return PEP_OUT_OF_MEMORY;
   2.232 -                status = get_trust(session, _sender);
   2.233 -                if (_sender->comm_type != PEP_ct_unknown) {
   2.234 -                    *rating = worst_rating(_rating(_sender->comm_type, PEP_rating_undefined),
   2.235 -                              kl_rating);
   2.236 -                }
   2.237 -                free_identity(_sender);
   2.238 -                if (status == PEP_CANNOT_FIND_IDENTITY)
   2.239 -                   status = PEP_STATUS_OK;
   2.240 -            }
   2.241 +            free_identity(_sender);
   2.242 +            if (status == PEP_CANNOT_FIND_IDENTITY)
   2.243 +               status = PEP_STATUS_OK;
   2.244          }
   2.245      }
   2.246      return status;
   2.247 @@ -1669,7 +1660,7 @@
   2.248      assert(flags);
   2.249  
   2.250      if (!(session && src && dst && keylist && rating && flags))
   2.251 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.252 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.253  
   2.254      *flags = 0;
   2.255  
   2.256 @@ -1680,7 +1671,7 @@
   2.257      // we would need to check signature
   2.258      status = _update_identity_for_incoming_message(session, src);
   2.259      if(status != PEP_STATUS_OK)
   2.260 -        return ERROR(status);
   2.261 +        return ADD_TO_LOG(status);
   2.262  
   2.263      // Get detached signature, if any
   2.264      bloblist_t* detached_sig = NULL;
   2.265 @@ -1714,7 +1705,7 @@
   2.266                                  PEP_decrypt_flag_consume;
   2.267                  }
   2.268                  else if (status != PEP_STATUS_OK) {
   2.269 -                    return ERROR(status);
   2.270 +                    return ADD_TO_LOG(status);
   2.271                  }
   2.272              }
   2.273              
   2.274 @@ -1746,7 +1737,7 @@
   2.275                  }
   2.276              }
   2.277              
   2.278 -            return ERROR(PEP_UNENCRYPTED);
   2.279 +            return ADD_TO_LOG(PEP_UNENCRYPTED);
   2.280  
   2.281          case PEP_enc_PGP_MIME:
   2.282              ctext = src->attachments->next->value;
   2.283 @@ -2088,7 +2079,6 @@
   2.284                              PEP_decrypt_flag_ignore :
   2.285                              PEP_decrypt_flag_consume;
   2.286  
   2.287 -                status = decrypt_status;
   2.288              }
   2.289              else if (status != PEP_STATUS_OK){
   2.290                  goto pep_error;
   2.291 @@ -2107,7 +2097,10 @@
   2.292      *dst = msg;
   2.293      *keylist = _keylist;
   2.294  
   2.295 -    return PEP_STATUS_OK;
   2.296 +    if(decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
   2.297 +        return ADD_TO_LOG(PEP_STATUS_OK);
   2.298 +    else
   2.299 +        return ADD_TO_LOG(decrypt_status);
   2.300  
   2.301  enomem:
   2.302      status = PEP_OUT_OF_MEMORY;
   2.303 @@ -2117,7 +2110,7 @@
   2.304      free_message(msg);
   2.305      free_stringlist(_keylist);
   2.306  
   2.307 -    return ERROR(status);
   2.308 +    return ADD_TO_LOG(status);
   2.309  }
   2.310  
   2.311  DYNAMIC_API PEP_STATUS decrypt_message(
   2.312 @@ -2166,7 +2159,7 @@
   2.313  
   2.314      free_identity_list(private_il);
   2.315  
   2.316 -    return ERROR(status);
   2.317 +    return ADD_TO_LOG(status);
   2.318  }
   2.319  
   2.320  static void _max_comm_type_from_identity_list(
   2.321 @@ -2207,10 +2200,10 @@
   2.322      assert(rating);
   2.323  
   2.324      if (!(session && msg && rating))
   2.325 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.326 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.327  
   2.328      if (msg->dir != PEP_dir_outgoing)
   2.329 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.330 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.331  
   2.332      *rating = PEP_rating_undefined;
   2.333  
   2.334 @@ -2297,6 +2290,74 @@
   2.335      return PEP_color_no_color;
   2.336  }
   2.337  
   2.338 +/* [0-9]: 0x30 - 0x39; [A-F] = 0x41 - 0x46; [a-f] = 0x61 - 0x66 */
   2.339 +static short asciihex_to_num(char a) {
   2.340 +    short conv_num = -1;
   2.341 +    if (a >= 0x30 && a <= 0x39)
   2.342 +        conv_num = a - 0x30;
   2.343 +    else {
   2.344 +        // convert case, subtract offset, get number
   2.345 +        conv_num = ((a | 0x20) - 0x61) + 10;
   2.346 +        if (conv_num < 0xa || conv_num > 0xf)
   2.347 +            conv_num = -1;
   2.348 +    }
   2.349 +    return conv_num;
   2.350 +}
   2.351 +
   2.352 +static char num_to_asciihex(short h) {
   2.353 +    if (h < 0 || h > 16)
   2.354 +        return '\0';
   2.355 +    if (h < 10)
   2.356 +        return (char)(h + 0x30);
   2.357 +    return (char)((h - 10) + 0x41); // for readability
   2.358 +}
   2.359 +
   2.360 +static char xor_hex_chars(char a, char b) {
   2.361 +    short a_num = asciihex_to_num(a);
   2.362 +    short b_num = asciihex_to_num(b);
   2.363 +    if (a_num < 0 || b_num < 0)
   2.364 +        return '\0';
   2.365 +    short xor_num = a_num^b_num;
   2.366 +    return num_to_asciihex(xor_num);
   2.367 +}
   2.368 +
   2.369 +static char* skip_separators(char* current, char* begin) {
   2.370 +    while (current >= begin) {
   2.371 +        /* .:,;-_ ' ' - [2c-2e] [3a-3b] [20] [5f] */
   2.372 +        char check_char = *current;
   2.373 +        switch (check_char) {
   2.374 +            case '.':
   2.375 +            case ':':
   2.376 +            case ',':
   2.377 +            case ';':
   2.378 +            case '-':
   2.379 +            case '_':
   2.380 +            case ' ':
   2.381 +                current--;
   2.382 +                continue;
   2.383 +            default:
   2.384 +                break;
   2.385 +        }
   2.386 +        break;
   2.387 +    }
   2.388 +    return current;
   2.389 +}
   2.390 +
   2.391 +PEP_STATUS check_for_zero_fpr(char* fpr) {
   2.392 +    PEP_STATUS status = PEP_TRUSTWORDS_DUPLICATE_FPR;
   2.393 +    
   2.394 +    while (*fpr) {
   2.395 +        if (*fpr != '0') {
   2.396 +            status = PEP_STATUS_OK;
   2.397 +            break;
   2.398 +        }
   2.399 +        fpr++;    
   2.400 +    }
   2.401 +    
   2.402 +    return status;
   2.403 +    
   2.404 +}
   2.405 +
   2.406  DYNAMIC_API PEP_STATUS get_trustwords(
   2.407      PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
   2.408      const char* lang, char **words, size_t *wsize, bool full
   2.409 @@ -2310,96 +2371,114 @@
   2.410      assert(words);
   2.411      assert(wsize);
   2.412  
   2.413 +    int SHORT_NUM_TWORDS = 5; 
   2.414 +    
   2.415 +    PEP_STATUS status = PEP_STATUS_OK;
   2.416 +    
   2.417      if (!(session && id1 && id2 && words && wsize) ||
   2.418          !(id1->fpr) || (!id2->fpr))
   2.419          return PEP_ILLEGAL_VALUE;
   2.420  
   2.421 -    const char *source1 = id1->fpr;
   2.422 -    const char *source2 = id2->fpr;
   2.423 -
   2.424 -    *words = NULL;
   2.425 +    char *source1 = id1->fpr;
   2.426 +    char *source2 = id2->fpr;
   2.427 +
   2.428 +    int source1_len = strlen(source1);
   2.429 +    int source2_len = strlen(source2);
   2.430 +    int max_len;
   2.431 +        
   2.432 +    *words = NULL;    
   2.433      *wsize = 0;
   2.434  
   2.435 -    const size_t SHORT_NUM_TWORDS = 5;
   2.436 -
   2.437 -    // N.B. THIS will have to be changed once we start checking trustword entropy.
   2.438 -    // For now, full is ALL, and otherwise it's 5-per-id.
   2.439 -    size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
   2.440 -
   2.441 -    char* first_set = NULL;
   2.442 -    char* second_set = NULL;
   2.443 -    size_t first_wsize = 0;
   2.444 -    size_t second_wsize = 0;
   2.445 -
   2.446 -    int fpr_comparison = -255;
   2.447 -    PEP_STATUS status = _compare_fprs(source1, strlen(source1), source2, strlen(source2), &fpr_comparison);
   2.448 -    if (status != PEP_STATUS_OK)
   2.449 -        return status;
   2.450 -
   2.451 -    char* _retstr = NULL;
   2.452 -
   2.453 -    switch (fpr_comparison) {
   2.454 -        case 1: // source1 > source2
   2.455 -            status = trustwords(session, source2, lang, &first_set, &first_wsize, max_words_per_id);
   2.456 -            if (status != PEP_STATUS_OK)
   2.457 -                goto error_release;
   2.458 -            status = trustwords(session, source1, lang, &second_set, &second_wsize, max_words_per_id);
   2.459 -            if (status != PEP_STATUS_OK)
   2.460 -                goto error_release;
   2.461 +    max_len = (source1_len > source2_len ? source1_len : source2_len);
   2.462 +    
   2.463 +    char* XORed_fpr = (char*)(calloc(1,max_len + 1));
   2.464 +    *(XORed_fpr + max_len) = '\0';
   2.465 +    char* result_curr = XORed_fpr + max_len - 1;
   2.466 +    char* source1_curr = source1 + source1_len - 1;
   2.467 +    char* source2_curr = source2 + source2_len - 1;
   2.468 +
   2.469 +    while (source1 <= source1_curr && source2 <= source2_curr) {
   2.470 +        source1_curr = skip_separators(source1_curr, source1);
   2.471 +        source2_curr = skip_separators(source2_curr, source2);
   2.472 +        
   2.473 +        if (source1_curr < source1 || source2_curr < source2)
   2.474              break;
   2.475 -        case 0:
   2.476 -        case -1: // source1 <= source2
   2.477 -            status = trustwords(session, source1, lang, &first_set, &first_wsize, max_words_per_id);
   2.478 -            if (status != PEP_STATUS_OK)
   2.479 -                goto error_release;
   2.480 -            status = trustwords(session, source2, lang, &second_set, &second_wsize, max_words_per_id);
   2.481 -            if (status != PEP_STATUS_OK)
   2.482 -                goto error_release;
   2.483 -            break;
   2.484 -        default:
   2.485 -            return ERROR(PEP_UNKNOWN_ERROR); // shouldn't be possible
   2.486 -    }
   2.487 -
   2.488 -    size_t _wsize = first_wsize + second_wsize;
   2.489 -
   2.490 -    bool needs_space = (first_set[first_wsize - 1] != ' ');
   2.491 -
   2.492 -    if (needs_space)
   2.493 -        _wsize++;
   2.494 -
   2.495 -    _retstr = calloc(1, _wsize + 1);
   2.496 -
   2.497 -    size_t len = strlcpy(_retstr, first_set, _wsize);
   2.498 -    if (len >= _wsize) {
   2.499 -        status = PEP_UNKNOWN_ERROR;
   2.500 -        goto error_release;
   2.501 -    }
   2.502 -    if (needs_space) {
   2.503 -        strlcat(_retstr, " ", _wsize);
   2.504 -        if (len >= _wsize) {
   2.505 -            status = PEP_UNKNOWN_ERROR;
   2.506 +            
   2.507 +        char xor_hex = xor_hex_chars(*source1_curr, *source2_curr);
   2.508 +        if (xor_hex == '\0') {
   2.509 +            status = PEP_ILLEGAL_VALUE;
   2.510              goto error_release;
   2.511          }
   2.512 +        
   2.513 +        *result_curr = xor_hex;
   2.514 +        result_curr--; source1_curr--; source2_curr--;
   2.515      }
   2.516 -    strlcat(_retstr, second_set, _wsize);
   2.517 -    if (len >= _wsize){
   2.518 -        status = PEP_UNKNOWN_ERROR;
   2.519 +
   2.520 +    char* remainder_start = NULL;
   2.521 +    char* remainder_curr = NULL;
   2.522 +    
   2.523 +    if (source1 <= source1_curr) {
   2.524 +        remainder_start = source1;
   2.525 +        remainder_curr = source1_curr;
   2.526 +    }
   2.527 +    else if (source2 <= source2_curr) {
   2.528 +        remainder_start = source2;
   2.529 +        remainder_curr = source2_curr;
   2.530 +    }
   2.531 +    if (remainder_curr) {
   2.532 +        while (remainder_start <= remainder_curr) {
   2.533 +            remainder_curr = skip_separators(remainder_curr, remainder_start);
   2.534 +            
   2.535 +            if (remainder_curr < remainder_start)
   2.536 +                break;
   2.537 +            
   2.538 +            char the_char = *remainder_curr;
   2.539 +            
   2.540 +            if (asciihex_to_num(the_char) < 0) {
   2.541 +                status = PEP_ILLEGAL_VALUE;
   2.542 +                goto error_release;
   2.543 +            }
   2.544 +            
   2.545 +            *result_curr = the_char;                
   2.546 +            result_curr--;
   2.547 +            remainder_curr--;
   2.548 +        }
   2.549 +    }
   2.550 +    
   2.551 +    result_curr++;
   2.552 +
   2.553 +    if (result_curr > XORed_fpr) {
   2.554 +        char* tempstr = strdup(result_curr);
   2.555 +        free(XORed_fpr);
   2.556 +        XORed_fpr = tempstr;
   2.557 +    }
   2.558 +    
   2.559 +    status = check_for_zero_fpr(XORed_fpr);
   2.560 +    
   2.561 +    if (status != PEP_STATUS_OK)
   2.562          goto error_release;
   2.563 -    }
   2.564 -
   2.565 -    *words = _retstr;
   2.566 -    *wsize = _wsize;
   2.567 +    
   2.568 +    size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
   2.569 +
   2.570 +    char* the_words = NULL;
   2.571 +    size_t the_size = 0;
   2.572 +
   2.573 +    status = trustwords(session, XORed_fpr, lang, &the_words, &the_size, max_words_per_id);
   2.574 +    if (status != PEP_STATUS_OK)
   2.575 +        goto error_release;
   2.576 +
   2.577 +    *words = the_words;
   2.578 +    *wsize = the_size;
   2.579 +    
   2.580      status = PEP_STATUS_OK;
   2.581  
   2.582      goto the_end;
   2.583  
   2.584      error_release:
   2.585 -    free(_retstr);
   2.586 -
   2.587 +        free (XORed_fpr);
   2.588 +        
   2.589      the_end:
   2.590 -    free(first_set);
   2.591 -    free(second_set);
   2.592 -    return ERROR(status);
   2.593 +    return ADD_TO_LOG(status);
   2.594  }
   2.595  
   2.596  DYNAMIC_API PEP_STATUS get_message_trustwords(
   2.597 @@ -2485,7 +2564,7 @@
   2.598  
   2.599      if (status != PEP_STATUS_OK) {
   2.600          free_identity(partner);
   2.601 -        return ERROR(status);
   2.602 +        return ADD_TO_LOG(status);
   2.603      }
   2.604     
   2.605      // Find own identity corresponding to given account address.
   2.606 @@ -2498,7 +2577,7 @@
   2.607  
   2.608      if (status != PEP_STATUS_OK) {
   2.609          free_identity(stored_identity);
   2.610 -        return ERROR(status);
   2.611 +        return ADD_TO_LOG(status);
   2.612      }
   2.613  
   2.614      // get the trustwords
   2.615 @@ -2507,7 +2586,7 @@
   2.616                              partner, received_by, 
   2.617                              lang, words, &wsize, full);
   2.618  
   2.619 -    return ERROR(status);
   2.620 +    return ADD_TO_LOG(status);
   2.621  }
   2.622  
   2.623  DYNAMIC_API PEP_STATUS MIME_decrypt_message(
   2.624 @@ -2558,14 +2637,14 @@
   2.625      {
   2.626          free(tmp_msg);
   2.627          free(dec_msg);
   2.628 -        return ERROR(decrypt_status);
   2.629 +        return ADD_TO_LOG(decrypt_status);
   2.630      }
   2.631      
   2.632  pep_error:
   2.633      free_message(tmp_msg);
   2.634      free_message(dec_msg);
   2.635  
   2.636 -    return ERROR(status);
   2.637 +    return ADD_TO_LOG(status);
   2.638  }
   2.639  
   2.640  
   2.641 @@ -2610,7 +2689,7 @@
   2.642      free_message(tmp_msg);
   2.643      free_message(enc_msg);
   2.644  
   2.645 -    return ERROR(status);
   2.646 +    return ADD_TO_LOG(status);
   2.647  
   2.648  }
   2.649  
   2.650 @@ -2654,7 +2733,7 @@
   2.651      free_message(tmp_msg);
   2.652      free_message(enc_msg);
   2.653  
   2.654 -    return ERROR(status);
   2.655 +    return ADD_TO_LOG(status);
   2.656  }
   2.657  
   2.658  static PEP_rating string_to_rating(const char * rating)
   2.659 @@ -2747,7 +2826,7 @@
   2.660      assert(rating);
   2.661  
   2.662      if (!(session && msg && rating))
   2.663 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.664 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.665  
   2.666      *rating = PEP_rating_undefined;
   2.667  
   2.668 @@ -2758,7 +2837,7 @@
   2.669                  goto got_rating;
   2.670              }
   2.671          }
   2.672 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.673 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.674      }
   2.675  
   2.676  got_rating:
   2.677 @@ -2775,7 +2854,7 @@
   2.678                  goto got_keylist;
   2.679              }
   2.680          }
   2.681 -        return ERROR(PEP_ILLEGAL_VALUE);
   2.682 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   2.683      }
   2.684  got_keylist:
   2.685  
   2.686 @@ -2794,5 +2873,5 @@
   2.687      if (must_free_keylist)
   2.688          free_stringlist(_keylist);
   2.689  
   2.690 -    return ERROR(status);
   2.691 +    return ADD_TO_LOG(status);
   2.692  }
     3.1 --- a/src/message_api.h	Tue Jun 13 13:00:37 2017 +0200
     3.2 +++ b/src/message_api.h	Wed Jun 28 11:21:52 2017 +0200
     3.3 @@ -18,8 +18,11 @@
     3.4          const message *msg,
     3.5          identity_list **private_idents
     3.6      );
     3.7 +
     3.8  void attach_own_key(PEP_SESSION session, message *msg);
     3.9 +
    3.10  PEP_cryptotech determine_encryption_format(message *msg);
    3.11 +
    3.12  void add_opt_field(message *msg, const char *name, const char *value);
    3.13  
    3.14  typedef enum _PEP_encrypt_flags {
    3.15 @@ -35,6 +38,7 @@
    3.16  
    3.17  typedef unsigned int PEP_encrypt_flags_t;
    3.18  
    3.19 +
    3.20  // encrypt_message() - encrypt message in memory
    3.21  //
    3.22  //  parameters:
    3.23 @@ -47,16 +51,18 @@
    3.24  //
    3.25  //  return value:
    3.26  //      PEP_STATUS_OK                   on success
    3.27 -//		PEP_KEY_NOT_FOUND	            at least one of the receipient keys
    3.28 -//		                                could not be found
    3.29 -//		PEP_KEY_HAS_AMBIG_NAME          at least one of the receipient keys has
    3.30 -//		                                an ambiguous name
    3.31 -//		PEP_GET_KEY_FAILED		        cannot retrieve key
    3.32 +//      PEP_KEY_NOT_FOUND               at least one of the receipient keys
    3.33 +//                                      could not be found
    3.34 +//      PEP_KEY_HAS_AMBIG_NAME          at least one of the receipient keys has
    3.35 +//                                      an ambiguous name
    3.36 +//      PEP_GET_KEY_FAILED              cannot retrieve key
    3.37 +//      PEP_UNENCRYPTED                 no recipients with usable key, 
    3.38 +//                                      message is left unencrypted,
    3.39 +//                                      and key is attached to it
    3.40  //
    3.41 -//	caveat:
    3.42 -//	    the ownershop of src remains with the caller
    3.43 -//	    the ownership of dst goes to the caller
    3.44 -
    3.45 +//  caveat:
    3.46 +//      the ownershop of src remains with the caller
    3.47 +//      the ownership of dst goes to the caller
    3.48  DYNAMIC_API PEP_STATUS encrypt_message(
    3.49          PEP_SESSION session,
    3.50          message *src,
    3.51 @@ -66,6 +72,7 @@
    3.52          PEP_encrypt_flags_t flags
    3.53      );
    3.54  
    3.55 +
    3.56  // encrypt_message_for_self() - encrypt message in memory for user's identity only,
    3.57  //                              ignoring recipients and other identities from
    3.58  //                              the message
    3.59 @@ -78,20 +85,19 @@
    3.60  //      flags (in)          flags to set special encryption features
    3.61  //
    3.62  //  return value:       (FIXME: This may not be correct or complete)
    3.63 -//      PEP_STATUS_OK                   on success
    3.64 -//		PEP_KEY_NOT_FOUND	            at least one of the receipient keys
    3.65 -//		                                could not be found
    3.66 -//		PEP_KEY_HAS_AMBIG_NAME          at least one of the receipient keys has
    3.67 -//		                                an ambiguous name
    3.68 -//		PEP_GET_KEY_FAILED		        cannot retrieve key
    3.69 +//      PEP_STATUS_OK            on success
    3.70 +//      PEP_KEY_NOT_FOUND        at least one of the receipient keys
    3.71 +//                               could not be found
    3.72 +//      PEP_KEY_HAS_AMBIG_NAME   at least one of the receipient keys has
    3.73 +//                               an ambiguous name
    3.74 +//      PEP_GET_KEY_FAILED       cannot retrieve key
    3.75  //
    3.76 -//	caveat:
    3.77 -//	    the ownership of src remains with the caller
    3.78 +//  caveat:
    3.79 +//      the ownership of src remains with the caller
    3.80  //      the ownership of target_id remains w/ caller            
    3.81 -//	    the ownership of dst goes to the caller
    3.82 +//      the ownership of dst goes to the caller
    3.83  //      message is NOT encrypted for identities other than the target_id (and then,
    3.84 -//          only if the target_id refers to self!)
    3.85 -
    3.86 +//      only if the target_id refers to self!)
    3.87  DYNAMIC_API PEP_STATUS encrypt_message_for_self(
    3.88          PEP_SESSION session,
    3.89          pEp_identity* target_id,
    3.90 @@ -101,6 +107,7 @@
    3.91          PEP_encrypt_flags_t flags
    3.92      );
    3.93  
    3.94 +
    3.95  // MIME_encrypt_message() - encrypt a MIME message, with MIME output
    3.96  //
    3.97  //  parameters:
    3.98 @@ -124,7 +131,6 @@
    3.99  //  caveat:
   3.100  //      the encrypted, encoded mime text will go to the ownership of the caller; mimetext
   3.101  //      will remain in the ownership of the caller
   3.102 -
   3.103  DYNAMIC_API PEP_STATUS MIME_encrypt_message(
   3.104      PEP_SESSION session,
   3.105      const char *mimetext,
   3.106 @@ -135,12 +141,13 @@
   3.107      PEP_encrypt_flags_t flags
   3.108  );
   3.109  
   3.110 +
   3.111  // MIME_encrypt_message_for_self() - encrypt MIME message for user's identity only,
   3.112  //                              ignoring recipients and other identities from
   3.113  //                              the message, with MIME output
   3.114  //  parameters:
   3.115  //      session (in)            session handle
   3.116 -//      target_id (in)      self identity this message should be encrypted for
   3.117 +//      target_id (in)          self identity this message should be encrypted for
   3.118  //      mimetext (in)           MIME encoded text to encrypt
   3.119  //      size (in)               size of input mime text
   3.120  //      mime_ciphertext (out)   encrypted, encoded message
   3.121 @@ -159,7 +166,6 @@
   3.122  //  caveat:
   3.123  //      the encrypted, encoded mime text will go to the ownership of the caller; mimetext
   3.124  //      will remain in the ownership of the caller
   3.125 -
   3.126  DYNAMIC_API PEP_STATUS MIME_encrypt_message_for_self(
   3.127      PEP_SESSION session,
   3.128      pEp_identity* target_id,
   3.129 @@ -171,7 +177,6 @@
   3.130  );
   3.131  
   3.132  
   3.133 -
   3.134  typedef enum _PEP_rating {
   3.135      PEP_rating_undefined = 0,
   3.136      PEP_rating_cannot_decrypt,
   3.137 @@ -196,13 +201,13 @@
   3.138      PEP_color_red = -1,
   3.139  } PEP_color;
   3.140  
   3.141 +
   3.142  // color_from_rating - calculate color from rating
   3.143  //
   3.144  //  parameters:
   3.145  //      rating (in)         rating
   3.146  //
   3.147  //  return value:           color representing that rating
   3.148 -
   3.149  DYNAMIC_API PEP_color color_from_rating(PEP_rating rating);
   3.150  
   3.151  typedef enum _PEP_decrypt_flags {
   3.152 @@ -213,6 +218,7 @@
   3.153  
   3.154  typedef unsigned int PEP_decrypt_flags_t;
   3.155  
   3.156 +
   3.157  // decrypt_message() - decrypt message in memory
   3.158  //
   3.159  //  parameters:
   3.160 @@ -224,15 +230,16 @@
   3.161  //      flags (out)         flags to signal special decryption features
   3.162  //
   3.163  //  return value:
   3.164 -//      error status or PEP_STATUS_OK on success
   3.165 +//      error status 
   3.166 +//      or PEP_DECRYPTED if message decrypted but not verified
   3.167 +//      or PEP_STATUS_OK on success
   3.168  //
   3.169 -//	caveat:
   3.170 -//	    the ownership of src remains with the caller
   3.171 -//	    the ownership of dst goes to the caller
   3.172 -//	    the ownership of keylist goes to the caller
   3.173 -//	    if src is unencrypted this function returns PEP_UNENCRYPTED and sets
   3.174 -//	    dst to NULL
   3.175 -
   3.176 +// caveat:
   3.177 +//      the ownership of src remains with the caller
   3.178 +//      the ownership of dst goes to the caller
   3.179 +//      the ownership of keylist goes to the caller
   3.180 +//      if src is unencrypted this function returns PEP_UNENCRYPTED and sets
   3.181 +//      dst to NULL
   3.182  DYNAMIC_API PEP_STATUS decrypt_message(
   3.183          PEP_SESSION session,
   3.184          message *src,
   3.185 @@ -242,6 +249,7 @@
   3.186          PEP_decrypt_flags_t *flags
   3.187  );
   3.188  
   3.189 +
   3.190  // MIME_decrypt_message() - decrypt a MIME message, with MIME output
   3.191  //
   3.192  //  parameters:
   3.193 @@ -267,7 +275,6 @@
   3.194  //  caveat:
   3.195  //      the decrypted, encoded mime text will go to the ownership of the caller; mimetext
   3.196  //      will remain in the ownership of the caller
   3.197 -
   3.198  DYNAMIC_API PEP_STATUS MIME_decrypt_message(
   3.199      PEP_SESSION session,
   3.200      const char *mimetext,
   3.201 @@ -295,17 +302,17 @@
   3.202  //  return value:
   3.203  //      error status or PEP_STATUS_OK on success
   3.204  //
   3.205 -//	caveat:
   3.206 -//	    the ownership of msg remains with the caller
   3.207 -//	    the ownership of ident goes to the caller
   3.208 -//	    msg MUST be encrypted so that this function can check own signature
   3.209 -
   3.210 +//  caveat:
   3.211 +//      the ownership of msg remains with the caller
   3.212 +//      the ownership of ident goes to the caller
   3.213 +//      msg MUST be encrypted so that this function can check own signature
   3.214  DYNAMIC_API PEP_STATUS own_message_private_key_details(
   3.215          PEP_SESSION session,
   3.216          message *msg,
   3.217          pEp_identity **ident 
   3.218  );
   3.219  
   3.220 +
   3.221  // outgoing_message_rating() - get rating for an outgoing message
   3.222  //
   3.223  //  parameters:
   3.224 @@ -320,7 +327,6 @@
   3.225  //      msg->from must point to a valid pEp_identity
   3.226  //      msg->dir must be PEP_dir_outgoing
   3.227  //      the ownership of msg remains with the caller
   3.228 -
   3.229  DYNAMIC_API PEP_STATUS outgoing_message_rating(
   3.230          PEP_SESSION session,
   3.231          message *msg,
   3.232 @@ -340,7 +346,6 @@
   3.233  //
   3.234  //  caveat:
   3.235  //      the ownership of ident remains with the caller
   3.236 -
   3.237  DYNAMIC_API PEP_STATUS identity_rating(
   3.238          PEP_SESSION session,
   3.239          pEp_identity *ident,
   3.240 @@ -356,6 +361,7 @@
   3.241  //                          **path is owned by the library, do not change it!
   3.242  DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path);
   3.243  
   3.244 +
   3.245  // get_trustwords() - get full trustwords string for a *pair* of identities
   3.246  //
   3.247  //    parameters:
   3.248 @@ -381,12 +387,12 @@
   3.249  //        the word pointer goes to the ownership of the caller
   3.250  //        the caller is responsible to free() it (on Windoze use pEp_free())
   3.251  //
   3.252 -
   3.253  DYNAMIC_API PEP_STATUS get_trustwords(
   3.254      PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
   3.255      const char* lang, char **words, size_t *wsize, bool full
   3.256  );
   3.257  
   3.258 +
   3.259  // get_message_trustwords() - get full trustwords string for message sender and reciever identities 
   3.260  //
   3.261  //    parameters:
     4.1 --- a/src/pEpEngine.c	Tue Jun 13 13:00:37 2017 +0200
     4.2 +++ b/src/pEpEngine.c	Wed Jun 28 11:21:52 2017 +0200
     4.3 @@ -10,6 +10,32 @@
     4.4  
     4.5  static int init_count = -1;
     4.6  
     4.7 +// sql overloaded functions - modified from sqlite3.c
     4.8 +static void _sql_lower(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
     4.9 +    char *z1;
    4.10 +    const char *z2;
    4.11 +    int i, n;
    4.12 +    z2 = (char*)sqlite3_value_text(argv[0]);
    4.13 +    n = sqlite3_value_bytes(argv[0]);
    4.14 +    /* Verify that the call to _bytes() does not invalidate the _text() pointer */
    4.15 +    assert( z2==(char*)sqlite3_value_text(argv[0]) );
    4.16 +    if( z2 ){
    4.17 +        z1 = (char*)sqlite3_malloc(n+1);
    4.18 +        if( z1 ){
    4.19 +            for(i=0; i<n; i++){
    4.20 +                char c = z2[i];
    4.21 +                char c_mod = c | 0x20;
    4.22 +                if (c_mod < 0x61 || c_mod > 0x7a)
    4.23 +                    c_mod = c;
    4.24 +                z1[i] = c_mod;
    4.25 +            }
    4.26 +            z1[n] = '\0';
    4.27 +            sqlite3_result_text(ctx, z1, n, sqlite3_free);
    4.28 +        }
    4.29 +    }
    4.30 +}
    4.31 +
    4.32 +
    4.33  // sql manipulation statements
    4.34  static const char *sql_log = 
    4.35      "insert into log (title, entity, description, comment)"
    4.36 @@ -19,6 +45,7 @@
    4.37      "select id, word from wordlist where lang = lower(?1) "
    4.38      "and id = ?2 ;";
    4.39  
    4.40 +
    4.41  static const char *sql_get_identity =  
    4.42      "select fpr, username, comm_type, lang,"
    4.43      "   identity.flags | pgp_keypair.flags"
    4.44 @@ -26,8 +53,13 @@
    4.45      "   join person on id = identity.user_id"
    4.46      "   join pgp_keypair on fpr = identity.main_key_id"
    4.47      "   join trust on id = trust.user_id"
    4.48 -    "       and pgp_keypair_fpr = identity.main_key_id"
    4.49 -    "   where address = ?1 and identity.user_id = ?2;";
    4.50 +    "       and pgp_keypair_fpr = identity.main_key_id"    
    4.51 +    "   where (case when (address = ?1) then (1)"
    4.52 +    "               when (lower(address) = lower(?1)) then (1)"
    4.53 +    "               when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)"
    4.54 +    "               else 0"
    4.55 +    "          end) = 1"
    4.56 +    "   and identity.user_id = ?2;";
    4.57  
    4.58  static const char *sql_replace_identities_fpr =  
    4.59      "update identity"
    4.60 @@ -414,6 +446,21 @@
    4.61              &version,
    4.62              NULL
    4.63          );
    4.64 +
    4.65 +        assert(int_result == SQLITE_OK);
    4.66 +        
    4.67 +        void (*xFunc_lower)(sqlite3_context*,int,sqlite3_value**) = &_sql_lower;
    4.68 +        
    4.69 +        int_result = sqlite3_create_function_v2(
    4.70 +            _session->db,
    4.71 +            "lower",
    4.72 +            1,
    4.73 +            SQLITE_UTF8 | SQLITE_DETERMINISTIC,
    4.74 +            NULL,
    4.75 +            xFunc_lower,
    4.76 +            NULL,
    4.77 +            NULL,
    4.78 +            NULL);
    4.79          assert(int_result == SQLITE_OK);
    4.80  
    4.81          if(version != 0) { 
    4.82 @@ -886,7 +933,7 @@
    4.83      } while (result == SQLITE_BUSY);
    4.84      sqlite3_reset(session->log);
    4.85  
    4.86 -    return ERROR(status);
    4.87 +    return ADD_TO_LOG(status);
    4.88  }
    4.89  
    4.90  DYNAMIC_API PEP_STATUS log_service(
    4.91 @@ -1988,7 +2035,7 @@
    4.92      status = PEP_OUT_OF_MEMORY;
    4.93  
    4.94  the_end:
    4.95 -    return ERROR(status);
    4.96 +    return ADD_TO_LOG(status);
    4.97  }
    4.98  
    4.99  DYNAMIC_API PEP_STATUS get_languagelist(
     5.1 --- a/src/pEpEngine.h	Tue Jun 13 13:00:37 2017 +0200
     5.2 +++ b/src/pEpEngine.h	Wed Jun 28 11:21:52 2017 +0200
     5.3 @@ -68,6 +68,7 @@
     5.4  
     5.5      PEP_TRUSTWORD_NOT_FOUND                         = 0x0501,
     5.6      PEP_TRUSTWORDS_FPR_WRONG_LENGTH                 = 0x0502,
     5.7 +    PEP_TRUSTWORDS_DUPLICATE_FPR                    = 0x0503,
     5.8  
     5.9      PEP_CANNOT_CREATE_KEY                           = 0x0601,
    5.10      PEP_CANNOT_SEND_KEY                             = 0x0602,
     6.1 --- a/src/pEp_internal.h	Tue Jun 13 13:00:37 2017 +0200
     6.2 +++ b/src/pEp_internal.h	Wed Jun 28 11:21:52 2017 +0200
     6.3 @@ -316,9 +316,9 @@
     6.4  
     6.5  #ifdef DEBUG_ERRORSTACK
     6.6      PEP_STATUS session_add_error(PEP_SESSION session, const char* file, unsigned line, PEP_STATUS status);
     6.7 -    #define ERROR(status)   session_add_error(session, __FILE__, __LINE__, (status))
     6.8 -    #define GOTO(label)     do{ (void)session_add_error(session, __FILE__, __LINE__, status); goto label; }while(0)
     6.9 +    #define ADD_TO_LOG(status)   session_add_error(session, __FILE__, __LINE__, (status))
    6.10 +    #define GOTO(label)          do{ (void)session_add_error(session, __FILE__, __LINE__, status); goto label; }while(0)
    6.11  #else
    6.12 -    #define ERROR(status)   (status)
    6.13 -    #define GOTO(label)     goto label
    6.14 +    #define ADD_TO_LOG(status)   (status)
    6.15 +    #define GOTO(label)          goto label
    6.16  #endif
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/test/case_and_dot_address_test.cc	Wed Jun 28 11:21:52 2017 +0200
     7.3 @@ -0,0 +1,80 @@
     7.4 +// This file is under GNU General Public License 3.0
     7.5 +// see LICENSE.txt
     7.6 +
     7.7 +#include <stdlib.h>
     7.8 +#include <string.h>
     7.9 +#include <time.h>
    7.10 +#include "platform.h"
    7.11 +#include <iostream>
    7.12 +#include <fstream>
    7.13 +#include <assert.h>
    7.14 +#include "mime.h"
    7.15 +#include "message_api.h"
    7.16 +#include "test_util.h"
    7.17 +
    7.18 +using namespace std;
    7.19 +
    7.20 +int main() {
    7.21 +    cout << "\n*** case_and_dot_address_test.cc ***\n\n";
    7.22 +
    7.23 +    PEP_SESSION session;
    7.24 +    
    7.25 +    cout << "calling init()\n";
    7.26 +    PEP_STATUS status = init(&session);   
    7.27 +    assert(status == PEP_STATUS_OK);
    7.28 +    assert(session);
    7.29 +    cout << "init() completed.\n";
    7.30 +    
    7.31 +    
    7.32 +    const string alice_pub_key = slurp("test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc");
    7.33 +    const string alice_priv_key = slurp("test_keys/priv/pep-test-alice-0x6FF00E97_priv.asc");
    7.34 +
    7.35 +    const char* alice_email_case = "pEp.teST.AlICe@pEP-pRoJeCt.ORG";
    7.36 +    const char* alice_email_dot = "pe.p.te.st.a.l.i.ce@pep-project.org";
    7.37 +    const char* alice_email_dotless = "peptestalice@pep-project.org";
    7.38 +    const char* alice_email_case_and_dot = "PE.p.teS.t.ALICE@pep-project.OrG";
    7.39 +
    7.40 +    PEP_STATUS statuspub = import_key(session, alice_pub_key.c_str(), alice_pub_key.length(), NULL);
    7.41 +    PEP_STATUS statuspriv = import_key(session, alice_priv_key.c_str(), alice_priv_key.length(), NULL);
    7.42 +    assert(statuspub == PEP_STATUS_OK);
    7.43 +    assert(statuspriv == PEP_STATUS_OK);
    7.44 +
    7.45 +    pEp_identity * alice_id = new_identity("pep.test.alice@pep-project.org", NULL, PEP_OWN_USERID, "Alice Test");
    7.46 +    status = update_identity(session, alice_id);
    7.47 +    assert(alice_id->fpr);
    7.48 +    assert(strcmp(alice_id->fpr, "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97") == 0);
    7.49 +    free_identity(alice_id);
    7.50 +    alice_id = NULL;
    7.51 +
    7.52 +    alice_id = new_identity(alice_email_case, NULL, PEP_OWN_USERID, "Alice Test");
    7.53 +    status = update_identity(session, alice_id);
    7.54 +    assert(alice_id->fpr);
    7.55 +    assert(strcmp(alice_id->fpr, "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97") == 0);
    7.56 +    free_identity(alice_id);
    7.57 +    alice_id = NULL;
    7.58 +
    7.59 +    alice_id = new_identity(alice_email_dot, NULL, PEP_OWN_USERID, "Alice Test");
    7.60 +    status = update_identity(session, alice_id);
    7.61 +    assert(alice_id->fpr);
    7.62 +    assert(strcmp(alice_id->fpr, "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97") == 0);
    7.63 +    free_identity(alice_id);
    7.64 +    alice_id = NULL;
    7.65 +
    7.66 +    alice_id = new_identity(alice_email_dotless, NULL, PEP_OWN_USERID, "Alice Test");
    7.67 +    status = update_identity(session, alice_id);
    7.68 +    assert(alice_id->fpr);
    7.69 +    assert(strcmp(alice_id->fpr, "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97") == 0);
    7.70 +    free_identity(alice_id);
    7.71 +    alice_id = NULL;
    7.72 +
    7.73 +    alice_id = new_identity(alice_email_case_and_dot, NULL, PEP_OWN_USERID, "Alice Test");
    7.74 +    status = update_identity(session, alice_id);
    7.75 +    assert(alice_id->fpr);
    7.76 +    assert(strcmp(alice_id->fpr, "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97") == 0);
    7.77 +    free_identity(alice_id);
    7.78 +    alice_id = NULL;
    7.79 +    
    7.80 +    release(session);
    7.81 +
    7.82 +    return 0;
    7.83 +}
     8.1 --- a/test/encrypt_for_identity_test.cc	Tue Jun 13 13:00:37 2017 +0200
     8.2 +++ b/test/encrypt_for_identity_test.cc	Wed Jun 28 11:21:52 2017 +0200
     8.3 @@ -99,7 +99,7 @@
     8.4      assert(decrypted_msg);
     8.5      assert(keylist_used);
     8.6      assert(rating);
     8.7 -    assert(status == PEP_STATUS_OK && rating == PEP_rating_unreliable);
     8.8 +    assert(status == PEP_DECRYPTED && rating == PEP_rating_unreliable);
     8.9      PEP_comm_type ct = encrypted_msg->from->comm_type;
    8.10      assert(ct == PEP_ct_pEp || ct == PEP_ct_pEp_unconfirmed || ct == PEP_ct_OpenPGP || ct == PEP_ct_OpenPGP_unconfirmed );
    8.11  
    8.12 @@ -169,7 +169,7 @@
    8.13      assert(keylist_used);
    8.14      assert(mimerating);
    8.15                               
    8.16 -    assert(status == PEP_STATUS_OK && mimerating == PEP_rating_unreliable);
    8.17 +    assert(status == PEP_DECRYPTED && mimerating == PEP_rating_unreliable);
    8.18  
    8.19      cout << "Decrypted message:" << endl;
    8.20      cout << decrypted_mimetext << endl;
     9.1 --- a/test/trustwords_test.cc	Tue Jun 13 13:00:37 2017 +0200
     9.2 +++ b/test/trustwords_test.cc	Wed Jun 28 11:21:52 2017 +0200
     9.3 @@ -14,6 +14,7 @@
     9.4      cout << "\n*** get_trustwords test ***\n\n";
     9.5  
     9.6      PEP_SESSION session = nullptr;
     9.7 +    PEP_STATUS status;
     9.8      
     9.9      cout << "calling init()\n";
    9.10      PEP_STATUS status1 = init(&session);
    9.11 @@ -55,29 +56,33 @@
    9.12      assert(words1);
    9.13      cout << words1 << "\n";
    9.14  
    9.15 +    free(words1);
    9.16 +    words1 = nullptr;
    9.17 +    
    9.18      cout << "\nfinding German trustwords for " << fingerprint2 << "...\n";
    9.19      trustwords(session, fingerprint2.c_str(), "de", &words2, &wsize2, 5);
    9.20      assert(words2);
    9.21      cout << words2 << "\n";
    9.22  
    9.23 +    free(words2);
    9.24 +    words1 = nullptr;
    9.25 +
    9.26      cout << "\nfinding German trustwords for " << identity1->address << " and " << identity2->address << "...\n";
    9.27      get_trustwords(session, identity1, identity2, "de", &full_wordlist, &wsize_full, false);
    9.28      assert(full_wordlist);
    9.29      cout << full_wordlist << "\n";
    9.30  
    9.31 -    cout << "\nfinding Englis trustwords for " << identity1->address << " and " << identity2->address << "... with spaces\n";
    9.32 +    free(full_wordlist);
    9.33 +    full_wordlist = nullptr;
    9.34 +
    9.35 +    cout << "\nfinding English trustwords for " << identity1->address << " and " << identity2->address << "... with spaces\n";
    9.36      get_trustwords(session, identity1, identity2_with_spaces, "en", &full_wordlist, &wsize_full, false);
    9.37      assert(full_wordlist);
    9.38      cout << full_wordlist << "\n";
    9.39 +
    9.40 +    free(full_wordlist);
    9.41 +    full_wordlist = nullptr;
    9.42      
    9.43 -    
    9.44 -    pEp_free(words1);
    9.45 -    words1 = nullptr;
    9.46 -    pEp_free(words2);
    9.47 -    words2 = nullptr;
    9.48 -    pEp_free(full_wordlist);
    9.49 -    full_wordlist = nullptr;
    9.50 -
    9.51      cout << "\nTest 2: fpr1 == fpr1, short" << endl;
    9.52      
    9.53      cout << "\nfinding French trustwords for " << fingerprint2 << "...\n";
    9.54 @@ -86,14 +91,14 @@
    9.55      cout << words1 << "\n";
    9.56          
    9.57      cout << "\nfinding French trustwords for " << identity2->address << " and " << identity2->address << "...\n";
    9.58 -    get_trustwords(session, identity2, identity2, "fr", &full_wordlist, &wsize_full, false);
    9.59 -    assert(full_wordlist);
    9.60 -    cout << full_wordlist << "\n";
    9.61 +    status = get_trustwords(session, identity2, identity2, "fr", &full_wordlist, &wsize_full, false);
    9.62 +    assert(status == PEP_TRUSTWORDS_DUPLICATE_FPR);
    9.63 +    cout << "Discovered duplicate fprs as desired" << endl;
    9.64  
    9.65      cout << "\nfinding English trustwords for " << identity2->address << " and " << identity2->address << "... with spaces\n";
    9.66      get_trustwords(session, identity2, identity2_with_spaces, "en", &full_wordlist, &wsize_full, false);
    9.67 -    assert(full_wordlist);
    9.68 -    cout << full_wordlist << "\n";
    9.69 +    assert(status == PEP_TRUSTWORDS_DUPLICATE_FPR);
    9.70 +    cout << "Discovered duplicate fprs as desired" << endl;
    9.71  
    9.72      pEp_free(words1);
    9.73      words1 = nullptr;
    9.74 @@ -112,13 +117,13 @@
    9.75      assert(words2);
    9.76      cout << words2 << "\n";
    9.77      
    9.78 -    cout << "\nfinding English trustwords for " << identity2->address << " and " << identity2->address << "...\n";
    9.79 +    cout << "\nfinding English trustwords for " << identity2->address << " and " << identity1->address << "...\n";
    9.80      get_trustwords(session, identity2, identity1, "en", &full_wordlist, &wsize_full, true);
    9.81      assert(full_wordlist);
    9.82      cout << full_wordlist << "\n";
    9.83      
    9.84 -    cout << "\nfinding English trustwords for " << identity2->address << " and " << identity2->address << "... with spaces\n";
    9.85 -    get_trustwords(session, identity2_with_spaces, identity1, "en", &full_wordlist, &wsize_full, false);
    9.86 +    cout << "\nfinding English trustwords for " << identity2->address << " and " << identity1->address << "... with spaces\n";
    9.87 +    get_trustwords(session, identity2_with_spaces, identity1, "en", &full_wordlist, &wsize_full, true);
    9.88      assert(full_wordlist);
    9.89      cout << full_wordlist << "\n";
    9.90      
    9.91 @@ -199,18 +204,18 @@
    9.92      pEp_free(full_wordlist);
    9.93      full_wordlist = nullptr;
    9.94  
    9.95 -    cout << "\nTest 6: fpr2 is too short" << endl;
    9.96 +    cout << "\nTest 6: fpr2 is shorter" << endl;
    9.97      
    9.98      pEp_identity* identity6 = new_identity(
    9.99          "nobody4@kgrothoff.org",
   9.100 -        "01F932086185C15917B72D30571AFBCA5493553",
   9.101 +        "F1F932086185c15917B72D30571AFBCA5493553",
   9.102          "blargh",
   9.103          "Krista Grothoff");
   9.104      
   9.105      cout << "\nfinding Turkish trustwords for " << identity5->address << " and " << identity6->address << "...\n";
   9.106      PEP_STATUS status6 = get_trustwords(session, identity5, identity6, "tr", &full_wordlist, &wsize_full, false);
   9.107 -    assert(status6 == PEP_TRUSTWORDS_FPR_WRONG_LENGTH);
   9.108 -    cout << "Bad fpr length correctly recognised." << "\n";
   9.109 +    assert(status6 == PEP_STATUS_OK);
   9.110 +    cout << full_wordlist << endl;
   9.111      
   9.112      pEp_identity* identity7 = new_identity(
   9.113          "nobody5@kgrothoff.org",
   9.114 @@ -238,4 +243,3 @@
   9.115      release(session);
   9.116      return 0;
   9.117  }
   9.118 -