Merged in key_reset sync
authorKrista Bennett <krista@pep-project.org>
Fri, 28 Sep 2018 10:36:44 +0200
branchsync
changeset 2958eacaf20a6854
parent 2946 bacb52cb79d0
parent 2957 9557662f7def
child 2983 513f7ae0897b
Merged in key_reset
test/include/MistrustUndoTests.h
test/src/engine_tests/MistrustUndoTests.cc
     1.1 --- a/.hgtags	Sat Sep 15 17:40:17 2018 +0200
     1.2 +++ b/.hgtags	Fri Sep 28 10:36:44 2018 +0200
     1.3 @@ -5,3 +5,4 @@
     1.4  3efe9ded2561d3f6d406acbcbcee01b823cb4de8 for_Outlook-1.1.10
     1.5  fa00137505b8528c77efe8df40963f5fef452cad 0.9.0 release
     1.6  b70a6082836b89f8718b23dcba0624d6db318033 ENGINE-323 fixed
     1.7 +d958333b87d0cdda1bb02f50173f1207baade54a Release 1.0.441
     2.1 --- a/build-mac/pEpEngine.xcodeproj/project.pbxproj	Sat Sep 15 17:40:17 2018 +0200
     2.2 +++ b/build-mac/pEpEngine.xcodeproj/project.pbxproj	Fri Sep 28 10:36:44 2018 +0200
     2.3 @@ -686,7 +686,7 @@
     2.4  		64796A371B455AA5004B1C24 /* Project object */ = {
     2.5  			isa = PBXProject;
     2.6  			attributes = {
     2.7 -				LastUpgradeCheck = 0920;
     2.8 +				LastUpgradeCheck = 0940;
     2.9  				ORGANIZATIONNAME = "Edouard Tisserant";
    2.10  				TargetAttributes = {
    2.11  					644297BE1BE11C65002BC73B = {
    2.12 @@ -932,12 +932,14 @@
    2.13  				CLANG_WARN_BOOL_CONVERSION = YES;
    2.14  				CLANG_WARN_COMMA = YES;
    2.15  				CLANG_WARN_CONSTANT_CONVERSION = YES;
    2.16 +				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
    2.17  				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
    2.18  				CLANG_WARN_EMPTY_BODY = YES;
    2.19  				CLANG_WARN_ENUM_CONVERSION = YES;
    2.20  				CLANG_WARN_INFINITE_RECURSION = YES;
    2.21  				CLANG_WARN_INT_CONVERSION = YES;
    2.22  				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
    2.23 +				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
    2.24  				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
    2.25  				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
    2.26  				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
    2.27 @@ -993,12 +995,14 @@
    2.28  				CLANG_WARN_BOOL_CONVERSION = YES;
    2.29  				CLANG_WARN_COMMA = YES;
    2.30  				CLANG_WARN_CONSTANT_CONVERSION = YES;
    2.31 +				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
    2.32  				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
    2.33  				CLANG_WARN_EMPTY_BODY = YES;
    2.34  				CLANG_WARN_ENUM_CONVERSION = YES;
    2.35  				CLANG_WARN_INFINITE_RECURSION = YES;
    2.36  				CLANG_WARN_INT_CONVERSION = YES;
    2.37  				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
    2.38 +				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
    2.39  				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
    2.40  				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
    2.41  				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/key_reset.c	Fri Sep 28 10:36:44 2018 +0200
     3.3 @@ -0,0 +1,478 @@
     3.4 +// This file is under GNU General Public License 3.0
     3.5 +// see LICENSE.txt
     3.6 +
     3.7 +#include "pEp_internal.h"
     3.8 +#include "dynamic_api.h"
     3.9 +#include "message_api.h"
    3.10 +
    3.11 +#include <string.h>
    3.12 +#include <stdlib.h>
    3.13 +
    3.14 +PEP_STATUS has_key_reset_been_sent(
    3.15 +        PEP_SESSION session, 
    3.16 +        const char* user_id, 
    3.17 +        const char* revoked_fpr,
    3.18 +        bool* contacted)
    3.19 +{
    3.20 +    assert(session);
    3.21 +    assert(contacted);
    3.22 +    assert(user_id);
    3.23 +    assert(revoked_fpr);
    3.24 +    assert(!EMPTYSTR(user_id));
    3.25 +
    3.26 +    if (!session || !contacted || EMPTYSTR(revoked_fpr) || EMPTYSTR(user_id))
    3.27 +        return PEP_ILLEGAL_VALUE;
    3.28 +    
    3.29 +    *contacted = false;
    3.30 +                    
    3.31 +    char* alias_default = NULL;
    3.32 +    
    3.33 +    PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
    3.34 +    
    3.35 +    if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
    3.36 +        free(alias_default);
    3.37 +        alias_default = strdup(user_id);
    3.38 +    }
    3.39 +    
    3.40 +    sqlite3_reset(session->was_id_for_revoke_contacted);
    3.41 +    sqlite3_bind_text(session->was_id_for_revoke_contacted, 1, revoked_fpr, -1,
    3.42 +            SQLITE_STATIC);
    3.43 +    sqlite3_bind_text(session->was_id_for_revoke_contacted, 2, user_id, -1,
    3.44 +            SQLITE_STATIC);        
    3.45 +    int result = sqlite3_step(session->was_id_for_revoke_contacted);
    3.46 +    switch (result) {
    3.47 +        case SQLITE_ROW: {
    3.48 +            *contacted = (sqlite3_column_int(session->was_id_for_revoke_contacted, 0) != 0);
    3.49 +            break;
    3.50 +        }
    3.51 +        default:
    3.52 +            sqlite3_reset(session->was_id_for_revoke_contacted);
    3.53 +            free(alias_default);
    3.54 +            return PEP_UNKNOWN_DB_ERROR;
    3.55 +    }
    3.56 +
    3.57 +    sqlite3_reset(session->was_id_for_revoke_contacted);
    3.58 +    return PEP_STATUS_OK;
    3.59 +}
    3.60 +
    3.61 +//static const char *sql_set_revoke_contact_as_notified =
    3.62 +//    "insert or replace into revocation_contact_list(fpr, contact_id) values (?1, ?2) ;";
    3.63 +
    3.64 +PEP_STATUS set_reset_contact_notified(
    3.65 +        PEP_SESSION session,
    3.66 +        const char* revoke_fpr,
    3.67 +        const char* contact_id
    3.68 +    )
    3.69 +{
    3.70 +    PEP_STATUS status = PEP_STATUS_OK;
    3.71 +    
    3.72 +    assert(session && !EMPTYSTR(revoke_fpr) && !EMPTYSTR(contact_id));
    3.73 +    
    3.74 +    if (!session || EMPTYSTR(revoke_fpr) || EMPTYSTR(contact_id))
    3.75 +        return PEP_ILLEGAL_VALUE;
    3.76 +    
    3.77 +    sqlite3_reset(session->set_revoke_contact_as_notified);
    3.78 +    sqlite3_bind_text(session->set_revoke_contact_as_notified, 1, revoke_fpr, -1, 
    3.79 +            SQLITE_STATIC);
    3.80 +    sqlite3_bind_text(session->set_revoke_contact_as_notified, 2, contact_id, -1,
    3.81 +            SQLITE_STATIC);
    3.82 +
    3.83 +    int result;
    3.84 +    
    3.85 +    result = sqlite3_step(session->set_revoke_contact_as_notified);
    3.86 +    switch (result) {
    3.87 +        case SQLITE_DONE:
    3.88 +            status = PEP_STATUS_OK;
    3.89 +            break;
    3.90 +            
    3.91 +        default:
    3.92 +            status = PEP_UNKNOWN_DB_ERROR;
    3.93 +    }
    3.94 +    
    3.95 +    sqlite3_reset(session->set_revoke_contact_as_notified);
    3.96 +    return status;    
    3.97 +}
    3.98 +
    3.99 +
   3.100 +PEP_STATUS receive_key_reset(PEP_SESSION session,
   3.101 +                             message* reset_msg) {
   3.102 +
   3.103 +    if (!session || !reset_msg)
   3.104 +        return PEP_ILLEGAL_VALUE;
   3.105 +
   3.106 +    pEp_identity* sender_id = reset_msg->from;
   3.107 +                
   3.108 +    if (!sender_id)
   3.109 +        return PEP_MALFORMED_KEY_RESET_MSG;
   3.110 +        
   3.111 +    PEP_STATUS status = update_identity(session, sender_id);
   3.112 +    if (!sender_id->user_id)
   3.113 +        return PEP_UNKNOWN_ERROR;
   3.114 +        
   3.115 +    if (is_me(session, sender_id))
   3.116 +        return PEP_ILLEGAL_VALUE;    
   3.117 +        
   3.118 +    if (!reset_msg->longmsg || strncmp(reset_msg->longmsg, "OLD: ", 5) != 0) 
   3.119 +        return PEP_MALFORMED_KEY_RESET_MSG;
   3.120 +
   3.121 +    status = PEP_STATUS_OK;
   3.122 +    char* old_fpr = NULL;
   3.123 +    char* new_fpr = NULL;
   3.124 +    
   3.125 +    stringlist_t* keylist = NULL;
   3.126 +    pEp_identity* temp_ident = identity_dup(sender_id);
   3.127 +    if (!temp_ident) {
   3.128 +        status = PEP_OUT_OF_MEMORY;
   3.129 +        goto pEp_free;
   3.130 +    }        
   3.131 +            
   3.132 +    char* rest = NULL;
   3.133 +    char* p = strtok_r(reset_msg->longmsg, "\r\n", &rest);
   3.134 +    if (!EMPTYSTR(p + 5))
   3.135 +        old_fpr = strdup(p + 5);
   3.136 +    else {
   3.137 +        status = PEP_MALFORMED_KEY_RESET_MSG;
   3.138 +        goto pEp_free;
   3.139 +    }
   3.140 +    
   3.141 +    bool own_key = false;
   3.142 +    status = is_own_key(session, old_fpr, &own_key);
   3.143 +    
   3.144 +    if (own_key) {
   3.145 +        // Nope, no one can make us our own default. If we want to do that,
   3.146 +        // that's keysync, NOT key reset.
   3.147 +        status = PEP_ILLEGAL_VALUE;
   3.148 +        goto pEp_free;
   3.149 +    }
   3.150 +            
   3.151 +    p = strtok_r(NULL, "\r\n", &rest); 
   3.152 +    if (strncmp(p, "NEW: ", 5) != 0  || EMPTYSTR(p + 5)) {
   3.153 +        status = PEP_MALFORMED_KEY_RESET_MSG;
   3.154 +        goto pEp_free;
   3.155 +    }
   3.156 +
   3.157 +    new_fpr = strdup(p + 5);
   3.158 +        
   3.159 +    // Reset the original key
   3.160 +    status = key_reset(session, old_fpr, temp_ident);
   3.161 +    if (status != PEP_STATUS_OK)
   3.162 +        goto pEp_free;
   3.163 +        
   3.164 +    status = find_keys(session, new_fpr, &keylist);
   3.165 +    if (status != PEP_STATUS_OK)
   3.166 +        goto pEp_free;
   3.167 +        
   3.168 +    if (!keylist) {
   3.169 +        status = PEP_KEY_NOT_FOUND;
   3.170 +        goto pEp_free;
   3.171 +    }
   3.172 +
   3.173 +    // alright, we've checked as best we can. Let's set that baby.
   3.174 +    sender_id->fpr = new_fpr;
   3.175 +    
   3.176 +    // This only sets as the default, does NOT TRUST IN ANY WAY
   3.177 +    sender_id->comm_type = sender_id->comm_type & (~PEP_ct_confirmed);
   3.178 +    status = set_identity(session, sender_id);
   3.179 +    
   3.180 +    sender_id->fpr = NULL; // ownership for free
   3.181 +pEp_free:    
   3.182 +    free_stringlist(keylist);    
   3.183 +    free(old_fpr);
   3.184 +    free(new_fpr);
   3.185 +    free_identity(temp_ident);
   3.186 +    return status;
   3.187 +}
   3.188 +
   3.189 +PEP_STATUS create_standalone_key_reset_message(PEP_SESSION session,
   3.190 +                                               message** dst, 
   3.191 +                                               pEp_identity* recip,
   3.192 +                                               const char* old_fpr,
   3.193 +                                               const char* new_fpr) {
   3.194 +                                                   
   3.195 +    if (!dst || !recip->user_id || !recip->address)
   3.196 +        return PEP_ILLEGAL_VALUE;
   3.197 +
   3.198 +    if (!old_fpr || !new_fpr)
   3.199 +        return PEP_ILLEGAL_VALUE;
   3.200 +        
   3.201 +    *dst = NULL;
   3.202 +    // Get own identity user has corresponded with
   3.203 +    pEp_identity* own_identity = NULL;
   3.204 +    
   3.205 +    PEP_STATUS status = get_own_ident_for_contact_id(session,
   3.206 +                                                     recip,
   3.207 +                                                     &own_identity);                                                       
   3.208 +    if (status != PEP_STATUS_OK)
   3.209 +        return status;
   3.210 +        
   3.211 +    message* reset_message = new_message(PEP_dir_outgoing);
   3.212 +    reset_message->from = own_identity;
   3.213 +    reset_message->to = new_identity_list(identity_dup(recip)); // ?
   3.214 +    
   3.215 +    const char* oldtag = "OLD: ";
   3.216 +    const char* newtag = "\nNEW: ";
   3.217 +    const size_t taglens = 11;
   3.218 +    size_t full_len = taglens + strlen(old_fpr) + strlen(new_fpr) + 2; // \n and \0
   3.219 +    char* longmsg = calloc(full_len, 1);
   3.220 +    strlcpy(longmsg, oldtag, full_len);
   3.221 +    strlcat(longmsg, old_fpr, full_len);
   3.222 +    strlcat(longmsg, newtag, full_len);
   3.223 +    strlcat(longmsg, new_fpr, full_len);
   3.224 +    strlcat(longmsg, "\n", full_len);
   3.225 +    reset_message->longmsg = longmsg; 
   3.226 +    reset_message->shortmsg = strdup("Key reset");    
   3.227 +    
   3.228 +    message* output_msg = NULL;
   3.229 +    
   3.230 +    status = encrypt_message(session, reset_message, NULL,
   3.231 +                             &output_msg, PEP_enc_PGP_MIME,
   3.232 +                             PEP_encrypt_flag_key_reset_only);
   3.233 +
   3.234 +    if (status == PEP_STATUS_OK)
   3.235 +        *dst = output_msg;
   3.236 +        
   3.237 +    free_message(reset_message);
   3.238 +    return status;
   3.239 +}
   3.240 +
   3.241 +PEP_STATUS send_key_reset_to_recents(PEP_SESSION session,
   3.242 +                                     const char* old_fpr, 
   3.243 +                                     const char* new_fpr) {
   3.244 +    assert(old_fpr);
   3.245 +    assert(new_fpr);
   3.246 +    assert(session);
   3.247 +    assert(session->messageToSend);
   3.248 +    
   3.249 +    if (!session || !old_fpr || !new_fpr)
   3.250 +        return PEP_ILLEGAL_VALUE;
   3.251 +
   3.252 +    messageToSend_t send_cb = session->messageToSend;
   3.253 +    if (!send_cb)
   3.254 +        return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
   3.255 +        
   3.256 +    identity_list* recent_contacts = NULL;
   3.257 +    message* reset_msg = NULL;
   3.258 +
   3.259 +    PEP_STATUS status = get_last_contacted(session, &recent_contacts);
   3.260 +    
   3.261 +    if (status != PEP_STATUS_OK)
   3.262 +        goto pEp_free;
   3.263 +                    
   3.264 +    identity_list* curr_id_ptr = recent_contacts;
   3.265 +
   3.266 +    for (curr_id_ptr = recent_contacts; curr_id_ptr; curr_id_ptr = curr_id_ptr->next) {
   3.267 +        pEp_identity* curr_id = curr_id_ptr->ident;
   3.268 +        
   3.269 +        if (!curr_id)
   3.270 +            break;
   3.271 +    
   3.272 +        const char* user_id = curr_id->user_id;
   3.273 +        
   3.274 +        // Should be impossible, but?
   3.275 +        if (!user_id)
   3.276 +            continue;
   3.277 +        
   3.278 +        // Check if it's us - if so, pointless...
   3.279 +        if (is_me(session, curr_id))
   3.280 +            continue;
   3.281 +            
   3.282 +        // Check if they've already been told - this shouldn't be the case, but...
   3.283 +        bool contacted = false;
   3.284 +        status = has_key_reset_been_sent(session, user_id, old_fpr, &contacted);
   3.285 +        if (status != PEP_STATUS_OK)
   3.286 +            goto pEp_free;
   3.287 +    
   3.288 +        if (contacted)
   3.289 +            continue;
   3.290 +            
   3.291 +        // if not, make em a message    
   3.292 +        reset_msg = NULL;
   3.293 +        
   3.294 +        status = create_standalone_key_reset_message(session,
   3.295 +                                                     &reset_msg,
   3.296 +                                                     curr_id,
   3.297 +                                                     old_fpr,
   3.298 +                                                     new_fpr);
   3.299 +
   3.300 +        if (status == PEP_CANNOT_FIND_IDENTITY) { // this is ok, just means we never mailed them 
   3.301 +            status = PEP_STATUS_OK;
   3.302 +            continue; 
   3.303 +        }
   3.304 +            
   3.305 +        if (status != PEP_STATUS_OK) {
   3.306 +            free(reset_msg);
   3.307 +            goto pEp_free;
   3.308 +        }
   3.309 +        
   3.310 +        // insert into queue
   3.311 +        status = send_cb(reset_msg);
   3.312 +
   3.313 +        if (status != PEP_STATUS_OK) {
   3.314 +            free(reset_msg);
   3.315 +            goto pEp_free;            
   3.316 +        }
   3.317 +            
   3.318 +        // Put into notified DB
   3.319 +        status = set_reset_contact_notified(session, old_fpr, user_id);
   3.320 +        if (status != PEP_STATUS_OK)
   3.321 +            goto pEp_free;            
   3.322 +    }
   3.323 +    
   3.324 +pEp_free:
   3.325 +    free_identity_list(recent_contacts);
   3.326 +    return status;
   3.327 +}
   3.328 +
   3.329 +DYNAMIC_API PEP_STATUS key_reset(
   3.330 +        PEP_SESSION session,
   3.331 +        const char* key_id,
   3.332 +        pEp_identity* ident
   3.333 +    )
   3.334 +{
   3.335 +    if (!session)
   3.336 +        return PEP_ILLEGAL_VALUE;
   3.337 +        
   3.338 +    PEP_STATUS status = PEP_STATUS_OK;
   3.339 +        
   3.340 +    char* fpr_copy = NULL;
   3.341 +    char* own_id = NULL;
   3.342 +    char* new_key = NULL;
   3.343 +    identity_list* key_idents = NULL;
   3.344 +    stringlist_t* keys = NULL;
   3.345 +    
   3.346 +    if (!EMPTYSTR(key_id)) {
   3.347 +        fpr_copy = strdup(key_id);
   3.348 +        if (!fpr_copy)
   3.349 +            return PEP_OUT_OF_MEMORY;
   3.350 +    }
   3.351 +        
   3.352 +    if (!ident) {
   3.353 +        // Get list of own identities
   3.354 +        status = get_default_own_userid(session, &own_id);
   3.355 +        if (status != PEP_STATUS_OK)
   3.356 +            goto pEp_free;
   3.357 +            
   3.358 +        if (EMPTYSTR(fpr_copy)) {
   3.359 +            status = get_all_keys_for_user(session, own_id, &keys);
   3.360 +            if (status == PEP_STATUS_OK) {
   3.361 +                stringlist_t* curr_key;
   3.362 +                for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
   3.363 +                    status = key_reset(session, curr_key->value, NULL);
   3.364 +                    if (status != PEP_STATUS_OK)
   3.365 +                        break;
   3.366 +                }
   3.367 +            }
   3.368 +            goto pEp_free;
   3.369 +        } // otherwise, we have a specific fpr to process
   3.370 +
   3.371 +        // fpr_copy exists, so... let's go.
   3.372 +        // Process own identities with this fpr
   3.373 +        status = get_identities_by_main_key_id(session, fpr_copy, &key_idents);
   3.374 +        
   3.375 +        if (status == PEP_STATUS_OK) {
   3.376 +            // have ident list, or should
   3.377 +            identity_list* curr_ident;
   3.378 +            for (curr_ident = key_idents; curr_ident && curr_ident->ident; 
   3.379 +                 curr_ident = curr_ident->next) {
   3.380 +                pEp_identity* this_identity = curr_ident->ident;
   3.381 +                status = key_reset(session, fpr_copy, this_identity);
   3.382 +                if (status != PEP_STATUS_OK)
   3.383 +                    break;                    
   3.384 +            }
   3.385 +        }
   3.386 +        goto pEp_free;
   3.387 +    }
   3.388 +    else { // an identity was specified.       
   3.389 +        if (is_me(session, ident)) {            
   3.390 +            // FIXME: make sure this IS our fpr?
   3.391 +            
   3.392 +            // If it got sent in with an empty fpr...
   3.393 +            if (EMPTYSTR(fpr_copy)) {
   3.394 +                //
   3.395 +                // if (!EMPTYSTR(ident->fpr))
   3.396 +                //     fpr_copy = strdup(ident->fpr);
   3.397 +                status = _myself(session, ident, false, true);
   3.398 +                if (status == PEP_STATUS_OK && ident->fpr)
   3.399 +                    fpr_copy = strdup(ident->fpr);
   3.400 +                else {
   3.401 +                    // last resort?
   3.402 +                    // Get list of own identities
   3.403 +                    char* own_id = NULL;
   3.404 +                    status = get_default_own_userid(session, &own_id);
   3.405 +                    if (status == PEP_STATUS_OK)
   3.406 +                        status = get_user_default_key(session, own_id, &fpr_copy);
   3.407 +                    if (status != PEP_STATUS_OK || EMPTYSTR(fpr_copy))  {
   3.408 +                        free(own_id);
   3.409 +                        return (status == PEP_STATUS_OK ? PEP_KEY_NOT_FOUND : status);
   3.410 +                    }
   3.411 +                }
   3.412 +            }
   3.413 +                        
   3.414 +            free(ident->fpr);
   3.415 +            ident->fpr = fpr_copy;            
   3.416 +            // Create revocation
   3.417 +            status = revoke_key(session, fpr_copy, NULL);
   3.418 +            // generate new key
   3.419 +            if (status == PEP_STATUS_OK) {
   3.420 +                ident->fpr = NULL;
   3.421 +                status = generate_keypair(session, ident);
   3.422 +            }
   3.423 +            if (status == PEP_STATUS_OK) {
   3.424 +                new_key = strdup(ident->fpr);
   3.425 +                status = set_own_key(session, ident, new_key);
   3.426 +            }
   3.427 +            // mistrust fpr from trust
   3.428 +            ident->fpr = fpr_copy;
   3.429 +            
   3.430 +            ident->comm_type = PEP_ct_mistrusted;
   3.431 +            status = set_trust(session, ident);
   3.432 +            ident->fpr = NULL;
   3.433 +            
   3.434 +            // Done with old use of ident.
   3.435 +            if (status == PEP_STATUS_OK) {
   3.436 +                // Update fpr for outgoing
   3.437 +                status = myself(session, ident);
   3.438 +            }
   3.439 +            
   3.440 +            if (status == PEP_STATUS_OK)
   3.441 +                // cascade that mistrust for anyone using this key
   3.442 +                status = mark_as_compromised(session, fpr_copy);
   3.443 +            if (status == PEP_STATUS_OK)
   3.444 +                status = remove_fpr_as_default(session, fpr_copy);
   3.445 +            if (status == PEP_STATUS_OK)
   3.446 +                status = add_mistrusted_key(session, fpr_copy);
   3.447 +            // add to revocation list 
   3.448 +            if (status == PEP_STATUS_OK) 
   3.449 +                status = set_revoked(session, fpr_copy, new_key, time(NULL));            
   3.450 +            // for all active communication partners:
   3.451 +            //      active_send revocation
   3.452 +            if (status == PEP_STATUS_OK)
   3.453 +                status = send_key_reset_to_recents(session, fpr_copy, new_key);
   3.454 +                
   3.455 +        }
   3.456 +        else { // not is_me
   3.457 +            // TODO: Decide what this means. We have a non-own identity, we don't
   3.458 +            //       have an fpr. Do we reset all keys for that identity?
   3.459 +            if (EMPTYSTR(fpr_copy)) {
   3.460 +                NOT_IMPLEMENTED
   3.461 +            }
   3.462 +                
   3.463 +            // remove fpr from all identities
   3.464 +            // remove fpr from all users
   3.465 +            if (status == PEP_STATUS_OK)
   3.466 +                status = remove_fpr_as_default(session, fpr_copy);
   3.467 +            // delete key from DB
   3.468 +            if (status == PEP_STATUS_OK) {
   3.469 +                status = remove_key(session, fpr_copy);
   3.470 +            };
   3.471 +        }
   3.472 +    }
   3.473 +    
   3.474 +pEp_free:
   3.475 +    free(fpr_copy);
   3.476 +    free(own_id);
   3.477 +    free_identity_list(key_idents);
   3.478 +    free_stringlist(keys);
   3.479 +    free(new_key);    
   3.480 +    return status;
   3.481 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/key_reset.h	Fri Sep 28 10:36:44 2018 +0200
     4.3 @@ -0,0 +1,80 @@
     4.4 +// This file is under GNU General Public License 3.0
     4.5 +// see LICENSE.txt
     4.6 +
     4.7 +#pragma once
     4.8 +
     4.9 +#include "key_reset.h"
    4.10 +
    4.11 +#include "pEpEngine.h"
    4.12 +#include "keymanagement.h"
    4.13 +#include "message.h"
    4.14 +#include "message_api.h"
    4.15 +#include "cryptotech.h"
    4.16 +
    4.17 +#ifdef __cplusplus
    4.18 +extern "C" {
    4.19 +#endif
    4.20 +
    4.21 +// key_reset() - reset the database status for a key, removing all trust information
    4.22 +//               and default database connections. For own keys, also revoke the key
    4.23 +//               and communicate the revocation and new key to partners we have sent
    4.24 +//               mail to recently from the specific identity (i.e. address/user_id)
    4.25 +//               that contacted them. We also in this case set up information so that
    4.26 +//               if someone we mail uses the wrong key and wasn't yet contacted,
    4.27 +//               we can send them the reset information from the right address.
    4.28 +//
    4.29 +//               Can be called manually or through another protocol.
    4.30 +//
    4.31 +//  parameters:
    4.32 +//      session (in)            session handle
    4.33 +//      fpr (in)                fingerprint of key to reset. If NULL and ident is NULL,
    4.34 +//                              we reset all keys for the own user. If NULL and ident is
    4.35 +//                              an own identity, we reset the default key for that
    4.36 +//                              identity. If that own identity has no default key, we
    4.37 +//                              reset the user default.
    4.38 +//                              if it is NULL and there is a non-own identity, this is
    4.39 +//                              currently undefined and will return an error. Later, we
    4.40 +//                              may decide on semantics for it (e.g. remove all keys
    4.41 +//                              in the DB for that identity)
    4.42 +//      ident (in)              identity for which the key reset should occur.
    4.43 +//                              if NULL and fpr is non-NULL, we'll reset the key for all
    4.44 +//                              associated identities. If both ident and fpr are NULL, see 
    4.45 +//                              the fpr arg documentation.
    4.46 +//
    4.47 +//      Note: ident->fpr is always ignored
    4.48 +//
    4.49 +//
    4.50 +DYNAMIC_API PEP_STATUS key_reset(
    4.51 +        PEP_SESSION session,
    4.52 +        const char* fpr,
    4.53 +        pEp_identity* ident
    4.54 +    );
    4.55 +
    4.56 +PEP_STATUS has_key_reset_been_sent(
    4.57 +        PEP_SESSION session, 
    4.58 +        const char* user_id, 
    4.59 +        const char* revoked_fpr,
    4.60 +        bool* contacted);
    4.61 +
    4.62 +PEP_STATUS set_reset_contact_notified(
    4.63 +        PEP_SESSION session,
    4.64 +        const char* revoke_fpr,
    4.65 +        const char* contact_id
    4.66 +    );
    4.67 +
    4.68 +PEP_STATUS receive_key_reset(PEP_SESSION session,
    4.69 +                             message* reset_msg);
    4.70 +
    4.71 +PEP_STATUS create_standalone_key_reset_message(PEP_SESSION session,
    4.72 +                                               message** dst, 
    4.73 +                                               pEp_identity* recip,
    4.74 +                                               const char* old_fpr,
    4.75 +                                               const char* new_fpr);
    4.76 +                                               
    4.77 +PEP_STATUS send_key_reset_to_recents(PEP_SESSION session,
    4.78 +                                     const char* old_fpr, 
    4.79 +                                     const char* new_fpr);
    4.80 +    
    4.81 +#ifdef __cplusplus
    4.82 +}
    4.83 +#endif
     5.1 --- a/src/keymanagement.c	Sat Sep 15 17:40:17 2018 +0200
     5.2 +++ b/src/keymanagement.c	Fri Sep 28 10:36:44 2018 +0200
     5.3 @@ -232,6 +232,43 @@
     5.4      return status;
     5.5  }
     5.6  
     5.7 +PEP_STATUS get_all_keys_for_user(PEP_SESSION session, 
     5.8 +                                 const char* user_id,
     5.9 +                                 stringlist_t** keys) {
    5.10 +
    5.11 +    if (!session || EMPTYSTR(user_id) || !keys)
    5.12 +        return PEP_ILLEGAL_VALUE;
    5.13 +        
    5.14 +    PEP_STATUS status = PEP_STATUS_OK;
    5.15 +        
    5.16 +    *keys = NULL;
    5.17 +    stringlist_t* _kl = NULL;
    5.18 +    
    5.19 +    sqlite3_reset(session->get_all_keys_for_user);
    5.20 +    sqlite3_bind_text(session->get_all_keys_for_user, 1, user_id, -1, SQLITE_STATIC);
    5.21 +
    5.22 +    int result = -1;
    5.23 +    
    5.24 +    while ((result = sqlite3_step(session->get_all_keys_for_user)) == SQLITE_ROW) {
    5.25 +        const char* keyres = (const char *) sqlite3_column_text(session->get_all_keys_for_user, 0);
    5.26 +        if (keyres) {
    5.27 +            if (_kl)
    5.28 +                stringlist_add(_kl, keyres);
    5.29 +            else
    5.30 +                _kl = new_stringlist(keyres);
    5.31 +        }
    5.32 +    }
    5.33 +    
    5.34 +    if (!_kl)
    5.35 +        return PEP_KEY_NOT_FOUND;
    5.36 +        
    5.37 +    *keys = _kl;
    5.38 +    
    5.39 +    sqlite3_reset(session->get_all_keys_for_user);
    5.40 +
    5.41 +    return status;
    5.42 +}
    5.43 +
    5.44  PEP_STATUS get_user_default_key(PEP_SESSION session, const char* user_id,
    5.45                                  char** default_key) {
    5.46      assert(session);
    5.47 @@ -1121,71 +1158,21 @@
    5.48  
    5.49      if (!(session && ident && ident->fpr))
    5.50          return PEP_ILLEGAL_VALUE;
    5.51 +            
    5.52 +    // double-check to be sure key is even in the DB
    5.53 +    if (ident->fpr)
    5.54 +        status = set_pgp_keypair(session, ident->fpr);
    5.55  
    5.56 -    if (ident->me)
    5.57 -    {
    5.58 -        revoke_key(session, ident->fpr, NULL);
    5.59 -        myself(session, ident);
    5.60 -    }
    5.61 -    else
    5.62 -    {
    5.63 -        // for undo
    5.64 -        if (session->cached_mistrusted)
    5.65 -            free(session->cached_mistrusted);
    5.66 -        session->cached_mistrusted = identity_dup(ident);
    5.67 -        
    5.68 -        // set mistrust for this user_id/keypair (even if there's not an
    5.69 -        // identity set yet, this is important, as we need to record the mistrust
    5.70 -        // action)
    5.71 -        
    5.72 -        // double-check to be sure key is even in the DB
    5.73 -        if (ident->fpr)
    5.74 -            status = set_pgp_keypair(session, ident->fpr);
    5.75 -
    5.76 -        // We set this temporarily but will grab it back from the cache afterwards
    5.77 -        ident->comm_type = PEP_ct_mistrusted;
    5.78 -        status = set_trust(session, ident);
    5.79 -        ident->comm_type = session->cached_mistrusted->comm_type;
    5.80 -        
    5.81 -        if (status == PEP_STATUS_OK)
    5.82 -            // cascade that mistrust for anyone using this key
    5.83 -            status = mark_as_compromised(session, ident->fpr);
    5.84 -        if (status == PEP_STATUS_OK)
    5.85 -            status = remove_fpr_as_default(session, ident->fpr);
    5.86 -        if (status == PEP_STATUS_OK)
    5.87 -            status = add_mistrusted_key(session, ident->fpr);
    5.88 -    }
    5.89 -
    5.90 -    return status;
    5.91 -}
    5.92 -
    5.93 -DYNAMIC_API PEP_STATUS undo_last_mistrust(PEP_SESSION session) {
    5.94 -    assert(session);
    5.95 +    // We set this temporarily but will grab it back from the cache afterwards
    5.96 +    ident->comm_type = PEP_ct_mistrusted;
    5.97 +    status = set_trust(session, ident);
    5.98      
    5.99 -    if (!session)
   5.100 -        return PEP_ILLEGAL_VALUE;
   5.101 -    
   5.102 -    PEP_STATUS status = PEP_STATUS_OK;
   5.103 -        
   5.104 -    pEp_identity* cached_ident = session->cached_mistrusted;
   5.105 -    
   5.106 -    if (!cached_ident)
   5.107 -        status = PEP_CANNOT_FIND_IDENTITY;
   5.108 -    else {
   5.109 -        status = delete_mistrusted_key(session, cached_ident->fpr);
   5.110 -        if (status == PEP_STATUS_OK) {
   5.111 -            status = set_identity(session, cached_ident);
   5.112 -            // THIS SHOULDN'T BE NECESSARY - PREVIOUS VALUE WAS IN THE DB
   5.113 -            // if (status == PEP_STATUS_OK) {
   5.114 -            //     if ((cached_ident->comm_type | PEP_ct_confirmed) == PEP_ct_pEp)
   5.115 -            //         status = set_as_pEp_user(session, cached_ident);
   5.116 -            // }            
   5.117 -            free_identity(session->cached_mistrusted);
   5.118 -        }
   5.119 -    }
   5.120 -    
   5.121 -    session->cached_mistrusted = NULL;
   5.122 -    
   5.123 +    if (status == PEP_STATUS_OK)
   5.124 +        // cascade that mistrust for anyone using this key
   5.125 +        status = mark_as_compromised(session, ident->fpr);
   5.126 +    if (status == PEP_STATUS_OK)
   5.127 +        status = add_mistrusted_key(session, ident->fpr);
   5.128 +            
   5.129      return status;
   5.130  }
   5.131  
   5.132 @@ -1670,6 +1657,15 @@
   5.133      if (status != PEP_STATUS_OK && status != PEP_GET_KEY_FAILED && status != PEP_KEY_UNSUITABLE)
   5.134          return status;
   5.135      status = PEP_STATUS_OK;
   5.136 +
   5.137 +    bool private = false;
   5.138 +    status = contains_priv_key(session, fpr, &private);
   5.139 +    
   5.140 +    if (status != PEP_STATUS_OK)
   5.141 +        return status;
   5.142 +        
   5.143 +    if (!private)
   5.144 +        return PEP_KEY_UNSUITABLE;
   5.145   
   5.146      if (me->fpr)
   5.147          free(me->fpr);
     6.1 --- a/src/keymanagement.h	Sat Sep 15 17:40:17 2018 +0200
     6.2 +++ b/src/keymanagement.h	Fri Sep 28 10:36:44 2018 +0200
     6.3 @@ -367,6 +367,11 @@
     6.4         const char *fpr
     6.5      );
     6.6  
     6.7 +PEP_STATUS get_all_keys_for_user(PEP_SESSION session, 
     6.8 +                                 const char* user_id,
     6.9 +                                 stringlist_t** keys);
    6.10 +
    6.11 +
    6.12  PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags);
    6.13  
    6.14  PEP_STATUS add_mistrusted_key(PEP_SESSION session, const char* fpr);
     7.1 --- a/src/message_api.c	Sat Sep 15 17:40:17 2018 +0200
     7.2 +++ b/src/message_api.c	Fri Sep 28 10:36:44 2018 +0200
     7.3 @@ -893,7 +893,7 @@
     7.4  }
     7.5  
     7.6  static message* wrap_message_as_attachment(message* envelope, 
     7.7 -    message* attachment, bool keep_orig_subject) {
     7.8 +    message* attachment, message_wrap_type wrap_type, bool keep_orig_subject) {
     7.9      
    7.10      if (!attachment)
    7.11          return NULL;
    7.12 @@ -904,14 +904,22 @@
    7.13  
    7.14      replace_opt_field(attachment, "X-pEp-Version", PEP_VERSION, true);
    7.15          
    7.16 -    if (!_envelope) {
    7.17 +    if (!_envelope && (wrap_type != PEP_message_transport)) {
    7.18          _envelope = extract_minimal_envelope(attachment, PEP_dir_outgoing);
    7.19          status = generate_message_id(_envelope);
    7.20          
    7.21          if (status != PEP_STATUS_OK)
    7.22              goto enomem;
    7.23          
    7.24 -        attachment->longmsg = encapsulate_message_wrap_info("INNER", attachment->longmsg);
    7.25 +        const char* inner_type_string = "";
    7.26 +        switch (wrap_type) {
    7.27 +            case PEP_message_key_reset:
    7.28 +                inner_type_string = "KEY_RESET";
    7.29 +                break;
    7.30 +            default:
    7.31 +                inner_type_string = "INNER";
    7.32 +        }
    7.33 +        attachment->longmsg = encapsulate_message_wrap_info(inner_type_string, attachment->longmsg);
    7.34          _envelope->longmsg = encapsulate_message_wrap_info("OUTER", _envelope->longmsg);
    7.35      }
    7.36      else {
    7.37 @@ -1323,6 +1331,45 @@
    7.38      }
    7.39  }
    7.40  
    7.41 +static PEP_comm_type _get_comm_type_preview(
    7.42 +    PEP_SESSION session,
    7.43 +    PEP_comm_type max_comm_type,
    7.44 +    pEp_identity *ident
    7.45 +    )
    7.46 +{
    7.47 +    assert(session);
    7.48 +    assert(ident);
    7.49 +
    7.50 +    PEP_STATUS status = PEP_STATUS_OK;
    7.51 +
    7.52 +    if (max_comm_type == PEP_ct_compromised)
    7.53 +        return PEP_ct_compromised;
    7.54 +
    7.55 +    if (max_comm_type == PEP_ct_mistrusted)
    7.56 +        return PEP_ct_mistrusted;
    7.57 +
    7.58 +    PEP_comm_type comm_type = PEP_ct_unknown;
    7.59 +    if (ident && !EMPTYSTR(ident->address) && !EMPTYSTR(ident->user_id)) {
    7.60 +        pEp_identity *ident2;
    7.61 +        status = get_identity(session, ident->address, ident->user_id, &ident2);
    7.62 +        comm_type = ident2 ? ident2->comm_type : PEP_ct_unknown;
    7.63 +        free_identity(ident2);
    7.64 +
    7.65 +        if (status == PEP_STATUS_OK) {
    7.66 +            if (comm_type == PEP_ct_compromised)
    7.67 +                comm_type = PEP_ct_compromised;
    7.68 +            else if (comm_type == PEP_ct_mistrusted)
    7.69 +                comm_type = PEP_ct_mistrusted;
    7.70 +            else
    7.71 +                comm_type = _MIN(max_comm_type, comm_type);
    7.72 +        }
    7.73 +        else {
    7.74 +            comm_type = PEP_ct_unknown;
    7.75 +        }
    7.76 +    }
    7.77 +    return comm_type;
    7.78 +}
    7.79 +
    7.80  static void free_bl_entry(bloblist_t *bl)
    7.81  {
    7.82      if (bl) {
    7.83 @@ -1617,12 +1664,11 @@
    7.84      
    7.85      PEP_comm_type max_comm_type = PEP_ct_pEp;
    7.86  
    7.87 -    identity_list * _il;
    7.88 -
    7.89 +    identity_list * _il = NULL;
    7.90  
    7.91      if (enc_format != PEP_enc_none && (_il = src->bcc) && _il->ident)
    7.92 +    // BCC limited support:
    7.93      {
    7.94 -        // BCC limited support:
    7.95          //     - App splits mails with BCC in multiple mails.
    7.96          //     - Each email is encrypted separately
    7.97  
    7.98 @@ -1681,7 +1727,7 @@
    7.99              status = PEP_KEY_NOT_FOUND;
   7.100          }
   7.101      }
   7.102 -    else
   7.103 +    else // Non BCC
   7.104      {
   7.105          for (_il = src->to; _il && _il->ident; _il = _il->next) {
   7.106              PEP_STATUS _status = PEP_STATUS_OK;
   7.107 @@ -1713,9 +1759,17 @@
   7.108                  }
   7.109                  if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
   7.110                      is_pEp_user(session, _il->ident, &has_pEp_user);
   7.111 +                
   7.112 +                _status = bind_own_ident_with_contact_ident(session, src->from, _il->ident);
   7.113 +                if (_status != PEP_STATUS_OK) {
   7.114 +                    status = PEP_UNKNOWN_DB_ERROR;
   7.115 +                    goto pEp_error;
   7.116 +                }
   7.117 +    
   7.118              }
   7.119              else
   7.120                  _status = myself(session, _il->ident);
   7.121 +                
   7.122              if (_status != PEP_STATUS_OK) {
   7.123                  status = PEP_UNENCRYPTED;
   7.124                  goto pEp_error;
   7.125 @@ -1803,7 +1857,8 @@
   7.126      else {
   7.127          // FIXME - we need to deal with transport types (via flag)
   7.128          if ((!force_v_1) && ((max_comm_type | PEP_ct_confirmed) == PEP_ct_pEp)) {
   7.129 -            _src = wrap_message_as_attachment(NULL, src, false);
   7.130 +            message_wrap_type wrap_type = ((flags & PEP_encrypt_flag_key_reset_only) ? PEP_message_key_reset : PEP_message_default);
   7.131 +            _src = wrap_message_as_attachment(NULL, src, wrap_type, false);
   7.132              if (!_src)
   7.133                  goto pEp_error;
   7.134          }
   7.135 @@ -2100,8 +2155,8 @@
   7.136      determine_encryption_format(src);
   7.137      if (src->enc_format != PEP_enc_none)
   7.138          return PEP_ILLEGAL_VALUE;
   7.139 -
   7.140      if (target_id && (!target_id->user_id || target_id->user_id[0] == '\0')) {
   7.141 +        
   7.142          char* own_id = NULL;
   7.143          status = get_default_own_userid(session, &own_id);
   7.144          if (own_id) {
   7.145 @@ -2144,7 +2199,7 @@
   7.146      // if (!(flags & PEP_encrypt_flag_force_no_attached_key))
   7.147      //     _attach_key(session, target_fpr, src);
   7.148  
   7.149 -    _src = wrap_message_as_attachment(NULL, src, false);
   7.150 +    _src = wrap_message_as_attachment(NULL, src, PEP_message_default, false);
   7.151      if (!_src)
   7.152          goto pEp_error;
   7.153  
   7.154 @@ -3016,6 +3071,72 @@
   7.155      return NULL;
   7.156  }
   7.157  
   7.158 +PEP_STATUS check_for_own_revoked_key(
   7.159 +        PEP_SESSION session, 
   7.160 +        stringlist_t* keylist,
   7.161 +        stringpair_list_t** revoked_fpr_pairs
   7.162 +    ) 
   7.163 +{
   7.164 +    if (!session || !revoked_fpr_pairs)
   7.165 +        return PEP_ILLEGAL_VALUE;
   7.166 +        
   7.167 +    *revoked_fpr_pairs = NULL;
   7.168 +
   7.169 +    PEP_STATUS status = PEP_STATUS_OK;
   7.170 +    stringpair_list_t* _the_list = new_stringpair_list(NULL);
   7.171 +        
   7.172 +    stringlist_t* _k = keylist;
   7.173 +    for ( ; _k; _k = _k->next) {
   7.174 +
   7.175 +        if (EMPTYSTR(_k->value))
   7.176 +            continue; // Maybe the right thing to do is choke. 
   7.177 +                      // But we can have NULL-valued empty list heads.
   7.178 +
   7.179 +        const char* recip_fpr = _k->value;
   7.180 +        char* replace_fpr = NULL;
   7.181 +        uint64_t revoke_date = 0; 
   7.182 +        status = get_replacement_fpr(session, 
   7.183 +                                     recip_fpr, 
   7.184 +                                     &replace_fpr, 
   7.185 +                                     &revoke_date);
   7.186 +
   7.187 +        bool own_key = false;
   7.188 +        
   7.189 +        switch (status) {
   7.190 +            case PEP_CANNOT_FIND_IDENTITY:
   7.191 +                status = PEP_STATUS_OK;
   7.192 +                continue;
   7.193 +            case PEP_STATUS_OK:
   7.194 +        
   7.195 +                status = is_own_key(session, recip_fpr, &own_key);
   7.196 +                
   7.197 +                if (status != PEP_STATUS_OK) {
   7.198 +                    free(replace_fpr);
   7.199 +                    return status;
   7.200 +                }
   7.201 +                
   7.202 +                if (own_key)
   7.203 +                    stringpair_list_add(_the_list, new_stringpair(recip_fpr, replace_fpr));
   7.204 +
   7.205 +                free(replace_fpr);
   7.206 +                replace_fpr = NULL;
   7.207 +                break;
   7.208 +            default:    
   7.209 +                goto pEp_free;    
   7.210 +        }
   7.211 +    }
   7.212 +    
   7.213 +    if (_the_list && _the_list->value) {
   7.214 +        *revoked_fpr_pairs = _the_list;
   7.215 +        _the_list = NULL;
   7.216 +    }
   7.217 +            
   7.218 +pEp_free:
   7.219 +    free_stringpair_list(_the_list);
   7.220 +    return status;
   7.221 +
   7.222 +}
   7.223 +
   7.224  DYNAMIC_API PEP_STATUS _decrypt_message(
   7.225          PEP_SESSION session,
   7.226          message *src,
   7.227 @@ -3043,6 +3164,7 @@
   7.228      PEP_STATUS _decrypt_in_pieces_status = PEP_CANNOT_DECRYPT_UNKNOWN;
   7.229      message* msg = NULL;
   7.230      message* calculated_src = src;
   7.231 +    message* reset_msg = NULL;
   7.232      
   7.233      char *ctext;
   7.234      size_t csize;
   7.235 @@ -3103,13 +3225,15 @@
   7.236      bool imported_keys = import_attached_keys(session, src, NULL);
   7.237  
   7.238      // FIXME: is this really necessary here?
   7.239 -    if (!is_me(session, src->from))
   7.240 -        status = update_identity(session, src->from);
   7.241 -    else
   7.242 -        status = myself(session, src->from);
   7.243 +    if (src->from) {
   7.244 +        if (!is_me(session, src->from))
   7.245 +            status = update_identity(session, src->from);
   7.246 +        else
   7.247 +            status = myself(session, src->from);
   7.248          
   7.249 -    if (status != PEP_STATUS_OK)
   7.250 -        return status;
   7.251 +        if (status != PEP_STATUS_OK)
   7.252 +            return status;
   7.253 +    }
   7.254      
   7.255      /*** End Import any attached public keys and update identities accordingly ***/
   7.256      
   7.257 @@ -3192,13 +3316,14 @@
   7.258  
   7.259                  /* if decrypted, but not verified... */
   7.260                  if (decrypt_status == PEP_DECRYPTED) {
   7.261 -                                                                                     
   7.262 -                    status = verify_decrypted(session,
   7.263 -                                              src, msg,
   7.264 -                                              ptext, psize,
   7.265 -                                              &_keylist,
   7.266 -                                              &decrypt_status,
   7.267 -                                              crypto);
   7.268 +                    
   7.269 +                    if (src->from)                                                                 
   7.270 +                        status = verify_decrypted(session,
   7.271 +                                                  src, msg,
   7.272 +                                                  ptext, psize,
   7.273 +                                                  &_keylist,
   7.274 +                                                  &decrypt_status,
   7.275 +                                                  crypto);
   7.276                  }
   7.277                  break;
   7.278  
   7.279 @@ -3273,13 +3398,29 @@
   7.280                                      inner_message->enc_format = src->enc_format;
   7.281                                      // FIXME
   7.282                                      status = unencapsulate_hidden_fields(inner_message, NULL, &wrap_info);
   7.283 +                                    
   7.284 +                                    // ?
   7.285 +                                    if (status != PEP_STATUS_OK) {
   7.286 +                                        free_message(inner_message);
   7.287 +                                        goto pEp_error;
   7.288 +                                    }
   7.289 +    
   7.290                                      if (wrap_info) {
   7.291 -                                        // useless check, but just in case we screw up?
   7.292 -                                        if (strcmp(wrap_info, "INNER") == 0) {
   7.293 -                                            if (status != PEP_STATUS_OK) {
   7.294 -                                                free_message(inner_message);
   7.295 -                                                goto pEp_error;
   7.296 +                                        bool is_inner = (strcmp(wrap_info, "INNER") == 0);
   7.297 +                                        bool is_key_reset = (strcmp(wrap_info, "KEY_RESET") == 0);
   7.298 +
   7.299 +                                        if (is_key_reset) {
   7.300 +                                            if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
   7.301 +                                                status = receive_key_reset(session,
   7.302 +                                                                           inner_message);
   7.303 +                                                if (status != PEP_STATUS_OK) {
   7.304 +                                                    free_message(inner_message);
   7.305 +                                                    goto pEp_error;
   7.306 +                                                }
   7.307 +                                                *flags |= PEP_decrypt_flag_consume;
   7.308                                              }
   7.309 +                                        }
   7.310 +                                        else if (is_inner) {
   7.311  
   7.312                                              // check for private key in decrypted message attachment while importing
   7.313                                              // N.B. Apparently, we always import private keys into the keyring; however,
   7.314 @@ -3304,10 +3445,12 @@
   7.315                                              // needed...
   7.316                                              reconcile_src_and_inner_messages(src, inner_message);
   7.317                                              
   7.318 +
   7.319                                              // FIXME: free msg, but check references
   7.320                                              //src = msg = inner_message;
   7.321                                              calculated_src = msg = inner_message;
   7.322                                              
   7.323 +                                            // FIXME: should this be msg???
   7.324                                              if (src->from) {
   7.325                                                  if (!is_me(session, src->from))
   7.326                                                      update_identity(session, (src->from));
   7.327 @@ -3344,7 +3487,7 @@
   7.328          
   7.329          // Ok, so if it was signed and it's all verified, we can update
   7.330          // eligible signer comm_types to PEP_ct_pEp_*
   7.331 -        if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && is_pEp_msg)
   7.332 +        if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && is_pEp_msg && calculated_src->from)
   7.333              status = update_sender_to_pEp_trust(session, calculated_src->from, _keylist);
   7.334  
   7.335          /* Ok, now we have a keylist used for decryption/verification.
   7.336 @@ -3406,9 +3549,71 @@
   7.337          }
   7.338      } // End prepare output message for return
   7.339  
   7.340 +    // 3. Check to see if the sender used any of our revoked keys
   7.341 +    stringpair_list_t* revoke_replace_pairs = NULL;
   7.342 +    status = check_for_own_revoked_key(session, _keylist, &revoke_replace_pairs);
   7.343 +
   7.344 +    //assert(status != PEP_STATUS_OK); // FIXME: FOR DEBUGGING ONLY DO NOT LEAVE IN    
   7.345 +    if (status != PEP_STATUS_OK) {
   7.346 +        // This should really never choke unless the DB is broken.
   7.347 +        status = PEP_UNKNOWN_DB_ERROR;
   7.348 +        goto pEp_error;
   7.349 +    }
   7.350 +    
   7.351 +    stringpair_list_t* curr_pair_node;
   7.352 +    stringpair_t* curr_pair;
   7.353 +    
   7.354 +    for (curr_pair_node = revoke_replace_pairs; curr_pair_node; curr_pair_node = curr_pair_node->next) {
   7.355 +        curr_pair = curr_pair_node->value;
   7.356 +        
   7.357 +        if (!curr_pair)
   7.358 +            continue; // Again, shouldn't occur
   7.359 +            
   7.360 +        if (curr_pair->key && curr_pair->value) {
   7.361 +            status = create_standalone_key_reset_message(session,
   7.362 +                                                         &reset_msg,
   7.363 +                                                         msg->from,
   7.364 +                                                         curr_pair->key,
   7.365 +                                                         curr_pair->value);
   7.366 +
   7.367 +            // If we can't find the identity, this is someone we've never mailed, so we just
   7.368 +            // go on letting them use the wrong key until we mail them ourselves. (Spammers, etc)
   7.369 +            if (status != PEP_CANNOT_FIND_IDENTITY) {
   7.370 +                if (status != PEP_STATUS_OK)
   7.371 +                    goto pEp_error;
   7.372 +                    
   7.373 +                if (!reset_msg) {
   7.374 +                    status = PEP_OUT_OF_MEMORY;
   7.375 +                    goto pEp_error;
   7.376 +                }
   7.377 +                // insert into queue
   7.378 +                if (session->messageToSend)
   7.379 +                    status = session->messageToSend(reset_msg);
   7.380 +                else
   7.381 +                    status = PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
   7.382 +            
   7.383 +
   7.384 +                if (status == PEP_STATUS_OK) {    
   7.385 +                    // Put into notified DB
   7.386 +                    status = set_reset_contact_notified(session, curr_pair->key, msg->from->user_id);
   7.387 +                    if (status != PEP_STATUS_OK) // It's ok to barf because it's a DB problem??
   7.388 +                        goto pEp_error;
   7.389 +                }
   7.390 +                else {
   7.391 +                    // According to Volker, this would only be a fatal error, so...
   7.392 +                    free_message(reset_msg); // ??
   7.393 +                    reset_msg = NULL; // ??
   7.394 +                    goto pEp_error;
   7.395 +                }
   7.396 +            }
   7.397 +        }
   7.398 +    }
   7.399 +    
   7.400 +    // 4. Set up return values
   7.401      *dst = msg;
   7.402      *keylist = _keylist;
   7.403  
   7.404 +    // 5. Reencrypt if necessary
   7.405      if (reencrypt) {
   7.406          if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
   7.407              message* reencrypt_msg = NULL;
   7.408 @@ -3459,6 +3664,7 @@
   7.409      free(ptext);
   7.410      free(signer_fpr);
   7.411      free_message(msg);
   7.412 +    free_message(reset_msg);
   7.413      free_stringlist(_keylist);
   7.414  
   7.415      return status;
   7.416 @@ -3571,6 +3777,23 @@
   7.417      }
   7.418  }
   7.419  
   7.420 +static void _max_comm_type_from_identity_list_preview(
   7.421 +        identity_list *identities,
   7.422 +        PEP_SESSION session,
   7.423 +        PEP_comm_type *max_comm_type
   7.424 +    )
   7.425 +{
   7.426 +    identity_list * il;
   7.427 +    for (il = identities; il != NULL; il = il->next)
   7.428 +    {
   7.429 +        if (il->ident)
   7.430 +        {   
   7.431 +            *max_comm_type = _get_comm_type_preview(session, *max_comm_type,
   7.432 +                il->ident);
   7.433 +        }
   7.434 +    }
   7.435 +}
   7.436 +
   7.437  DYNAMIC_API PEP_STATUS outgoing_message_rating(
   7.438          PEP_SESSION session,
   7.439          message *msg,
   7.440 @@ -3614,6 +3837,42 @@
   7.441      return PEP_STATUS_OK;
   7.442  }
   7.443  
   7.444 +DYNAMIC_API PEP_STATUS outgoing_message_rating_preview(
   7.445 +        PEP_SESSION session,
   7.446 +        message *msg,
   7.447 +        PEP_rating *rating
   7.448 +    )
   7.449 +{
   7.450 +    PEP_comm_type max_comm_type = PEP_ct_pEp;
   7.451 +
   7.452 +    assert(session);
   7.453 +    assert(msg);
   7.454 +    assert(msg->dir == PEP_dir_outgoing);
   7.455 +    assert(rating);
   7.456 +
   7.457 +    if (!(session && msg && rating))
   7.458 +        return PEP_ILLEGAL_VALUE;
   7.459 +
   7.460 +    if (msg->dir != PEP_dir_outgoing)
   7.461 +        return PEP_ILLEGAL_VALUE;
   7.462 +
   7.463 +    *rating = PEP_rating_undefined;
   7.464 +
   7.465 +    _max_comm_type_from_identity_list_preview(msg->to, session,
   7.466 +            &max_comm_type);
   7.467 +
   7.468 +    _max_comm_type_from_identity_list_preview(msg->cc, session,
   7.469 +            &max_comm_type);
   7.470 +
   7.471 +    _max_comm_type_from_identity_list_preview(msg->bcc, session,
   7.472 +            &max_comm_type);
   7.473 +
   7.474 +    *rating = _MAX(_rating(max_comm_type, PEP_rating_undefined),
   7.475 +            PEP_rating_unencrypted);
   7.476 +
   7.477 +    return PEP_STATUS_OK;
   7.478 +}
   7.479 +
   7.480  DYNAMIC_API PEP_STATUS identity_rating(
   7.481          PEP_SESSION session,
   7.482          pEp_identity *ident,
     8.1 --- a/src/message_api.h	Sat Sep 15 17:40:17 2018 +0200
     8.2 +++ b/src/message_api.h	Fri Sep 28 10:36:44 2018 +0200
     8.3 @@ -40,12 +40,19 @@
     8.4      
     8.5      // This is mainly used by pEp clients to send private keys to 
     8.6      // their own PGP-only device
     8.7 -    PEP_encrypt_flag_force_version_1 = 0x16
     8.8 +    PEP_encrypt_flag_force_version_1 = 0x10,
     8.9 +    
    8.10 +    PEP_encrypt_flag_key_reset_only = 0x20
    8.11      
    8.12  } PEP_encrypt_flags; 
    8.13  
    8.14  typedef unsigned int PEP_encrypt_flags_t;
    8.15  
    8.16 +typedef enum _message_wrap_type {
    8.17 +    PEP_message_default,    // typical inner/outer message 2.0
    8.18 +    PEP_message_transport,  // e.g. for onion layers
    8.19 +    PEP_message_key_reset   // for wrapped key reset information
    8.20 +} message_wrap_type;
    8.21  
    8.22  // encrypt_message() - encrypt message in memory
    8.23  //
    8.24 @@ -434,6 +441,26 @@
    8.25      );
    8.26  
    8.27  
    8.28 +// outgoing_message_rating_preview() - get rating preview
    8.29 +//
    8.30 +//  parameters:
    8.31 +//      session (in)        session handle
    8.32 +//      msg (in)            message to get the rating for
    8.33 +//      rating (out)        rating preview for the message
    8.34 +//
    8.35 +//  return value:
    8.36 +//      error status or PEP_STATUS_OK on success
    8.37 +//
    8.38 +//  caveat:
    8.39 +//      msg->from must point to a valid pEp_identity
    8.40 +//      msg->dir must be PEP_dir_outgoing
    8.41 +//      the ownership of msg remains with the caller
    8.42 +DYNAMIC_API PEP_STATUS outgoing_message_rating_preview(
    8.43 +        PEP_SESSION session,
    8.44 +        message *msg,
    8.45 +        PEP_rating *rating
    8.46 +    );
    8.47 +
    8.48  // identity_rating() - get rating for a single identity
    8.49  //
    8.50  //  parameters:
     9.1 --- a/src/mime.c	Sat Sep 15 17:40:17 2018 +0200
     9.2 +++ b/src/mime.c	Fri Sep 28 10:36:44 2018 +0200
     9.3 @@ -446,8 +446,6 @@
     9.4      char *subject = msg->shortmsg ? msg->shortmsg : altstr;
     9.5  
     9.6      assert(msg);
     9.7 -    assert(msg->from);
     9.8 -    assert(msg->from->address);
     9.9      assert(result);
    9.10  
    9.11      *result = NULL;
    9.12 @@ -485,7 +483,7 @@
    9.13          dt = NULL;
    9.14      }
    9.15  
    9.16 -    /* if (msg->from) */ {
    9.17 +     if (msg->from) {
    9.18          struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
    9.19          if (from == NULL)
    9.20              goto enomem;
    10.1 --- a/src/pEpEngine.c	Sat Sep 15 17:40:17 2018 +0200
    10.2 +++ b/src/pEpEngine.c	Fri Sep 28 10:36:44 2018 +0200
    10.3 @@ -98,6 +98,32 @@
    10.4      "   order by is_own desc, "
    10.5      "   timestamp desc; ";
    10.6  
    10.7 +static const char *sql_get_identities_by_userid =  
    10.8 +    "select address, fpr, username, comm_type, lang,"
    10.9 +    "   identity.flags | pgp_keypair.flags,"
   10.10 +    "   is_own"
   10.11 +    "   from identity"
   10.12 +    "   join person on id = identity.user_id"
   10.13 +    "   join pgp_keypair on fpr = identity.main_key_id"
   10.14 +    "   join trust on id = trust.user_id"
   10.15 +    "       and pgp_keypair_fpr = identity.main_key_id"    
   10.16 +    "   where identity.user_id = ?1" 
   10.17 +    "   order by is_own desc, "
   10.18 +    "   timestamp desc; ";
   10.19 +
   10.20 +static const char *sql_get_identities_by_main_key_id =  
   10.21 +    "select address, identity.user_id, username, comm_type, lang,"
   10.22 +    "   identity.flags | pgp_keypair.flags,"
   10.23 +    "   is_own"
   10.24 +    "   from identity"
   10.25 +    "   join person on id = identity.user_id"
   10.26 +    "   join pgp_keypair on fpr = identity.main_key_id"
   10.27 +    "   join trust on id = trust.user_id"
   10.28 +    "       and pgp_keypair_fpr = identity.main_key_id"    
   10.29 +    "   where identity.main_key_id = ?1" 
   10.30 +    "   order by is_own desc, "
   10.31 +    "   timestamp desc; ";
   10.32 +
   10.33  static const char *sql_get_identity_without_trust_check =  
   10.34      "select identity.main_key_id, username, lang,"
   10.35      "   identity.flags, is_own"
   10.36 @@ -174,6 +200,11 @@
   10.37      "update person set id = ?1 " 
   10.38      "   where id = ?2;";
   10.39  
   10.40 +// Hopefully this cascades and removes trust entries...
   10.41 +static const char *sql_delete_key =
   10.42 +    "delete from pgp_keypair "
   10.43 +    "   where fpr = ?1 ; ";
   10.44 +
   10.45  static const char *sql_replace_main_user_fpr =  
   10.46      "update person "
   10.47      "   set main_key_id = ?1 "
   10.48 @@ -373,6 +404,10 @@
   10.49      "select main_key_id from person" 
   10.50      "   where id = ?1;";
   10.51  
   10.52 +static const char* sql_get_all_keys_for_user =
   10.53 +    "select pgp_keypair_fpr from trust"
   10.54 +    "   where user_id = ?1; ";
   10.55 +
   10.56  static const char* sql_get_default_own_userid =
   10.57      "select id from person"
   10.58      "   join identity on id = identity.user_id"
   10.59 @@ -400,6 +435,10 @@
   10.60      "select revoked_fpr, revocation_date from revoked_keys"
   10.61      "    where replacement_fpr = upper(replace(?1,' ','')) ;";
   10.62  
   10.63 +static const char *sql_get_replacement_fpr = 
   10.64 +    "select replacement_fpr, revocation_date from revoked_keys"
   10.65 +    "    where revoked_fpr = upper(replace(?1,' ','')) ;";
   10.66 +
   10.67  static const char *sql_get_userid_alias_default =
   10.68      "select default_id from alternate_user_id "
   10.69      "   where alternate_id = ?1 ; ";
   10.70 @@ -418,6 +457,27 @@
   10.71  static const char *sql_add_userid_alias =
   10.72      "insert or replace into alternate_user_id (alternate_id, default_id) "
   10.73      "values (?2, ?1) ;";
   10.74 +
   10.75 +static const char *sql_add_into_social_graph =
   10.76 +    "insert or replace into social_graph(own_userid, own_address, contact_userid) "
   10.77 +    "values (?1, ?2, ?3) ;";
   10.78 +
   10.79 +static const char *sql_get_own_address_binding_from_contact =
   10.80 +    "select own_address from social_graph where own_userid = ?1 and contact_userid = ?2 ;";
   10.81 +
   10.82 +static const char *sql_set_revoke_contact_as_notified =
   10.83 +    "insert or replace into revocation_contact_list(fpr, contact_id) values (?1, ?2) ;";
   10.84 +    
   10.85 +static const char *sql_get_contacted_ids_from_revoke_fpr =
   10.86 +    "select * from revocation_contact_list where fpr = ?1 ;";
   10.87 +
   10.88 +static const char *sql_was_id_for_revoke_contacted = 
   10.89 +    "select count(*) from revocation_contact_list where fpr = ?1 and contact_id = ?2 ;";
   10.90 +
   10.91 +// We only need user_id and address, since in the main usage, we'll call update_identity
   10.92 +// on this anyway when sending out messages.
   10.93 +static const char *sql_get_last_contacted =
   10.94 +    "select user_id, address from identity where datetime('now') < datetime(timestamp, '+14 days') ; ";
   10.95      
   10.96  static int user_version(void *_version, int count, char **text, char **name)
   10.97  {
   10.98 @@ -614,7 +674,7 @@
   10.99      sqlite3_busy_timeout(_session->system_db, 1000);
  10.100  
  10.101  // increment this when patching DDL
  10.102 -#define _DDL_USER_VERSION "8"
  10.103 +#define _DDL_USER_VERSION "9"
  10.104  
  10.105      if (in_first) {
  10.106  
  10.107 @@ -715,6 +775,25 @@
  10.108                  "create table if not exists mistrusted_keys (\n"
  10.109                  "    fpr text primary key\n"
  10.110                  ");\n"
  10.111 +                // social graph for key resets
  10.112 +                "create table if not exists social_graph (\n"
  10.113 +                "    own_userid text,\n"
  10.114 +                "    own_address text,\n"
  10.115 +                "    contact_userid text,\n"
  10.116 +                "    CONSTRAINT fk_own_identity\n"
  10.117 +                "       FOREIGN KEY(own_address, own_userid)\n" 
  10.118 +                "       REFERENCES identity(address, user_id)\n"
  10.119 +                "       ON DELETE CASCADE ON UPDATE CASCADE\n"
  10.120 +                ");\n"
  10.121 +                // list of user_ids sent revocation
  10.122 +                "create table if not exists revocation_contact_list (\n"
  10.123 +                "   fpr text not null references pgp_keypair (fpr)\n"
  10.124 +                "       on delete cascade,\n"
  10.125 +                "   contact_id text not null references person (id)\n"
  10.126 +                "       on delete cascade on update cascade,\n"
  10.127 +                "   timestamp integer default (datetime('now')),\n"
  10.128 +                "   PRIMARY KEY(fpr, contact_id)\n"
  10.129 +                ");\n"
  10.130                  ,
  10.131              NULL,
  10.132              NULL,
  10.133 @@ -1005,6 +1084,33 @@
  10.134                  );
  10.135                  assert(int_result == SQLITE_OK);    
  10.136              }
  10.137 +            if (version < 9) {
  10.138 +                int_result = sqlite3_exec(
  10.139 +                    _session->db,
  10.140 +                    "create table if not exists social_graph (\n"
  10.141 +                    "    own_userid text,\n"
  10.142 +                    "    own_address text,\n"
  10.143 +                    "    contact_userid text,\n"
  10.144 +                    "    CONSTRAINT fk_own_identity\n"
  10.145 +                    "       FOREIGN KEY(own_address, own_userid)\n" 
  10.146 +                    "       REFERENCES identity(address, user_id)\n"
  10.147 +                    "       ON DELETE CASCADE ON UPDATE CASCADE,\n"
  10.148 +                    ");\n"
  10.149 +                    "create table if not exists revocation_contact_list (\n"
  10.150 +                    "   fpr text not null references pgp_keypair (fpr)\n"
  10.151 +                    "       on delete cascade,\n"
  10.152 +                    "   contact_id text not null references person (id)\n"
  10.153 +                    "       on delete cascade on update cascade,\n"
  10.154 +                    "   timestamp integer default (datetime('now')),\n"
  10.155 +                    "   PRIMARY KEY(fpr, contact_id)\n"
  10.156 +                    ");\n"
  10.157 +                    ,
  10.158 +                    NULL,
  10.159 +                    NULL,
  10.160 +                    NULL
  10.161 +                );
  10.162 +                assert(int_result == SQLITE_OK);    
  10.163 +            }
  10.164          }        
  10.165          else { 
  10.166              // Version from DB was 0, it means this is initial setup.
  10.167 @@ -1052,10 +1158,24 @@
  10.168              &_session->get_identities_by_address, NULL);
  10.169      assert(int_result == SQLITE_OK);
  10.170  
  10.171 +    int_result = sqlite3_prepare_v2(_session->db, sql_get_identities_by_userid,
  10.172 +            (int)strlen(sql_get_identities_by_userid), 
  10.173 +            &_session->get_identities_by_userid, NULL);
  10.174 +    assert(int_result == SQLITE_OK);
  10.175 +
  10.176 +    int_result = sqlite3_prepare_v2(_session->db, sql_get_identities_by_main_key_id,
  10.177 +            (int)strlen(sql_get_identities_by_main_key_id), 
  10.178 +            &_session->get_identities_by_main_key_id, NULL);
  10.179 +    assert(int_result == SQLITE_OK);
  10.180 +
  10.181      int_result = sqlite3_prepare_v2(_session->db, sql_get_user_default_key,
  10.182              (int)strlen(sql_get_user_default_key), &_session->get_user_default_key, NULL);
  10.183      assert(int_result == SQLITE_OK);
  10.184  
  10.185 +    int_result = sqlite3_prepare_v2(_session->db, sql_get_all_keys_for_user,
  10.186 +            (int)strlen(sql_get_all_keys_for_user), &_session->get_all_keys_for_user, NULL);
  10.187 +    assert(int_result == SQLITE_OK);
  10.188 +
  10.189      int_result = sqlite3_prepare_v2(_session->db, sql_get_default_own_userid,
  10.190              (int)strlen(sql_get_default_own_userid), &_session->get_default_own_userid, NULL);
  10.191      assert(int_result == SQLITE_OK);
  10.192 @@ -1072,6 +1192,10 @@
  10.193              (int)strlen(sql_replace_userid), &_session->replace_userid, NULL);
  10.194      assert(int_result == SQLITE_OK);
  10.195  
  10.196 +    int_result = sqlite3_prepare_v2(_session->db, sql_delete_key,
  10.197 +            (int)strlen(sql_delete_key), &_session->delete_key, NULL);
  10.198 +    assert(int_result == SQLITE_OK);
  10.199 +
  10.200      int_result = sqlite3_prepare_v2(_session->db, sql_replace_main_user_fpr,
  10.201              (int)strlen(sql_replace_main_user_fpr), &_session->replace_main_user_fpr, NULL);
  10.202      assert(int_result == SQLITE_OK);
  10.203 @@ -1114,6 +1238,46 @@
  10.204              (int)strlen(sql_is_pEp_user), &_session->is_pEp_user, NULL);
  10.205      assert(int_result == SQLITE_OK);
  10.206  
  10.207 +    int_result = sqlite3_prepare_v2(_session->db, sql_add_into_social_graph,
  10.208 +            (int)strlen(sql_add_into_social_graph), &_session->add_into_social_graph, NULL);
  10.209 +    assert(int_result == SQLITE_OK);
  10.210 +
  10.211 +    int_result = sqlite3_prepare_v2(_session->db, 
  10.212 +            sql_get_own_address_binding_from_contact,
  10.213 +            (int)strlen(sql_get_own_address_binding_from_contact), 
  10.214 +            &_session->get_own_address_binding_from_contact, NULL);
  10.215 +    assert(int_result == SQLITE_OK);
  10.216 +
  10.217 +    int_result = sqlite3_prepare_v2(_session->db, 
  10.218 +            sql_set_revoke_contact_as_notified,
  10.219 +            (int)strlen(sql_set_revoke_contact_as_notified), 
  10.220 +            &_session->set_revoke_contact_as_notified, NULL);
  10.221 +    assert(int_result == SQLITE_OK);
  10.222 +
  10.223 +    int_result = sqlite3_prepare_v2(_session->db, 
  10.224 +            sql_get_contacted_ids_from_revoke_fpr,
  10.225 +            (int)strlen(sql_get_contacted_ids_from_revoke_fpr), 
  10.226 +            &_session->get_contacted_ids_from_revoke_fpr, NULL);
  10.227 +    assert(int_result == SQLITE_OK);
  10.228 +
  10.229 +    int_result = sqlite3_prepare_v2(_session->db, 
  10.230 +            sql_was_id_for_revoke_contacted,
  10.231 +            (int)strlen(sql_was_id_for_revoke_contacted), 
  10.232 +            &_session->was_id_for_revoke_contacted, NULL);
  10.233 +    assert(int_result == SQLITE_OK);
  10.234 +
  10.235 +    int_result = sqlite3_prepare_v2(_session->db, 
  10.236 +            sql_get_last_contacted,
  10.237 +            (int)strlen(sql_get_last_contacted), 
  10.238 +            &_session->get_last_contacted, NULL);
  10.239 +    assert(int_result == SQLITE_OK);
  10.240 +
  10.241 +    int_result = sqlite3_prepare_v2(_session->db, 
  10.242 +            sql_get_own_address_binding_from_contact,
  10.243 +            (int)strlen(sql_get_own_address_binding_from_contact), 
  10.244 +            &_session->get_own_address_binding_from_contact, NULL);
  10.245 +    assert(int_result == SQLITE_OK);
  10.246 +
  10.247      int_result = sqlite3_prepare_v2(_session->db, sql_set_device_group,
  10.248              (int)strlen(sql_set_device_group), &_session->set_device_group, NULL);
  10.249      assert(int_result == SQLITE_OK);
  10.250 @@ -1259,6 +1423,10 @@
  10.251              (int)strlen(sql_get_revoked), &_session->get_revoked, NULL);
  10.252      assert(int_result == SQLITE_OK);
  10.253      
  10.254 +    int_result = sqlite3_prepare_v2(_session->db, sql_get_replacement_fpr,
  10.255 +            (int)strlen(sql_get_replacement_fpr), &_session->get_replacement_fpr, NULL);
  10.256 +    assert(int_result == SQLITE_OK);
  10.257 +
  10.258      int_result = sqlite3_prepare_v2(_session->db, sql_add_mistrusted_key,
  10.259              (int)strlen(sql_add_mistrusted_key), &_session->add_mistrusted_key, NULL);
  10.260      assert(int_result == SQLITE_OK);
  10.261 @@ -1351,8 +1519,14 @@
  10.262                  sqlite3_finalize(session->get_identity_without_trust_check);
  10.263              if (session->get_identities_by_address)
  10.264                  sqlite3_finalize(session->get_identities_by_address);            
  10.265 +            if (session->get_identities_by_userid)
  10.266 +                sqlite3_finalize(session->get_identities_by_userid);                
  10.267 +            if (session->get_identities_by_main_key_id)
  10.268 +                sqlite3_finalize(session->get_identities_by_main_key_id);                                
  10.269              if (session->get_user_default_key)
  10.270 -                sqlite3_finalize(session->get_user_default_key);    
  10.271 +                sqlite3_finalize(session->get_user_default_key);
  10.272 +            if (session->get_all_keys_for_user)
  10.273 +                sqlite3_finalize(session->get_all_keys_for_user);                        
  10.274              if (session->get_default_own_userid)
  10.275                  sqlite3_finalize(session->get_default_own_userid);
  10.276              if (session->get_userid_alias_default)
  10.277 @@ -1370,7 +1544,19 @@
  10.278              if (session->is_pEp_user)
  10.279                  sqlite3_finalize(session->is_pEp_user);
  10.280              if (session->exists_person)
  10.281 -                sqlite3_finalize(session->exists_person);                        
  10.282 +                sqlite3_finalize(session->exists_person);
  10.283 +            if (session->add_into_social_graph)
  10.284 +                sqlite3_finalize(session->add_into_social_graph);  
  10.285 +            if (session->get_own_address_binding_from_contact)
  10.286 +                sqlite3_finalize(session->get_own_address_binding_from_contact);  
  10.287 +            if (session->set_revoke_contact_as_notified)
  10.288 +                sqlite3_finalize(session->set_revoke_contact_as_notified);  
  10.289 +            if (session->get_contacted_ids_from_revoke_fpr)
  10.290 +                sqlite3_finalize(session->get_contacted_ids_from_revoke_fpr);  
  10.291 +            if (session->was_id_for_revoke_contacted)
  10.292 +                sqlite3_finalize(session->was_id_for_revoke_contacted);   
  10.293 +            if (session->get_last_contacted)
  10.294 +                sqlite3_finalize(session->get_last_contacted);                                       
  10.295              if (session->set_device_group)
  10.296                  sqlite3_finalize(session->set_device_group);
  10.297              if (session->get_device_group)
  10.298 @@ -1411,6 +1597,8 @@
  10.299                  sqlite3_finalize(session->i18n_token);
  10.300              if (session->replace_userid)
  10.301                  sqlite3_finalize(session->replace_userid);
  10.302 +            if (session->delete_key)
  10.303 +                sqlite3_finalize(session->delete_key);                
  10.304              if (session->replace_main_user_fpr)
  10.305                  sqlite3_finalize(session->replace_main_user_fpr);                
  10.306              if (session->get_main_user_fpr)
  10.307 @@ -1441,7 +1629,8 @@
  10.308                  sqlite3_finalize(session->set_revoked);
  10.309              if (session->get_revoked)
  10.310                  sqlite3_finalize(session->get_revoked);
  10.311 -
  10.312 +            if (session->get_replacement_fpr)
  10.313 +                sqlite3_finalize(session->get_replacement_fpr);                
  10.314              if (session->add_mistrusted_key)
  10.315                  sqlite3_finalize(session->add_mistrusted_key);
  10.316              if (session->delete_mistrusted_key)
  10.317 @@ -1951,6 +2140,149 @@
  10.318      return status;
  10.319  }
  10.320  
  10.321 +PEP_STATUS get_identities_by_userid(
  10.322 +        PEP_SESSION session,
  10.323 +        const char *user_id,
  10.324 +        identity_list **identities
  10.325 +    )
  10.326 +{
  10.327 +    if (!session || !identities || EMPTYSTR(user_id))
  10.328 +        return PEP_ILLEGAL_VALUE;
  10.329 +
  10.330 +    PEP_STATUS status = PEP_STATUS_OK;
  10.331 +    
  10.332 +    pEp_identity* ident = NULL;
  10.333 +
  10.334 +    *identities = new_identity_list(NULL);
  10.335 +
  10.336 +    sqlite3_reset(session->get_identities_by_userid);
  10.337 +    sqlite3_bind_text(session->get_identities_by_userid, 1, user_id, -1, SQLITE_STATIC);
  10.338 +
  10.339 +    int result = -1;
  10.340 +    while ((result = sqlite3_step(session->get_identities_by_userid)) == SQLITE_ROW) {
  10.341 +            // "select address, fpr, username, comm_type, lang,"
  10.342 +            // "   identity.flags | pgp_keypair.flags,"
  10.343 +            // "   is_own"
  10.344 +            // "   from identity"
  10.345 +            // "   join person on id = identity.user_id"
  10.346 +            // "   join pgp_keypair on fpr = identity.main_key_id"
  10.347 +            // "   join trust on id = trust.user_id"
  10.348 +            // "       and pgp_keypair_fpr = identity.main_key_id"    
  10.349 +            // "   where identity.user_id = ?1" 
  10.350 +            // "   order by is_own desc, "
  10.351 +            // "   timestamp desc; ";
  10.352 +
  10.353 +        ident = new_identity(
  10.354 +                    (const char *) sqlite3_column_text(session->get_identities_by_userid, 0),
  10.355 +                    (const char *) sqlite3_column_text(session->get_identities_by_userid, 1),                
  10.356 +                    user_id,
  10.357 +                    (const char *) sqlite3_column_text(session->get_identities_by_userid, 2)
  10.358 +                );
  10.359 +                
  10.360 +        assert(ident);
  10.361 +        if (ident == NULL) {
  10.362 +            sqlite3_reset(session->get_identities_by_userid);
  10.363 +            return PEP_OUT_OF_MEMORY;
  10.364 +        }
  10.365 +
  10.366 +        ident->comm_type = (PEP_comm_type)
  10.367 +            sqlite3_column_int(session->get_identities_by_userid, 3);
  10.368 +        const char* const _lang = (const char *)
  10.369 +            sqlite3_column_text(session->get_identities_by_userid, 4);
  10.370 +        if (_lang && _lang[0]) {
  10.371 +            assert(_lang[0] >= 'a' && _lang[0] <= 'z');
  10.372 +            assert(_lang[1] >= 'a' && _lang[1] <= 'z');
  10.373 +            assert(_lang[2] == 0);
  10.374 +            ident->lang[0] = _lang[0];
  10.375 +            ident->lang[1] = _lang[1];
  10.376 +            ident->lang[2] = 0;
  10.377 +        }
  10.378 +        ident->flags = (unsigned int)
  10.379 +            sqlite3_column_int(session->get_identities_by_userid, 5);
  10.380 +        ident->me = (unsigned int)
  10.381 +            sqlite3_column_int(session->get_identities_by_userid, 6);
  10.382 +    
  10.383 +        identity_list_add(*identities, ident);
  10.384 +        ident = NULL;
  10.385 +    }
  10.386 +
  10.387 +    if ((*identities)->ident == NULL) {
  10.388 +        free_identity_list(*identities);
  10.389 +        *identities = NULL;
  10.390 +        status = PEP_CANNOT_FIND_IDENTITY;
  10.391 +    }
  10.392 +            
  10.393 +    sqlite3_reset(session->get_identities_by_userid);
  10.394 +
  10.395 +    return status;
  10.396 +}
  10.397 +
  10.398 +PEP_STATUS get_identities_by_main_key_id(
  10.399 +        PEP_SESSION session,
  10.400 +        const char *fpr,
  10.401 +        identity_list **identities
  10.402 +    )
  10.403 +{
  10.404 +    if (!session || !identities || EMPTYSTR(fpr))
  10.405 +        return PEP_ILLEGAL_VALUE;
  10.406 +
  10.407 +    PEP_STATUS status = PEP_STATUS_OK;
  10.408 +    
  10.409 +    pEp_identity* ident = NULL;
  10.410 +
  10.411 +    *identities = new_identity_list(NULL);
  10.412 +
  10.413 +    sqlite3_reset(session->get_identities_by_main_key_id);
  10.414 +    sqlite3_bind_text(session->get_identities_by_main_key_id, 1, fpr, -1, SQLITE_STATIC);
  10.415 +
  10.416 +    int result = -1;
  10.417 +    
  10.418 +    while ((result = sqlite3_step(session->get_identities_by_main_key_id)) == SQLITE_ROW) {
  10.419 +        ident = new_identity(
  10.420 +                    (const char *) sqlite3_column_text(session->get_identities_by_main_key_id, 0),
  10.421 +                    fpr,
  10.422 +                    (const char *) sqlite3_column_text(session->get_identities_by_main_key_id, 1),                
  10.423 +                    (const char *) sqlite3_column_text(session->get_identities_by_main_key_id, 2)
  10.424 +                );
  10.425 +                
  10.426 +        assert(ident);
  10.427 +        if (ident == NULL) {
  10.428 +            sqlite3_reset(session->get_identities_by_main_key_id);
  10.429 +            return PEP_OUT_OF_MEMORY;
  10.430 +        }
  10.431 +
  10.432 +        ident->comm_type = (PEP_comm_type)
  10.433 +            sqlite3_column_int(session->get_identities_by_main_key_id, 3);
  10.434 +        const char* const _lang = (const char *)
  10.435 +            sqlite3_column_text(session->get_identities_by_main_key_id, 4);
  10.436 +        if (_lang && _lang[0]) {
  10.437 +            assert(_lang[0] >= 'a' && _lang[0] <= 'z');
  10.438 +            assert(_lang[1] >= 'a' && _lang[1] <= 'z');
  10.439 +            assert(_lang[2] == 0);
  10.440 +            ident->lang[0] = _lang[0];
  10.441 +            ident->lang[1] = _lang[1];
  10.442 +            ident->lang[2] = 0;
  10.443 +        }
  10.444 +        ident->flags = (unsigned int)
  10.445 +            sqlite3_column_int(session->get_identities_by_main_key_id, 5);
  10.446 +        ident->me = (unsigned int)
  10.447 +            sqlite3_column_int(session->get_identities_by_main_key_id, 6);
  10.448 +    
  10.449 +        identity_list_add(*identities, ident);
  10.450 +        ident = NULL;
  10.451 +    }
  10.452 +
  10.453 +    if ((*identities)->ident == NULL) {
  10.454 +        free_identity_list(*identities);
  10.455 +        *identities = NULL;
  10.456 +        status = PEP_CANNOT_FIND_IDENTITY;
  10.457 +    }
  10.458 +            
  10.459 +    sqlite3_reset(session->get_identities_by_main_key_id);
  10.460 +
  10.461 +    return status;
  10.462 +}
  10.463 +
  10.464  PEP_STATUS get_identity_without_trust_check(
  10.465          PEP_SESSION session,
  10.466          const char *address,
  10.467 @@ -2017,6 +2349,7 @@
  10.468      return status;
  10.469  }
  10.470  
  10.471 +
  10.472  PEP_STATUS get_identities_by_address(
  10.473          PEP_SESSION session,
  10.474          const char *address,
  10.475 @@ -2108,6 +2441,7 @@
  10.476                        SQLITE_STATIC);
  10.477                    
  10.478      int result = sqlite3_step(session->exists_identity_entry);
  10.479 +
  10.480      switch (result) {
  10.481          case SQLITE_ROW: {
  10.482              // yeah yeah, I know, we could be lazy here, but it looks bad.
  10.483 @@ -2115,7 +2449,7 @@
  10.484              break;
  10.485          }
  10.486          default: 
  10.487 -            status = PEP_UNKNOWN_ERROR;
  10.488 +            status = PEP_UNKNOWN_DB_ERROR;
  10.489      }
  10.490  
  10.491      sqlite3_reset(session->exists_identity_entry);
  10.492 @@ -2149,7 +2483,7 @@
  10.493              break;
  10.494          }
  10.495          default:
  10.496 -            status = PEP_UNKNOWN_ERROR;
  10.497 +            status = PEP_UNKNOWN_DB_ERROR;
  10.498      }
  10.499      
  10.500      sqlite3_reset(session->exists_trust_entry);
  10.501 @@ -2433,7 +2767,7 @@
  10.502  
  10.503  
  10.504  // This ONLY sets the user flag. Must be called outside of a transaction.
  10.505 -PEP_STATUS set_as_pEp_user(PEP_SESSION session, pEp_identity* user) {
  10.506 +DYNAMIC_API PEP_STATUS set_as_pEp_user(PEP_SESSION session, pEp_identity* user) {
  10.507  
  10.508      assert(session);
  10.509      assert(user);
  10.510 @@ -2503,7 +2837,7 @@
  10.511              }
  10.512              default:
  10.513                  sqlite3_reset(session->exists_person);
  10.514 -                return PEP_UNKNOWN_ERROR;
  10.515 +                return PEP_UNKNOWN_DB_ERROR;
  10.516          }
  10.517          sqlite3_reset(session->exists_person);
  10.518      }
  10.519 @@ -2532,10 +2866,7 @@
  10.520      *is_pEp = false;
  10.521              
  10.522      const char* user_id = identity->user_id;
  10.523 -    
  10.524 -    if (!session || EMPTYSTR(user_id))
  10.525 -        return PEP_ILLEGAL_VALUE;
  10.526 -        
  10.527 +            
  10.528      char* alias_default = NULL;
  10.529      
  10.530      PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
  10.531 @@ -2565,6 +2896,73 @@
  10.532      return PEP_STATUS_OK;
  10.533  }
  10.534  
  10.535 +PEP_STATUS bind_own_ident_with_contact_ident(PEP_SESSION session,
  10.536 +                                             pEp_identity* own_ident, 
  10.537 +                                             pEp_identity* contact_ident) {
  10.538 +    if (!own_ident || !contact_ident || 
  10.539 +        !own_ident->address || !own_ident->user_id || !contact_ident->user_id)
  10.540 +        return PEP_ILLEGAL_VALUE;
  10.541 +        
  10.542 +    sqlite3_reset(session->add_into_social_graph);
  10.543 +    sqlite3_bind_text(session->add_into_social_graph, 1, own_ident->user_id, -1,
  10.544 +            SQLITE_STATIC);
  10.545 +    sqlite3_bind_text(session->add_into_social_graph, 2, own_ident->address, -1,
  10.546 +            SQLITE_STATIC);
  10.547 +    sqlite3_bind_text(session->add_into_social_graph, 3, contact_ident->user_id, -1,
  10.548 +            SQLITE_STATIC);
  10.549 +        
  10.550 +    int result = sqlite3_step(session->add_into_social_graph);
  10.551 +    sqlite3_reset(session->add_into_social_graph);
  10.552 +    
  10.553 +    if (result != SQLITE_DONE)
  10.554 +        return PEP_CANNOT_SET_PERSON;
  10.555 +
  10.556 +    return PEP_STATUS_OK;
  10.557 +}
  10.558 +
  10.559 +PEP_STATUS get_own_ident_for_contact_id(PEP_SESSION session,
  10.560 +                                          const pEp_identity* contact,
  10.561 +                                          pEp_identity** own_ident) {
  10.562 +                                              
  10.563 +    if (!contact || !contact->user_id || !own_ident)
  10.564 +        return PEP_ILLEGAL_VALUE;
  10.565 +        
  10.566 +    char* own_user_id = NULL;
  10.567 +    *own_ident = NULL;
  10.568 +    PEP_STATUS status = get_default_own_userid(session, &own_user_id);
  10.569 +    
  10.570 +    if (status != PEP_STATUS_OK)
  10.571 +        return status;
  10.572 +
  10.573 +    sqlite3_reset(session->get_own_address_binding_from_contact);
  10.574 +    sqlite3_bind_text(session->get_own_address_binding_from_contact, 1, own_user_id, -1,
  10.575 +            SQLITE_STATIC);
  10.576 +    sqlite3_bind_text(session->get_own_address_binding_from_contact, 2, contact->user_id, -1,
  10.577 +            SQLITE_STATIC);
  10.578 +
  10.579 +    int result = sqlite3_step(session->get_own_address_binding_from_contact);
  10.580 +    
  10.581 +    const char* own_address = NULL;
  10.582 +    
  10.583 +    switch (result) {
  10.584 +        case SQLITE_ROW:
  10.585 +            own_address = (const char *)
  10.586 +                sqlite3_column_text(session->get_own_address_binding_from_contact, 0);
  10.587 +            if (own_address) {
  10.588 +                status = get_identity(session, own_address, own_user_id, own_ident);
  10.589 +                if (status == PEP_STATUS_OK) {
  10.590 +                    if (!own_ident)
  10.591 +                        status = PEP_CANNOT_FIND_IDENTITY;
  10.592 +                }
  10.593 +            }
  10.594 +            break;
  10.595 +        default:
  10.596 +            status = PEP_CANNOT_FIND_IDENTITY;
  10.597 +    }
  10.598 +    
  10.599 +    free(own_user_id);
  10.600 +    return status;
  10.601 +}
  10.602  
  10.603  PEP_STATUS remove_fpr_as_default(PEP_SESSION session, 
  10.604                                   const char* fpr) 
  10.605 @@ -2812,6 +3210,27 @@
  10.606      return PEP_STATUS_OK;
  10.607  }
  10.608  
  10.609 +PEP_STATUS remove_key(PEP_SESSION session, const char* fpr) {
  10.610 +    assert(session);
  10.611 +    assert(fpr);
  10.612 +    
  10.613 +    if (!session || EMPTYSTR(fpr))
  10.614 +        return PEP_ILLEGAL_VALUE;
  10.615 +
  10.616 +    int result;
  10.617 +
  10.618 +    sqlite3_reset(session->delete_key);
  10.619 +    sqlite3_bind_text(session->delete_key, 1, fpr, -1,
  10.620 +            SQLITE_STATIC);
  10.621 +    result = sqlite3_step(session->delete_key);
  10.622 +    sqlite3_reset(session->delete_key);
  10.623 +    if (result != SQLITE_DONE)
  10.624 +        return PEP_CANNOT_SET_PGP_KEYPAIR;
  10.625 +
  10.626 +    return PEP_STATUS_OK;
  10.627 +}
  10.628 +
  10.629 +
  10.630  PEP_STATUS refresh_userid_default_key(PEP_SESSION session, const char* user_id) {
  10.631      assert(session);
  10.632      assert(user_id);
  10.633 @@ -3283,6 +3702,15 @@
  10.634      if (!(session && fpr))
  10.635          return PEP_ILLEGAL_VALUE;
  10.636  
  10.637 +    // Check to see first if it is revoked
  10.638 +    bool revoked = false;
  10.639 +    PEP_STATUS status = key_revoked(session, fpr, &revoked);
  10.640 +    if (status != PEP_STATUS_OK)
  10.641 +        return status;
  10.642 +        
  10.643 +    if (revoked)
  10.644 +        return PEP_STATUS_OK;
  10.645 +
  10.646      return session->cryptotech[PEP_crypt_OpenPGP].revoke_key(session, fpr,
  10.647              reason);
  10.648  }
  10.649 @@ -3508,7 +3936,7 @@
  10.650              break;
  10.651  
  10.652          default:
  10.653 -            status = PEP_UNKNOWN_ERROR;
  10.654 +            status = PEP_UNKNOWN_DB_ERROR;
  10.655              result = SQLITE_DONE;
  10.656          }
  10.657      } while (result != SQLITE_DONE);
  10.658 @@ -3559,7 +3987,7 @@
  10.659          break;
  10.660  
  10.661      default:
  10.662 -        status = PEP_UNKNOWN_ERROR;
  10.663 +        status = PEP_UNKNOWN_DB_ERROR;
  10.664      }
  10.665  
  10.666      if (status == PEP_STATUS_OK) {
  10.667 @@ -3602,7 +4030,7 @@
  10.668              status = PEP_RECORD_NOT_FOUND;
  10.669              break;
  10.670          default:
  10.671 -            status = PEP_UNKNOWN_ERROR;
  10.672 +            status = PEP_UNKNOWN_DB_ERROR;
  10.673      }
  10.674      sqlite3_reset(session->sequence_value2);
  10.675  
  10.676 @@ -3667,6 +4095,35 @@
  10.677      return status;
  10.678  }
  10.679  
  10.680 +PEP_STATUS is_own_key(PEP_SESSION session, const char* fpr, bool* own_key) {
  10.681 +    
  10.682 +    assert(session);
  10.683 +    assert(!EMPTYSTR(fpr));
  10.684 +
  10.685 +    if (!session || EMPTYSTR(fpr))
  10.686 +        return PEP_ILLEGAL_VALUE;
  10.687 +    
  10.688 +    *own_key = false;
  10.689 +    sqlite3_reset(session->own_key_is_listed);
  10.690 +    
  10.691 +    sqlite3_bind_text(session->own_key_is_listed, 1, fpr, -1,
  10.692 +            SQLITE_STATIC);
  10.693 +    int result = sqlite3_step(session->own_key_is_listed);
  10.694 +    switch (result) {
  10.695 +        case SQLITE_ROW: {
  10.696 +            *own_key = (sqlite3_column_int(session->own_key_is_listed, 0) != 0);
  10.697 +            break;
  10.698 +        }
  10.699 +        default:
  10.700 +            sqlite3_reset(session->own_key_is_listed);
  10.701 +            return PEP_UNKNOWN_DB_ERROR;
  10.702 +    }
  10.703 +
  10.704 +    sqlite3_reset(session->own_key_is_listed);
  10.705 +    return PEP_STATUS_OK;
  10.706 +
  10.707 +}
  10.708 +
  10.709  DYNAMIC_API PEP_STATUS set_revoked(
  10.710         PEP_SESSION session,
  10.711         const char *revoked_fpr,
  10.712 @@ -3702,7 +4159,7 @@
  10.713              break;
  10.714              
  10.715          default:
  10.716 -            status = PEP_UNKNOWN_ERROR;
  10.717 +            status = PEP_UNKNOWN_DB_ERROR;
  10.718      }
  10.719      
  10.720      sqlite3_reset(session->set_revoked);
  10.721 @@ -3759,6 +4216,99 @@
  10.722      return status;
  10.723  }
  10.724  
  10.725 +DYNAMIC_API PEP_STATUS get_replacement_fpr(
  10.726 +        PEP_SESSION session,
  10.727 +        const char *fpr,
  10.728 +        char **revoked_fpr,
  10.729 +        uint64_t *revocation_date
  10.730 +    )
  10.731 +{
  10.732 +    PEP_STATUS status = PEP_STATUS_OK;
  10.733 +
  10.734 +    assert(session && revoked_fpr && !EMPTYSTR(fpr) && revocation_date);
  10.735 +    
  10.736 +    if (!session || !revoked_fpr || EMPTYSTR(fpr) || !revocation_date)
  10.737 +        return PEP_ILLEGAL_VALUE;
  10.738 +
  10.739 +    *revoked_fpr = NULL;
  10.740 +    *revocation_date = 0;
  10.741 +
  10.742 +    sqlite3_reset(session->get_replacement_fpr);
  10.743 +    sqlite3_bind_text(session->get_replacement_fpr, 1, fpr, -1, SQLITE_STATIC);
  10.744 +
  10.745 +    int result;
  10.746 +    
  10.747 +    result = sqlite3_step(session->get_replacement_fpr);
  10.748 +    switch (result) {
  10.749 +        case SQLITE_ROW: {
  10.750 +            *revoked_fpr = strdup((const char *)
  10.751 +                    sqlite3_column_text(session->get_replacement_fpr, 0));
  10.752 +            if(*revoked_fpr)
  10.753 +                *revocation_date = sqlite3_column_int64(session->get_replacement_fpr,
  10.754 +                        1);
  10.755 +            else
  10.756 +                status = PEP_OUT_OF_MEMORY;
  10.757 +
  10.758 +            break;
  10.759 +        }
  10.760 +        default:
  10.761 +            status = PEP_CANNOT_FIND_IDENTITY;
  10.762 +    }
  10.763 +
  10.764 +    sqlite3_reset(session->get_replacement_fpr);
  10.765 +
  10.766 +    return status;
  10.767 +}
  10.768 +
  10.769 +PEP_STATUS get_last_contacted(
  10.770 +        PEP_SESSION session,
  10.771 +        identity_list** id_list
  10.772 +    )
  10.773 +{
  10.774 +    pEp_identity* ident;
  10.775 +
  10.776 +    assert(session);
  10.777 +    assert(id_list);
  10.778 +
  10.779 +    if (!(session && id_list))
  10.780 +        return PEP_ILLEGAL_VALUE;
  10.781 +
  10.782 +    *id_list = NULL;
  10.783 +    identity_list* ident_list = NULL;
  10.784 +
  10.785 +    sqlite3_reset(session->get_last_contacted);
  10.786 +    int result;
  10.787 +
  10.788 +    while ((result = sqlite3_step(session->get_last_contacted)) == SQLITE_ROW) {
  10.789 +        ident = new_identity(
  10.790 +                (const char *) sqlite3_column_text(session->get_last_contacted, 1),
  10.791 +                NULL,
  10.792 +                (const char *) sqlite3_column_text(session->get_last_contacted, 0),
  10.793 +                NULL);
  10.794 +                
  10.795 +        assert(ident);
  10.796 +        if (ident == NULL) {
  10.797 +            sqlite3_reset(session->get_last_contacted);
  10.798 +            return PEP_OUT_OF_MEMORY;
  10.799 +        }
  10.800 +    
  10.801 +        if (ident_list)
  10.802 +            identity_list_add(ident_list, ident);
  10.803 +        else
  10.804 +            ident_list = new_identity_list(ident);
  10.805 +    }
  10.806 +
  10.807 +    sqlite3_reset(session->get_last_contacted);
  10.808 +    
  10.809 +    *id_list = ident_list;
  10.810 +    
  10.811 +    if (!ident_list)
  10.812 +        return PEP_CANNOT_FIND_IDENTITY;
  10.813 +    
  10.814 +    return PEP_STATUS_OK;    
  10.815 +}
  10.816 +
  10.817 +
  10.818  PEP_STATUS key_created(
  10.819          PEP_SESSION session,
  10.820          const char *fpr,
  10.821 @@ -3783,6 +4333,7 @@
  10.822                                                                      keylist);
  10.823  }
  10.824  
  10.825 +
  10.826  DYNAMIC_API const char* get_engine_version() {
  10.827      return PEP_ENGINE_VERSION;
  10.828  }
  10.829 @@ -3805,7 +4356,7 @@
  10.830      assert(int_result == SQLITE_OK);
  10.831  
  10.832      if (int_result != SQLITE_OK)
  10.833 -        return PEP_UNKNOWN_ERROR;
  10.834 +        return PEP_UNKNOWN_DB_ERROR;
  10.835  
  10.836      return PEP_STATUS_OK;
  10.837  }
    11.1 --- a/src/pEpEngine.h	Sat Sep 15 17:40:17 2018 +0200
    11.2 +++ b/src/pEpEngine.h	Fri Sep 28 10:36:44 2018 +0200
    11.3 @@ -44,6 +44,7 @@
    11.4      PEP_INIT_SQLITE3_WITHOUT_MUTEX                  = 0x0120,
    11.5      PEP_INIT_CANNOT_OPEN_DB                         = 0x0121,
    11.6      PEP_INIT_CANNOT_OPEN_SYSTEM_DB                  = 0x0122,
    11.7 +    PEP_UNKNOWN_DB_ERROR                            = 0x01ff,
    11.8      
    11.9      PEP_KEY_NOT_FOUND                               = 0x0201,
   11.10      PEP_KEY_HAS_AMBIG_NAME                          = 0x0202,
   11.11 @@ -51,6 +52,8 @@
   11.12      PEP_CANNOT_EXPORT_KEY                           = 0x0204,
   11.13      PEP_CANNOT_EDIT_KEY                             = 0x0205,
   11.14      PEP_KEY_UNSUITABLE                              = 0x0206,
   11.15 +    PEP_MALFORMED_KEY_RESET_MSG                     = 0x0210,
   11.16 +    PEP_KEY_NOT_RESET                               = 0x0211,
   11.17      
   11.18      PEP_CANNOT_FIND_IDENTITY                        = 0x0301,
   11.19      PEP_CANNOT_SET_PERSON                           = 0x0381,
   11.20 @@ -93,6 +96,7 @@
   11.21      PEP_SYNC_NO_INJECT_CALLBACK                     = 0x0903,
   11.22      PEP_SYNC_NO_CHANNEL                             = 0x0904,
   11.23      PEP_SYNC_CANNOT_ENCRYPT                         = 0x0905,
   11.24 +    PEP_SYNC_NO_MESSAGE_SEND_CALLBACK               = 0x0906,
   11.25  
   11.26      PEP_CANNOT_INCREASE_SEQUENCE                    = 0x0971,
   11.27  
   11.28 @@ -1217,7 +1221,6 @@
   11.29          uint64_t *revocation_date
   11.30      );
   11.31  
   11.32 -
   11.33  // key_created() - get creation date of a key
   11.34  //
   11.35  //  parameters:
   11.36 @@ -1294,10 +1297,18 @@
   11.37          const char *address,
   11.38          identity_list** id_list
   11.39      );
   11.40 +    
   11.41 +PEP_STATUS get_identities_by_userid(
   11.42 +        PEP_SESSION session,
   11.43 +        const char *user_id,
   11.44 +        identity_list **identities
   11.45 +    );    
   11.46          
   11.47  PEP_STATUS replace_userid(PEP_SESSION session, const char* old_uid,
   11.48                                const char* new_uid);
   11.49                                
   11.50 +PEP_STATUS remove_key(PEP_SESSION session, const char* fpr);
   11.51 +                              
   11.52  PEP_STATUS remove_fpr_as_default(PEP_SESSION session, 
   11.53                                      const char* fpr);
   11.54                                
   11.55 @@ -1309,10 +1320,17 @@
   11.56  PEP_STATUS replace_main_user_fpr(PEP_SESSION session, const char* user_id,
   11.57                                const char* new_fpr);
   11.58      
   11.59 +DYNAMIC_API PEP_STATUS get_replacement_fpr(
   11.60 +        PEP_SESSION session,
   11.61 +        const char *fpr,
   11.62 +        char **revoked_fpr,
   11.63 +        uint64_t *revocation_date
   11.64 +    );
   11.65 +    
   11.66  PEP_STATUS refresh_userid_default_key(PEP_SESSION session, const char* user_id);
   11.67  
   11.68  // This ONLY sets the *user* flag, and creates a shell identity if necessary.
   11.69 -PEP_STATUS set_as_pEp_user(PEP_SESSION session, pEp_identity* user);
   11.70 +DYNAMIC_API PEP_STATUS set_as_pEp_user(PEP_SESSION session, pEp_identity* user);
   11.71  
   11.72  // returns true (by reference) if a person with this user_id exists; 
   11.73  // Also replaces aliased user_ids by defaults in identity.
   11.74 @@ -1320,6 +1338,29 @@
   11.75  
   11.76  PEP_STATUS set_pgp_keypair(PEP_SESSION session, const char* fpr);
   11.77  
   11.78 +PEP_STATUS bind_own_ident_with_contact_ident(PEP_SESSION session,
   11.79 +                                             pEp_identity* own_ident, 
   11.80 +                                             pEp_identity* contact_ident);
   11.81 +
   11.82 +PEP_STATUS get_last_contacted(
   11.83 +        PEP_SESSION session,
   11.84 +        identity_list** id_list
   11.85 +    );
   11.86 +
   11.87 +PEP_STATUS get_own_ident_for_contact_id(PEP_SESSION session,
   11.88 +                                          const pEp_identity* contact,
   11.89 +                                          pEp_identity** own_ident);
   11.90 +
   11.91 +PEP_STATUS exists_trust_entry(PEP_SESSION session, pEp_identity* identity,
   11.92 +                              bool* exists);
   11.93 +
   11.94 +PEP_STATUS is_own_key(PEP_SESSION session, const char* fpr, bool* own_key);
   11.95 +
   11.96 +PEP_STATUS get_identities_by_main_key_id(
   11.97 +        PEP_SESSION session,
   11.98 +        const char *fpr,
   11.99 +        identity_list **identities);
  11.100 +
  11.101  #ifdef __cplusplus
  11.102  }
  11.103  #endif
    12.1 --- a/src/pEp_internal.h	Sat Sep 15 17:40:17 2018 +0200
    12.2 +++ b/src/pEp_internal.h	Fri Sep 28 10:36:44 2018 +0200
    12.3 @@ -109,6 +109,8 @@
    12.4  #include "sync_api.h"
    12.5  #include "Sync_func.h"
    12.6  
    12.7 +#include "key_reset.h"
    12.8 +
    12.9  #define NOT_IMPLEMENTED assert(0); return PEP_UNKNOWN_ERROR;
   12.10  
   12.11  struct _pEpSession;
   12.12 @@ -134,16 +136,25 @@
   12.13      sqlite3_stmt *get_identity;
   12.14      sqlite3_stmt *get_identity_without_trust_check;
   12.15      sqlite3_stmt *get_identities_by_address;
   12.16 +    sqlite3_stmt *get_identities_by_userid;
   12.17 +    sqlite3_stmt *get_identities_by_main_key_id;
   12.18      sqlite3_stmt *replace_identities_fpr;
   12.19      sqlite3_stmt *replace_main_user_fpr;
   12.20      sqlite3_stmt *get_main_user_fpr;
   12.21      sqlite3_stmt *refresh_userid_default_key;
   12.22 +    sqlite3_stmt *delete_key;
   12.23      sqlite3_stmt *remove_fpr_as_default;
   12.24      sqlite3_stmt *set_person;
   12.25      sqlite3_stmt *update_person;
   12.26      sqlite3_stmt *exists_person;    
   12.27      sqlite3_stmt *set_as_pEp_user;
   12.28      sqlite3_stmt *is_pEp_user;
   12.29 +    sqlite3_stmt *add_into_social_graph;
   12.30 +    sqlite3_stmt *get_own_address_binding_from_contact;
   12.31 +    sqlite3_stmt *set_revoke_contact_as_notified;
   12.32 +    sqlite3_stmt *get_contacted_ids_from_revoke_fpr;
   12.33 +    sqlite3_stmt *was_id_for_revoke_contacted;
   12.34 +    sqlite3_stmt *get_last_contacted;
   12.35      sqlite3_stmt *set_device_group;
   12.36      sqlite3_stmt *get_device_group;
   12.37      sqlite3_stmt *set_pgp_keypair;
   12.38 @@ -172,14 +183,16 @@
   12.39      sqlite3_stmt *blacklist_is_listed;
   12.40      sqlite3_stmt *blacklist_retrieve;
   12.41      
   12.42 -    // Own keys
   12.43 +    // Keys
   12.44      sqlite3_stmt *own_key_is_listed;
   12.45      sqlite3_stmt *own_identities_retrieve;
   12.46      sqlite3_stmt *own_keys_retrieve;
   12.47      sqlite3_stmt *get_user_default_key;
   12.48 +    sqlite3_stmt *get_all_keys_for_user;
   12.49          
   12.50      sqlite3_stmt *get_default_own_userid;
   12.51  
   12.52 +
   12.53  //    sqlite3_stmt *set_own_key;
   12.54  
   12.55      // sequence value
   12.56 @@ -189,6 +202,7 @@
   12.57      // revoked keys
   12.58      sqlite3_stmt *set_revoked;
   12.59      sqlite3_stmt *get_revoked;
   12.60 +    sqlite3_stmt *get_replacement_fpr;
   12.61  
   12.62      // mistrusted
   12.63      sqlite3_stmt* add_mistrusted_key;
   12.64 @@ -223,9 +237,6 @@
   12.65      bool unencrypted_subject;
   12.66      bool keep_sync_msg;
   12.67      bool service_log;
   12.68 -
   12.69 -    // mistrust undo cache
   12.70 -    pEp_identity* cached_mistrusted;
   12.71      
   12.72  #ifdef DEBUG_ERRORSTACK
   12.73      stringlist_t* errorstack;
    13.1 --- a/src/pgp_gpg.c	Sat Sep 15 17:40:17 2018 +0200
    13.2 +++ b/src/pgp_gpg.c	Fri Sep 28 10:36:44 2018 +0200
    13.3 @@ -298,8 +298,6 @@
    13.4  
    13.5          gpgme = dlopen(LIBGPGME, RTLD_LAZY);
    13.6          if (gpgme == NULL) {
    13.7 -            // FIXME: Hotfix here?
    13.8 -            
    13.9              status = PEP_INIT_CANNOT_LOAD_GPGME;
   13.10              goto pEp_error;
   13.11          }
    14.1 --- a/test/Makefile	Sat Sep 15 17:40:17 2018 +0200
    14.2 +++ b/test/Makefile	Fri Sep 28 10:36:44 2018 +0200
    14.3 @@ -48,7 +48,7 @@
    14.4  	LLDB_BIN=lldb
    14.5  endif
    14.6  
    14.7 -LDLIBS += -lcpptest
    14.8 +LDLIBS+= -lcpptest
    14.9  
   14.10  
   14.11  # Create a list of the extra library paths for the loader. I do not assume that the engine (and its dependencies) are installed for testing.
   14.12 @@ -93,7 +93,12 @@
   14.13  ifndef PY_ENV
   14.14  	@echo "WARNING: Can't find python3 - this is fine unless you're adding test suites. If so, please install python3."
   14.15  else
   14.16 +ifndef EXCLUDE
   14.17  	$(PY_ENV) gensuitemaker.py
   14.18 +else
   14.19 +	# Comma-separated list, no spaces
   14.20 +	$(PY_ENV) gensuitemaker.py --exclude=$(EXCLUDE)
   14.21 +endif
   14.22  endif
   14.23  		
   14.24  .PHONY: test_home_
    15.1 --- a/test/gensuitemaker.py	Sat Sep 15 17:40:17 2018 +0200
    15.2 +++ b/test/gensuitemaker.py	Fri Sep 28 10:36:44 2018 +0200
    15.3 @@ -1,6 +1,6 @@
    15.4  # This file is under GNU General Public License 3.0
    15.5  # see LICENSE.txt
    15.6 -
    15.7 +import argparse
    15.8  from os import listdir, getcwd
    15.9  from os.path import isfile, join
   15.10  from re import sub
   15.11 @@ -14,11 +14,23 @@
   15.12  
   15.13  indent = "    "
   15.14  
   15.15 +parser = argparse.ArgumentParser()
   15.16 +parser.add_argument("--exclude", "-x", help="Comma-separated list of tests to exclude from test suite build")
   15.17 +
   15.18 +args = parser.parse_args()
   15.19 +
   15.20 +exclude_arg = args.exclude
   15.21 +exclude_list = []
   15.22 +if exclude_arg:
   15.23 +    exclude_list = exclude_arg.split(",")
   15.24 +    for x in exclude_list:
   15.25 +        x.replace(" ","")
   15.26  for f in ls:
   15.27      if isfile(join(srcpath, f)):
   15.28          if (f.endswith(".cc")):
   15.29              suite = sub('\.cc$', '', f)
   15.30 -            suites.append(suite)
   15.31 +            if not suite in exclude_list:
   15.32 +                suites.append(suite)
   15.33  
   15.34  license = (''
   15.35  '// This file is under GNU General Public License 3.0\n'
    16.1 --- a/test/include/EngineTestSuite.h	Sat Sep 15 17:40:17 2018 +0200
    16.2 +++ b/test/include/EngineTestSuite.h	Fri Sep 28 10:36:44 2018 +0200
    16.3 @@ -4,6 +4,8 @@
    16.4  #include <cpptest.h>
    16.5  #include <string>
    16.6  #include <map>
    16.7 +#include <vector>
    16.8 +#include <utility>
    16.9  #include "pEpEngine.h"
   16.10  
   16.11  using namespace std;
   16.12 @@ -14,7 +16,9 @@
   16.13          virtual ~EngineTestSuite();
   16.14          
   16.15          void add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()> test_func);
   16.16 -        
   16.17 +        void output_test_header(const char* test_name);
   16.18 +        void output_test_footer(const char* test_name);
   16.19 +
   16.20      protected:
   16.21          PEP_SESSION session;
   16.22          string test_home;
   16.23 @@ -24,6 +28,9 @@
   16.24          
   16.25          string current_test_name;
   16.26  
   16.27 +        messageToSend_t cached_messageToSend;
   16.28 +        inject_sync_event_t cached_inject_sync_event;
   16.29 +
   16.30  #define TEST_FAILED_MESSAGE_BUFSIZE 1000        
   16.31          char failed_msg_buf[TEST_FAILED_MESSAGE_BUFSIZE];
   16.32          
   16.33 @@ -34,12 +41,24 @@
   16.34          unsigned int number_of_tests;
   16.35          unsigned int on_test_number;
   16.36          
   16.37 +        string temp_test_home;
   16.38 +        
   16.39          virtual void setup();
   16.40          virtual void tear_down();
   16.41          
   16.42          void set_full_env();
   16.43 +        void set_full_env(const char* gpg_conf_copy_path, const char* gpg_agent_conf_file_copy_path, const char* db_conf_file_copy_path);
   16.44          void restore_full_env();
   16.45          void initialise_test_home();
   16.46          void set_my_name();    
   16.47 +	
   16.48 +        void copy_conf_file_to_test_dir(const char* dest_path, const char* conf_orig_path, const char* conf_dest_name);
   16.49 +        
   16.50 +        std::vector<std::pair<std::string, std::string>> gpgdir_fileadd_queue;
   16.51 +        std::vector<std::pair<std::string, std::string>> homedir_fileadd_queue;
   16.52 +        void add_file_to_gpg_dir_queue(std::string copy_from, std::string dst_fname);    
   16.53 +        void add_file_to_home_dir_queue(std::string copy_from, std::string dst_fname);
   16.54 +        void process_file_queue(std::string dirname, std::vector<std::pair<std::string, std::string>> file_queue);
   16.55 +
   16.56  };
   16.57  #endif
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/test/include/KeyResetMessageTests.h	Fri Sep 28 10:36:44 2018 +0200
    17.3 @@ -0,0 +1,52 @@
    17.4 +// This file is under GNU General Public License 3.0
    17.5 +// see LICENSE.txt
    17.6 +
    17.7 +#ifndef KEY_RESET_MESSAGE_H
    17.8 +#define KEY_RESET_MESSAGE_H
    17.9 +
   17.10 +#include <string>
   17.11 +#include "EngineTestIndividualSuite.h"
   17.12 +#include "pEpEngine.h"
   17.13 +
   17.14 +using namespace std;
   17.15 +
   17.16 +class KeyResetMessageTests : public EngineTestIndividualSuite {
   17.17 +    public:
   17.18 +        KeyResetMessageTests(string test_suite, string test_home_dir);
   17.19 +        
   17.20 +        static PEP_STATUS message_send_callback(message *msg);
   17.21 +        
   17.22 +        static KeyResetMessageTests* fake_this;
   17.23 +        
   17.24 +        vector<message*> m_queue;
   17.25 +        
   17.26 +        static constexpr const char* alice_fpr = "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97";
   17.27 +        static constexpr const char* bob_fpr = "BFCDB7F301DEEEBBF947F29659BFF488C9C2EE39";
   17.28 +        
   17.29 +        static constexpr const char* alice_receive_reset_fpr = "6A349E4F68801E39145CD4C5712616A385412538";
   17.30 +
   17.31 +        static const string alice_user_id;
   17.32 +        static const string bob_user_id;    
   17.33 +        static const string carol_user_id;
   17.34 +        static const string dave_user_id;
   17.35 +        static const string erin_user_id;
   17.36 +        static const string fenris_user_id;
   17.37 +
   17.38 +    protected:
   17.39 +        void setup();
   17.40 +                
   17.41 +    private:
   17.42 +        void check_key_reset_message();        
   17.43 +        void check_reset_key_and_notify();
   17.44 +        void check_non_reset_receive_revoked();
   17.45 +        void check_reset_receive_revoked();
   17.46 +        void check_receive_message_to_revoked_key_from_unknown();   
   17.47 +        void check_receive_message_to_revoked_key_from_contact();   
   17.48 +        
   17.49 +        void send_setup();
   17.50 +        void receive_setup();     
   17.51 +        void create_msg_for_revoked_key();
   17.52 +        
   17.53 +};
   17.54 +
   17.55 +#endif
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/test/include/MessageNullFromTests.h	Fri Sep 28 10:36:44 2018 +0200
    18.3 @@ -0,0 +1,26 @@
    18.4 +// This file is under GNU General Public License 3.0
    18.5 +// see LICENSE.txt
    18.6 +
    18.7 +#ifndef MESSAGE_NULL_FROM_H
    18.8 +#define MESSAGE_NULL_FROM_H
    18.9 +
   18.10 +#include <string>
   18.11 +#include "EngineTestIndividualSuite.h"
   18.12 +
   18.13 +using namespace std;
   18.14 +
   18.15 +class MessageNullFromTests : public EngineTestIndividualSuite {
   18.16 +    public:
   18.17 +        MessageNullFromTests(string test_suite, string test_home_dir);
   18.18 +    protected:
   18.19 +        void setup();
   18.20 +    private:
   18.21 +        void check_message_null_from_no_header_key_unencrypted();
   18.22 +        void check_message_null_from_header_key_unencrypted();
   18.23 +        void check_message_null_from_encrypted_not_signed();
   18.24 +        void check_message_null_from_encrypted_and_signed(); 
   18.25 +        void import_bob_pair_and_set_own();
   18.26 +        void import_alice_pub();
   18.27 +};
   18.28 +
   18.29 +#endif
    19.1 --- a/test/include/MistrustUndoTests.h	Sat Sep 15 17:40:17 2018 +0200
    19.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.3 @@ -1,19 +0,0 @@
    19.4 -// This file is under GNU General Public License 3.0
    19.5 -// see LICENSE.txt
    19.6 -
    19.7 -#ifndef MISTRUST_UNDO_H
    19.8 -#define MISTRUST_UNDO_H
    19.9 -
   19.10 -#include <string>
   19.11 -#include "EngineTestSessionSuite.h"
   19.12 -
   19.13 -using namespace std;
   19.14 -
   19.15 -class MistrustUndoTests : public EngineTestSessionSuite {
   19.16 -    public:
   19.17 -        MistrustUndoTests(string test_suite, string test_home_dir);
   19.18 -    private:
   19.19 -        void check_mistrust_undo();
   19.20 -};
   19.21 -
   19.22 -#endif
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/test/include/pEpTestOutput.h	Fri Sep 28 10:36:44 2018 +0200
    20.3 @@ -0,0 +1,43 @@
    20.4 +
    20.5 +#ifndef PEP_TEST_OUTPUT_H
    20.6 +#define PEP_TEST_OUTPUT_H
    20.7 +
    20.8 +#include <cpptest.h>
    20.9 +#include <vector>
   20.10 +#include <string>
   20.11 +
   20.12 +namespace Test {
   20.13 +    class pEpTestOutput : public Output {
   20.14 +        public:
   20.15 +            pEpTestOutput();
   20.16 +            ~pEpTestOutput() {};
   20.17 +            void finished(int tests, const Time& time);
   20.18 +            void initialize(int tests) {};
   20.19 +            void suite_start(int tests, const std::string& name);
   20.20 +            void suite_end(int tests, const std::string& name,
   20.21 +                           const Time& time);
   20.22 +            void test_start(const std::string& name);
   20.23 +            void test_end(const std::string& name, bool ok,
   20.24 +                          const Time& time);
   20.25 +            void assertment(const Test::Source& s);
   20.26 +            
   20.27 +            void outputCorrectPercentage(int num_tests, int failures, int width);
   20.28 +            
   20.29 +        private:
   20.30 +            static constexpr const char* huge_sepline = "///////////////////////////////////////////////////////////////////////////\n";
   20.31 +            static constexpr const char* alt_sepline = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
   20.32 +            static constexpr const char* big_sepline = "********************************************************\n";
   20.33 +            static constexpr const char* med_sepline = "-----------------------------------\n";
   20.34 +            static constexpr const char* sml_sepline = "++++++++++++++++++++++++++\n";
   20.35 +            static constexpr const char* lil_sepline = "~~~~~~\n";
   20.36 +            int _total_failed;
   20.37 +            int _total_tests;
   20.38 +            int _suite_failed;
   20.39 +            int _suite_total;
   20.40 +            std::string _suite_name;
   20.41 +            std::string _test_name;
   20.42 +            std::vector<Source> _test_errors;
   20.43 +            
   20.44 +    };
   20.45 +}
   20.46 +#endif
   20.47 \ No newline at end of file
    21.1 --- a/test/include/test_util.h	Sat Sep 15 17:40:17 2018 +0200
    21.2 +++ b/test/include/test_util.h	Fri Sep 28 10:36:44 2018 +0200
    21.3 @@ -11,6 +11,18 @@
    21.4  
    21.5  void test_init();
    21.6  
    21.7 +bool file_exists(std::string filename);
    21.8 +
    21.9 +PEP_STATUS read_file_and_import_key(PEP_SESSION session, const char* fname);
   21.10 +PEP_STATUS set_up_ident_from_scratch(PEP_SESSION session, 
   21.11 +                                     const char* key_fname,
   21.12 +                                     const char* address,
   21.13 +                                     const char* fpr,
   21.14 +                                     const char* user_id,
   21.15 +                                     const char* username,
   21.16 +                                     pEp_identity** ret_ident,
   21.17 +                                     bool is_priv);
   21.18 +
   21.19  // string equality (case and non-case sensitive)
   21.20  bool _streq(const char* str1, const char* str2);
   21.21  bool _strceq(const char* str1, const char* str2);
   21.22 @@ -41,5 +53,6 @@
   21.23                           const struct stat *file_stat, 
   21.24                           int ftw_info, 
   21.25                           struct FTW * ftw_struct);
   21.26 +                         
   21.27          
   21.28  #endif
    22.1 --- a/test/src/EngineTestIndividualSuite.cc	Sat Sep 15 17:40:17 2018 +0200
    22.2 +++ b/test/src/EngineTestIndividualSuite.cc	Fri Sep 28 10:36:44 2018 +0200
    22.3 @@ -27,4 +27,4 @@
    22.4  void EngineTestIndividualSuite::tear_down() {
    22.5      restore_full_env();
    22.6      EngineTestSuite::tear_down();
    22.7 -}
    22.8 +}
    22.9 \ No newline at end of file
    23.1 --- a/test/src/EngineTestSessionSuite.cc	Sat Sep 15 17:40:17 2018 +0200
    23.2 +++ b/test/src/EngineTestSessionSuite.cc	Fri Sep 28 10:36:44 2018 +0200
    23.3 @@ -23,7 +23,6 @@
    23.4  }
    23.5  
    23.6  void EngineTestSessionSuite::tear_down() {
    23.7 -    cout << "Session: tear_down - OTN: " << on_test_number << " NOT: " << number_of_tests << endl; 
    23.8      if (on_test_number == number_of_tests)
    23.9          restore_full_env();
   23.10          
    24.1 --- a/test/src/EngineTestSuite.cc	Sat Sep 15 17:40:17 2018 +0200
    24.2 +++ b/test/src/EngineTestSuite.cc	Fri Sep 28 10:36:44 2018 +0200
    24.3 @@ -5,11 +5,20 @@
    24.4  #include <unistd.h>
    24.5  #include <ftw.h>
    24.6  #include <assert.h>
    24.7 +#include <fstream>
    24.8 +#include <iostream>
    24.9 +#include <sys/types.h>
   24.10 +#include <sys/stat.h>
   24.11 +
   24.12 +#import <string>
   24.13 +#import <vector>
   24.14 +#include <utility>
   24.15  
   24.16  #include "platform_unix.h"
   24.17  
   24.18  #include "test_util.h"
   24.19  #include "EngineTestSuite.h"
   24.20 +
   24.21  using namespace std;
   24.22  
   24.23  // Constructor
   24.24 @@ -20,6 +29,8 @@
   24.25      number_of_tests = 0;
   24.26      on_test_number = 0;
   24.27      real_home = getenv("HOME");
   24.28 +    cached_messageToSend = NULL;
   24.29 +    cached_inject_sync_event = NULL;
   24.30  }
   24.31  
   24.32  EngineTestSuite::~EngineTestSuite() {}
   24.33 @@ -30,7 +41,58 @@
   24.34      number_of_tests++;
   24.35  }
   24.36  
   24.37 +void EngineTestSuite::copy_conf_file_to_test_dir(const char* dest_path, const char* conf_orig_path, const char* conf_dest_name) {
   24.38 +    string conf_dest_path = dest_path;
   24.39 +    
   24.40 +    struct stat pathinfo;
   24.41 +
   24.42 +    if(stat(conf_dest_path.c_str(), &pathinfo) != 0) {
   24.43 +        int errchk = mkdir(conf_dest_path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
   24.44 +        if (errchk != 0)
   24.45 +            throw std::runtime_error("Error accessing conf file directory.");
   24.46 +    }
   24.47 +    
   24.48 +    conf_dest_path += "/";
   24.49 +    conf_dest_path += conf_dest_name;
   24.50 +    
   24.51 +    ifstream src(conf_orig_path);
   24.52 +    ofstream dst(conf_dest_path.c_str(), ios::trunc);
   24.53 +    
   24.54 +    assert(src);
   24.55 +    assert(dst);
   24.56 +    
   24.57 +    dst << src.rdbuf();
   24.58 +     
   24.59 +    src.close();
   24.60 +    dst.close();
   24.61 +}
   24.62 +
   24.63 +void EngineTestSuite::add_file_to_gpg_dir_queue(string copy_from, string dst_fname) {    
   24.64 +    gpgdir_fileadd_queue.push_back(make_pair(copy_from, dst_fname));
   24.65 +}
   24.66 +
   24.67 +void EngineTestSuite::add_file_to_home_dir_queue(string copy_from, string dst_fname) {
   24.68 +    homedir_fileadd_queue.push_back(make_pair(copy_from, dst_fname));
   24.69 +}
   24.70 +
   24.71 +void EngineTestSuite::process_file_queue(string dirname, vector<pair<string, string>> file_queue) {
   24.72 +    if (file_queue.empty())
   24.73 +        return;
   24.74 +        
   24.75 +    vector<pair<string, string>>::iterator it;
   24.76 +    
   24.77 +    for (it = file_queue.begin(); it != file_queue.end(); it++) {
   24.78 +        copy_conf_file_to_test_dir(dirname.c_str(), it->first.c_str(), it->second.c_str());
   24.79 +    }
   24.80 +    
   24.81 +    file_queue.clear();
   24.82 +}
   24.83 +
   24.84  void EngineTestSuite::set_full_env() {
   24.85 +    set_full_env(NULL, NULL, NULL);
   24.86 +}
   24.87 +
   24.88 +void EngineTestSuite::set_full_env(const char* gpg_conf_copy_path, const char* gpg_agent_conf_file_copy_path, const char* db_conf_file_copy_path) {
   24.89      int success = 0;
   24.90      struct stat dirchk;
   24.91      
   24.92 @@ -39,7 +101,7 @@
   24.93      success = system("gpgconf --kill all");
   24.94      if (success != 0)
   24.95          throw std::runtime_error("SETUP: Error when executing 'gpgconf --kill all'.");
   24.96 -    sleep(1); // hopefully enough time for the system to recognise that it is dead. *sigh*    
   24.97 + //   sleep(1); // hopefully enough time for the system to recognise that it is dead. *sigh*    
   24.98  
   24.99      if (stat(test_home.c_str(), &dirchk) == 0) {
  24.100          if (!S_ISDIR(dirchk.st_mode))
  24.101 @@ -48,7 +110,7 @@
  24.102          struct stat buf;
  24.103  
  24.104          if (stat(test_home.c_str(), &buf) == 0) {
  24.105 -            cout << test_home << " exists. Deleting..." << endl;
  24.106 +//            cout << test_home << " exists. We'll recursively delete. We hope we're not horking your whole system..." << endl;
  24.107              int success = nftw((test_home + "/.").c_str(), util_delete_filepath, 100, FTW_DEPTH);
  24.108          }
  24.109      }
  24.110 @@ -59,7 +121,7 @@
  24.111              throw std::runtime_error("Error creating a test directory.");
  24.112      }
  24.113  
  24.114 -    string temp_test_home = test_home + "/" + my_name;
  24.115 +    temp_test_home = test_home + "/" + my_name;
  24.116      
  24.117      int errchk = mkdir(temp_test_home.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
  24.118      if (errchk != 0)
  24.119 @@ -82,22 +144,28 @@
  24.120  
  24.121      
  24.122      string home = getenv("HOME");
  24.123 -    cout << "home is " << home << endl;
  24.124      assert(temp_test_home.compare(home) != 0);
  24.125      assert(temp_test_home.compare(home + "/") != 0);
  24.126 +    assert(temp_test_home.compare(home + "/.gnupg") != 0); // This is an EXCLUSION test, so we leave this.
  24.127 +    assert(temp_test_home.compare(home + ".gnupg") != 0);
  24.128      assert(temp_test_home.compare(home + "/gnupg") != 0);
  24.129      assert(temp_test_home.compare(home + "gnupg") != 0);
  24.130      assert(temp_test_home.compare(prev_gpg_home) != 0);
  24.131      assert(temp_test_home.compare(prev_gpg_home + "/gnupg") != 0);
  24.132      assert(temp_test_home.compare(prev_gpg_home + "gnupg") != 0);
  24.133 +    assert(temp_test_home.compare(prev_gpg_home + "/.gnupg") != 0);
  24.134 +    assert(temp_test_home.compare(prev_gpg_home + ".gnupg") != 0);
  24.135  
  24.136      if (temp_test_home.compare(home) == 0 || temp_test_home.compare(home + "/") == 0 ||
  24.137          temp_test_home.compare(home + "/gnupg") == 0 || temp_test_home.compare(home + "gnupg") == 0 ||
  24.138 +        temp_test_home.compare(home + "/.gnupg") == 0 || temp_test_home.compare(home + ".gnupg") == 0 ||
  24.139          temp_test_home.compare(prev_gpg_home) == 0 || temp_test_home.compare(prev_gpg_home + "/gnupg") == 0 ||
  24.140 -        temp_test_home.compare(prev_gpg_home + "gnupg") == 0)
  24.141 +        temp_test_home.compare(prev_gpg_home + "gnupg") == 0 || temp_test_home.compare(prev_gpg_home + "/.gnupg") == 0 ||
  24.142 +        temp_test_home.compare(prev_gpg_home + ".gnupg") == 0)
  24.143          throw std::runtime_error("SETUP: new GNUPGHOME threatens to mess up user GNUPGHOME (and delete all their keys). NO DICE.");
  24.144      
  24.145  //    cout << "Ok - checked if new test home will be safe. We'll try and make the directory, deleting it if it has already exists." << endl;
  24.146 +    cout << "Test home directory is " << temp_test_home << endl;
  24.147      
  24.148      struct stat buf;
  24.149      
  24.150 @@ -105,18 +173,30 @@
  24.151      if (success != 0)
  24.152          throw std::runtime_error("SETUP: Error when setting GNUPGHOME.");
  24.153  
  24.154 -    cout << "New GNUPGHOME is " << getenv("GNUPGHOME") << endl;
  24.155 +    cout << "New GNUPGHOME is " << getenv("GNUPGHOME") << endl << endl;
  24.156      
  24.157      success = setenv("HOME", temp_test_home.c_str(), 1);
  24.158      if (success != 0)
  24.159          throw std::runtime_error("SETUP: Cannot set test_home for init.");
  24.160 -    
  24.161 +
  24.162 +    string tmp_gpg_dir = temp_test_home + "/.gnupg";
  24.163 +
  24.164 +    process_file_queue(tmp_gpg_dir, gpgdir_fileadd_queue);
  24.165 +    process_file_queue(temp_test_home, homedir_fileadd_queue);
  24.166 +
  24.167 +    if (gpg_conf_copy_path)
  24.168 +        copy_conf_file_to_test_dir((temp_test_home + "/gnupg").c_str(), gpg_conf_copy_path, "gpg.conf");
  24.169 +    if (gpg_agent_conf_file_copy_path)        
  24.170 +        copy_conf_file_to_test_dir((temp_test_home + "/gnupg").c_str(), gpg_agent_conf_file_copy_path, "gpg-agent.conf");
  24.171 +    if (db_conf_file_copy_path)
  24.172 +        copy_conf_file_to_test_dir(temp_test_home.c_str(), db_conf_file_copy_path, ".pEp_management.db");
  24.173 +        
  24.174      unix_local_db(true);
  24.175      gpg_conf(true);
  24.176      gpg_agent_conf(true);
  24.177      
  24.178  //    cout << "calling init()\n";
  24.179 -    PEP_STATUS status = init(&session, NULL, NULL);
  24.180 +    PEP_STATUS status = init(&session, cached_messageToSend, cached_inject_sync_event);
  24.181      assert(status == PEP_STATUS_OK);
  24.182      assert(session);
  24.183  //    cout << "init() completed.\n";
  24.184 @@ -140,8 +220,8 @@
  24.185      success = setenv("HOME", real_home.c_str(), 1);
  24.186      if (success != 0)
  24.187          throw std::runtime_error("RESTORE: Cannot reset home directory! Either set environment variable manually back to your home, or quit this session!");
  24.188 -    else
  24.189 -        cout << "RESTORE: HOME is now " << getenv("HOME") << endl;
  24.190 +    // else
  24.191 +    //     cout << "RESTORE: HOME is now " << getenv("HOME") << endl;
  24.192      unix_local_db(true);
  24.193      gpg_conf(true);
  24.194      gpg_agent_conf(true);
  24.195 @@ -157,4 +237,3 @@
  24.196  void EngineTestSuite::set_my_name() {
  24.197      my_name = typeid(*this).name();
  24.198  }
  24.199 -
    25.1 --- a/test/src/SuiteMaker.cc	Sat Sep 15 17:40:17 2018 +0200
    25.2 +++ b/test/src/SuiteMaker.cc	Fri Sep 28 10:36:44 2018 +0200
    25.3 @@ -12,163 +12,167 @@
    25.4  #include "SuiteMaker.h"
    25.5  
    25.6  // Begin where we generate stuff
    25.7 -#include "MimeTests.h"
    25.8 -#include "BloblistTests.h"
    25.9 -#include "NewUpdateIdAndMyselfTests.h"
   25.10 +#include "DecorateTests.h"
   25.11 +#include "ReencryptPlusExtraKeysTests.h"
   25.12 +#include "BlacklistTests.h"
   25.13 +#include "AppleMailTests.h"
   25.14 +#include "MessageTwoPointOhTests.h"
   25.15 +#include "IdentityListTests.h"
   25.16  #include "I18nTests.h"
   25.17 -#include "IdentityListTests.h"
   25.18 -#include "PgpBinaryTests.h"
   25.19 -#include "MistrustUndoTests.h"
   25.20 -#include "LeastCommonDenomColorTests.h"
   25.21 +#include "DecryptAttachPrivateKeyUntrustedTests.h"
   25.22 +#include "BCCTests.h"
   25.23 +#include "LeastColorGroupTests.h"
   25.24 +#include "BlacklistAcceptNewKeyTests.h"
   25.25 +#include "MessageApiTests.h"
   25.26  #include "StringlistTests.h"
   25.27 -#include "PgpListKeysTests.h"
   25.28 -#include "MessageApiTests.h"
   25.29 -#include "EncryptMissingPrivateKeyTests.h"
   25.30 -#include "CaseAndDotAddressTests.h"
   25.31 -#include "UserIDAliasTests.h"
   25.32 -#include "BCCTests.h"
   25.33 -#include "BlacklistAcceptNewKeyTests.h"
   25.34 -#include "DecryptAttachPrivateKeyUntrustedTests.h"
   25.35 -#include "BlacklistTests.h"
   25.36 -#include "RevokeRegenAttachTests.h"
   25.37 -#include "PepSubjectReceivedTests.h"
   25.38 -#include "SequenceTests.h"
   25.39 -#include "EncryptAttachPrivateKeyTests.h"
   25.40 -#include "ExternalRevokeTests.h"
   25.41 -#include "KeyeditTests.h"
   25.42 -#include "LeastColorGroupTests.h"
   25.43 -#include "DecryptAttachPrivateKeyTrustedTests.h"
   25.44 -#include "TrustwordsTests.h"
   25.45 -#include "ReencryptPlusExtraKeysTests.h"
   25.46 -#include "MapAsn1Tests.h"
   25.47 -#include "DecorateTests.h"
   25.48 -#include "MessageTwoPointOhTests.h"
   25.49 -#include "CrashdumpTests.h"
   25.50  #include "StringpairListTests.h"
   25.51 -#include "EncryptForIdentityTests.h"
   25.52  #include "TrustManipulationTests.h"
   25.53  #include "SyncTests.h"
   25.54 -#include "AppleMailTests.h"
   25.55 +#include "EncryptAttachPrivateKeyTests.h"
   25.56 +#include "BloblistTests.h"
   25.57 +#include "KeyResetMessageTests.h"
   25.58 +#include "SequenceTests.h"
   25.59 +#include "TrustwordsTests.h"
   25.60 +#include "RevokeRegenAttachTests.h"
   25.61 +#include "EncryptMissingPrivateKeyTests.h"
   25.62 +#include "PepSubjectReceivedTests.h"
   25.63 +#include "KeyeditTests.h"
   25.64 +#include "MapAsn1Tests.h"
   25.65 +#include "PgpBinaryTests.h"
   25.66 +#include "DecryptAttachPrivateKeyTrustedTests.h"
   25.67 +#include "MessageNullFromTests.h"
   25.68 +#include "MimeTests.h"
   25.69 +#include "PgpListKeysTests.h"
   25.70 +#include "NewUpdateIdAndMyselfTests.h"
   25.71 +#include "EncryptForIdentityTests.h"
   25.72 +#include "CrashdumpTests.h"
   25.73 +#include "CaseAndDotAddressTests.h"
   25.74 +#include "LeastCommonDenomColorTests.h"
   25.75 +#include "ExternalRevokeTests.h"
   25.76 +#include "UserIDAliasTests.h"
   25.77  
   25.78  
   25.79  const char* SuiteMaker::all_suites[] = {
   25.80 -    "MimeTests",
   25.81 -    "BloblistTests",
   25.82 -    "NewUpdateIdAndMyselfTests",
   25.83 +    "DecorateTests",
   25.84 +    "ReencryptPlusExtraKeysTests",
   25.85 +    "BlacklistTests",
   25.86 +    "AppleMailTests",
   25.87 +    "MessageTwoPointOhTests",
   25.88 +    "IdentityListTests",
   25.89      "I18nTests",
   25.90 -    "IdentityListTests",
   25.91 -    "PgpBinaryTests",
   25.92 -    "MistrustUndoTests",
   25.93 -    "LeastCommonDenomColorTests",
   25.94 +    "DecryptAttachPrivateKeyUntrustedTests",
   25.95 +    "BCCTests",
   25.96 +    "LeastColorGroupTests",
   25.97 +    "BlacklistAcceptNewKeyTests",
   25.98 +    "MessageApiTests",
   25.99      "StringlistTests",
  25.100 -    "PgpListKeysTests",
  25.101 -    "MessageApiTests",
  25.102 -    "EncryptMissingPrivateKeyTests",
  25.103 -    "CaseAndDotAddressTests",
  25.104 -    "UserIDAliasTests",
  25.105 -    "BCCTests",
  25.106 -    "BlacklistAcceptNewKeyTests",
  25.107 -    "DecryptAttachPrivateKeyUntrustedTests",
  25.108 -    "BlacklistTests",
  25.109 -    "RevokeRegenAttachTests",
  25.110 -    "PepSubjectReceivedTests",
  25.111 -    "SequenceTests",
  25.112 -    "EncryptAttachPrivateKeyTests",
  25.113 -    "ExternalRevokeTests",
  25.114 -    "KeyeditTests",
  25.115 -    "LeastColorGroupTests",
  25.116 -    "DecryptAttachPrivateKeyTrustedTests",
  25.117 -    "TrustwordsTests",
  25.118 -    "ReencryptPlusExtraKeysTests",
  25.119 -    "MapAsn1Tests",
  25.120 -    "DecorateTests",
  25.121 -    "MessageTwoPointOhTests",
  25.122 -    "CrashdumpTests",
  25.123      "StringpairListTests",
  25.124 -    "EncryptForIdentityTests",
  25.125      "TrustManipulationTests",
  25.126      "SyncTests",
  25.127 -    "AppleMailTests",
  25.128 +    "EncryptAttachPrivateKeyTests",
  25.129 +    "BloblistTests",
  25.130 +    "KeyResetMessageTests",
  25.131 +    "SequenceTests",
  25.132 +    "TrustwordsTests",
  25.133 +    "RevokeRegenAttachTests",
  25.134 +    "EncryptMissingPrivateKeyTests",
  25.135 +    "PepSubjectReceivedTests",
  25.136 +    "KeyeditTests",
  25.137 +    "MapAsn1Tests",
  25.138 +    "PgpBinaryTests",
  25.139 +    "DecryptAttachPrivateKeyTrustedTests",
  25.140 +    "MessageNullFromTests",
  25.141 +    "MimeTests",
  25.142 +    "PgpListKeysTests",
  25.143 +    "NewUpdateIdAndMyselfTests",
  25.144 +    "EncryptForIdentityTests",
  25.145 +    "CrashdumpTests",
  25.146 +    "CaseAndDotAddressTests",
  25.147 +    "LeastCommonDenomColorTests",
  25.148 +    "ExternalRevokeTests",
  25.149 +    "UserIDAliasTests",
  25.150  };
  25.151  
  25.152  // This file is generated, so magic constants are ok.
  25.153 -int SuiteMaker::num_suites = 37;
  25.154 +int SuiteMaker::num_suites = 38;
  25.155  
  25.156  void SuiteMaker::suitemaker_build(const char* test_class_name, const char* test_home, Test::Suite** test_suite) {
  25.157 -    if (strcmp(test_class_name, "MimeTests") == 0)
  25.158 -        *test_suite = new MimeTests(test_class_name, test_home);
  25.159 -    else if (strcmp(test_class_name, "BloblistTests") == 0)
  25.160 -        *test_suite = new BloblistTests(test_class_name, test_home);
  25.161 -    else if (strcmp(test_class_name, "NewUpdateIdAndMyselfTests") == 0)
  25.162 -        *test_suite = new NewUpdateIdAndMyselfTests(test_class_name, test_home);
  25.163 +    if (strcmp(test_class_name, "DecorateTests") == 0)
  25.164 +        *test_suite = new DecorateTests(test_class_name, test_home);
  25.165 +    else if (strcmp(test_class_name, "ReencryptPlusExtraKeysTests") == 0)
  25.166 +        *test_suite = new ReencryptPlusExtraKeysTests(test_class_name, test_home);
  25.167 +    else if (strcmp(test_class_name, "BlacklistTests") == 0)
  25.168 +        *test_suite = new BlacklistTests(test_class_name, test_home);
  25.169 +    else if (strcmp(test_class_name, "AppleMailTests") == 0)
  25.170 +        *test_suite = new AppleMailTests(test_class_name, test_home);
  25.171 +    else if (strcmp(test_class_name, "MessageTwoPointOhTests") == 0)
  25.172 +        *test_suite = new MessageTwoPointOhTests(test_class_name, test_home);
  25.173 +    else if (strcmp(test_class_name, "IdentityListTests") == 0)
  25.174 +        *test_suite = new IdentityListTests(test_class_name, test_home);
  25.175      else if (strcmp(test_class_name, "I18nTests") == 0)
  25.176          *test_suite = new I18nTests(test_class_name, test_home);
  25.177 -    else if (strcmp(test_class_name, "IdentityListTests") == 0)
  25.178 -        *test_suite = new IdentityListTests(test_class_name, test_home);
  25.179 -    else if (strcmp(test_class_name, "PgpBinaryTests") == 0)
  25.180 -        *test_suite = new PgpBinaryTests(test_class_name, test_home);
  25.181 -    else if (strcmp(test_class_name, "MistrustUndoTests") == 0)
  25.182 -        *test_suite = new MistrustUndoTests(test_class_name, test_home);
  25.183 -    else if (strcmp(test_class_name, "LeastCommonDenomColorTests") == 0)
  25.184 -        *test_suite = new LeastCommonDenomColorTests(test_class_name, test_home);
  25.185 +    else if (strcmp(test_class_name, "DecryptAttachPrivateKeyUntrustedTests") == 0)
  25.186 +        *test_suite = new DecryptAttachPrivateKeyUntrustedTests(test_class_name, test_home);
  25.187 +    else if (strcmp(test_class_name, "BCCTests") == 0)
  25.188 +        *test_suite = new BCCTests(test_class_name, test_home);
  25.189 +    else if (strcmp(test_class_name, "LeastColorGroupTests") == 0)
  25.190 +        *test_suite = new LeastColorGroupTests(test_class_name, test_home);
  25.191 +    else if (strcmp(test_class_name, "BlacklistAcceptNewKeyTests") == 0)
  25.192 +        *test_suite = new BlacklistAcceptNewKeyTests(test_class_name, test_home);
  25.193 +    else if (strcmp(test_class_name, "MessageApiTests") == 0)
  25.194 +        *test_suite = new MessageApiTests(test_class_name, test_home);
  25.195      else if (strcmp(test_class_name, "StringlistTests") == 0)
  25.196          *test_suite = new StringlistTests(test_class_name, test_home);
  25.197 -    else if (strcmp(test_class_name, "PgpListKeysTests") == 0)
  25.198 -        *test_suite = new PgpListKeysTests(test_class_name, test_home);
  25.199 -    else if (strcmp(test_class_name, "MessageApiTests") == 0)
  25.200 -        *test_suite = new MessageApiTests(test_class_name, test_home);
  25.201 -    else if (strcmp(test_class_name, "EncryptMissingPrivateKeyTests") == 0)
  25.202 -        *test_suite = new EncryptMissingPrivateKeyTests(test_class_name, test_home);
  25.203 -    else if (strcmp(test_class_name, "CaseAndDotAddressTests") == 0)
  25.204 -        *test_suite = new CaseAndDotAddressTests(test_class_name, test_home);
  25.205 -    else if (strcmp(test_class_name, "UserIDAliasTests") == 0)
  25.206 -        *test_suite = new UserIDAliasTests(test_class_name, test_home);
  25.207 -    else if (strcmp(test_class_name, "BCCTests") == 0)
  25.208 -        *test_suite = new BCCTests(test_class_name, test_home);
  25.209 -    else if (strcmp(test_class_name, "BlacklistAcceptNewKeyTests") == 0)
  25.210 -        *test_suite = new BlacklistAcceptNewKeyTests(test_class_name, test_home);
  25.211 -    else if (strcmp(test_class_name, "DecryptAttachPrivateKeyUntrustedTests") == 0)
  25.212 -        *test_suite = new DecryptAttachPrivateKeyUntrustedTests(test_class_name, test_home);
  25.213 -    else if (strcmp(test_class_name, "BlacklistTests") == 0)
  25.214 -        *test_suite = new BlacklistTests(test_class_name, test_home);
  25.215 -    else if (strcmp(test_class_name, "RevokeRegenAttachTests") == 0)
  25.216 -        *test_suite = new RevokeRegenAttachTests(test_class_name, test_home);
  25.217 -    else if (strcmp(test_class_name, "PepSubjectReceivedTests") == 0)
  25.218 -        *test_suite = new PepSubjectReceivedTests(test_class_name, test_home);
  25.219 -    else if (strcmp(test_class_name, "SequenceTests") == 0)
  25.220 -        *test_suite = new SequenceTests(test_class_name, test_home);
  25.221 -    else if (strcmp(test_class_name, "EncryptAttachPrivateKeyTests") == 0)
  25.222 -        *test_suite = new EncryptAttachPrivateKeyTests(test_class_name, test_home);
  25.223 -    else if (strcmp(test_class_name, "ExternalRevokeTests") == 0)
  25.224 -        *test_suite = new ExternalRevokeTests(test_class_name, test_home);
  25.225 -    else if (strcmp(test_class_name, "KeyeditTests") == 0)
  25.226 -        *test_suite = new KeyeditTests(test_class_name, test_home);
  25.227 -    else if (strcmp(test_class_name, "LeastColorGroupTests") == 0)
  25.228 -        *test_suite = new LeastColorGroupTests(test_class_name, test_home);
  25.229 -    else if (strcmp(test_class_name, "DecryptAttachPrivateKeyTrustedTests") == 0)
  25.230 -        *test_suite = new DecryptAttachPrivateKeyTrustedTests(test_class_name, test_home);
  25.231 -    else if (strcmp(test_class_name, "TrustwordsTests") == 0)
  25.232 -        *test_suite = new TrustwordsTests(test_class_name, test_home);
  25.233 -    else if (strcmp(test_class_name, "ReencryptPlusExtraKeysTests") == 0)
  25.234 -        *test_suite = new ReencryptPlusExtraKeysTests(test_class_name, test_home);
  25.235 -    else if (strcmp(test_class_name, "MapAsn1Tests") == 0)
  25.236 -        *test_suite = new MapAsn1Tests(test_class_name, test_home);
  25.237 -    else if (strcmp(test_class_name, "DecorateTests") == 0)
  25.238 -        *test_suite = new DecorateTests(test_class_name, test_home);
  25.239 -    else if (strcmp(test_class_name, "MessageTwoPointOhTests") == 0)
  25.240 -        *test_suite = new MessageTwoPointOhTests(test_class_name, test_home);
  25.241 -    else if (strcmp(test_class_name, "CrashdumpTests") == 0)
  25.242 -        *test_suite = new CrashdumpTests(test_class_name, test_home);
  25.243      else if (strcmp(test_class_name, "StringpairListTests") == 0)
  25.244          *test_suite = new StringpairListTests(test_class_name, test_home);
  25.245 -    else if (strcmp(test_class_name, "EncryptForIdentityTests") == 0)
  25.246 -        *test_suite = new EncryptForIdentityTests(test_class_name, test_home);
  25.247      else if (strcmp(test_class_name, "TrustManipulationTests") == 0)
  25.248          *test_suite = new TrustManipulationTests(test_class_name, test_home);
  25.249      else if (strcmp(test_class_name, "SyncTests") == 0)
  25.250          *test_suite = new SyncTests(test_class_name, test_home);
  25.251 -    else if (strcmp(test_class_name, "AppleMailTests") == 0)
  25.252 -        *test_suite = new AppleMailTests(test_class_name, test_home);
  25.253 +    else if (strcmp(test_class_name, "EncryptAttachPrivateKeyTests") == 0)
  25.254 +        *test_suite = new EncryptAttachPrivateKeyTests(test_class_name, test_home);
  25.255 +    else if (strcmp(test_class_name, "BloblistTests") == 0)
  25.256 +        *test_suite = new BloblistTests(test_class_name, test_home);
  25.257 +    else if (strcmp(test_class_name, "KeyResetMessageTests") == 0)
  25.258 +        *test_suite = new KeyResetMessageTests(test_class_name, test_home);
  25.259 +    else if (strcmp(test_class_name, "SequenceTests") == 0)
  25.260 +        *test_suite = new SequenceTests(test_class_name, test_home);
  25.261 +    else if (strcmp(test_class_name, "TrustwordsTests") == 0)
  25.262 +        *test_suite = new TrustwordsTests(test_class_name, test_home);
  25.263 +    else if (strcmp(test_class_name, "RevokeRegenAttachTests") == 0)
  25.264 +        *test_suite = new RevokeRegenAttachTests(test_class_name, test_home);
  25.265 +    else if (strcmp(test_class_name, "EncryptMissingPrivateKeyTests") == 0)
  25.266 +        *test_suite = new EncryptMissingPrivateKeyTests(test_class_name, test_home);
  25.267 +    else if (strcmp(test_class_name, "PepSubjectReceivedTests") == 0)
  25.268 +        *test_suite = new PepSubjectReceivedTests(test_class_name, test_home);
  25.269 +    else if (strcmp(test_class_name, "KeyeditTests") == 0)
  25.270 +        *test_suite = new KeyeditTests(test_class_name, test_home);
  25.271 +    else if (strcmp(test_class_name, "MapAsn1Tests") == 0)
  25.272 +        *test_suite = new MapAsn1Tests(test_class_name, test_home);
  25.273 +    else if (strcmp(test_class_name, "PgpBinaryTests") == 0)
  25.274 +        *test_suite = new PgpBinaryTests(test_class_name, test_home);
  25.275 +    else if (strcmp(test_class_name, "DecryptAttachPrivateKeyTrustedTests") == 0)
  25.276 +        *test_suite = new DecryptAttachPrivateKeyTrustedTests(test_class_name, test_home);
  25.277 +    else if (strcmp(test_class_name, "MessageNullFromTests") == 0)
  25.278 +        *test_suite = new MessageNullFromTests(test_class_name, test_home);
  25.279 +    else if (strcmp(test_class_name, "MimeTests") == 0)
  25.280 +        *test_suite = new MimeTests(test_class_name, test_home);
  25.281 +    else if (strcmp(test_class_name, "PgpListKeysTests") == 0)
  25.282 +        *test_suite = new PgpListKeysTests(test_class_name, test_home);
  25.283 +    else if (strcmp(test_class_name, "NewUpdateIdAndMyselfTests") == 0)
  25.284 +        *test_suite = new NewUpdateIdAndMyselfTests(test_class_name, test_home);
  25.285 +    else if (strcmp(test_class_name, "EncryptForIdentityTests") == 0)
  25.286 +        *test_suite = new EncryptForIdentityTests(test_class_name, test_home);
  25.287 +    else if (strcmp(test_class_name, "CrashdumpTests") == 0)
  25.288 +        *test_suite = new CrashdumpTests(test_class_name, test_home);
  25.289 +    else if (strcmp(test_class_name, "CaseAndDotAddressTests") == 0)
  25.290 +        *test_suite = new CaseAndDotAddressTests(test_class_name, test_home);
  25.291 +    else if (strcmp(test_class_name, "LeastCommonDenomColorTests") == 0)
  25.292 +        *test_suite = new LeastCommonDenomColorTests(test_class_name, test_home);
  25.293 +    else if (strcmp(test_class_name, "ExternalRevokeTests") == 0)
  25.294 +        *test_suite = new ExternalRevokeTests(test_class_name, test_home);
  25.295 +    else if (strcmp(test_class_name, "UserIDAliasTests") == 0)
  25.296 +        *test_suite = new UserIDAliasTests(test_class_name, test_home);
  25.297  }
  25.298  
  25.299  void SuiteMaker::suitemaker_buildlist(const char** test_class_names, int num_to_run, const char* test_home, std::vector<Test::Suite*>& test_suites) {
    26.1 --- a/test/src/TestDriver.cc	Sat Sep 15 17:40:17 2018 +0200
    26.2 +++ b/test/src/TestDriver.cc	Fri Sep 28 10:36:44 2018 +0200
    26.3 @@ -1,7 +1,9 @@
    26.4  #include <stdlib.h>
    26.5  #include <cpptest.h>
    26.6  #include <cpptest-suite.h>
    26.7 -#include <cpptest-textoutput.h>
    26.8 +#include <cpptest-output.h>
    26.9 +#include "pEpTestOutput.h"
   26.10 +
   26.11  #include <string>
   26.12  #include <vector>
   26.13  #include <sys/stat.h>
   26.14 @@ -51,7 +53,7 @@
   26.15          test_runner->add(suite); 
   26.16      }
   26.17  
   26.18 -    Test::TextOutput output(Test::TextOutput::Verbose);
   26.19 -    return test_runner->run(output, false) ? 0 : 1;
   26.20 -    
   26.21 +    Test::Output* output = new Test::pEpTestOutput(); // blah
   26.22 +    return test_runner->run(*output, false) ? 0 : 1;
   26.23 +    delete(output);
   26.24  }
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/test/src/engine_tests/KeyResetMessageTests.cc	Fri Sep 28 10:36:44 2018 +0200
    27.3 @@ -0,0 +1,510 @@
    27.4 +// This file is under GNU General Public License 3.0
    27.5 +// see LICENSE.txt
    27.6 +
    27.7 +#include <stdlib.h>
    27.8 +#include <string>
    27.9 +#include <vector>
   27.10 +#include <unordered_map>
   27.11 +#include <assert.h>
   27.12 +
   27.13 +#include "pEpEngine.h"
   27.14 +#include "pEp_internal.h"
   27.15 +#include "mime.h"
   27.16 +#include "keymanagement.h"
   27.17 +
   27.18 +#include "test_util.h"
   27.19 +#include "EngineTestIndividualSuite.h"
   27.20 +#include "KeyResetMessageTests.h"
   27.21 +
   27.22 +using namespace std;
   27.23 +
   27.24 +const string KeyResetMessageTests::alice_user_id = PEP_OWN_USERID;
   27.25 +const string KeyResetMessageTests::bob_user_id = "BobId";    
   27.26 +const string KeyResetMessageTests::carol_user_id = "carolId";
   27.27 +const string KeyResetMessageTests::dave_user_id = "DaveId";
   27.28 +const string KeyResetMessageTests::erin_user_id = "ErinErinErin";
   27.29 +const string KeyResetMessageTests::fenris_user_id = "BadWolf";
   27.30 +
   27.31 +KeyResetMessageTests* KeyResetMessageTests::fake_this = NULL;
   27.32 +
   27.33 +KeyResetMessageTests::KeyResetMessageTests(string suitename, string test_home_dir) :
   27.34 +    EngineTestIndividualSuite::EngineTestIndividualSuite(suitename, test_home_dir) {
   27.35 +        
   27.36 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("KeyResetMessageTests::check_key_reset_message"),
   27.37 +                                                                      static_cast<Func>(&KeyResetMessageTests::check_key_reset_message)));
   27.38 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("KeyResetMessageTests::check_reset_key_and_notify"),
   27.39 +                                                                      static_cast<Func>(&KeyResetMessageTests::check_reset_key_and_notify)));
   27.40 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("KeyResetMessageTests::check_non_reset_receive_revoked"),
   27.41 +                                                                      static_cast<Func>(&KeyResetMessageTests::check_non_reset_receive_revoked)));
   27.42 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("KeyResetMessageTests::check_reset_receive_revoked"),
   27.43 +                                                                      static_cast<Func>(&KeyResetMessageTests::check_reset_receive_revoked)));
   27.44 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("KeyResetMessageTests::check_receive_message_to_revoked_key_from_unknown"),
   27.45 +                                                                      static_cast<Func>(&KeyResetMessageTests::check_receive_message_to_revoked_key_from_unknown)));
   27.46 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("KeyResetMessageTests::check_receive_message_to_revoked_key_from_contact"),
   27.47 +                                                                      static_cast<Func>(&KeyResetMessageTests::check_receive_message_to_revoked_key_from_contact)));                                                                      
   27.48 +    fake_this = this;                                                                  
   27.49 +    
   27.50 +    cached_messageToSend = &KeyResetMessageTests::message_send_callback;
   27.51 +}
   27.52 +
   27.53 +PEP_STATUS KeyResetMessageTests::message_send_callback(message* msg) {
   27.54 +    fake_this->m_queue.push_back(msg);
   27.55 +    return PEP_STATUS_OK;    
   27.56 +}
   27.57 +
   27.58 +void KeyResetMessageTests::setup() {
   27.59 +    EngineTestIndividualSuite::setup();
   27.60 +    m_queue.clear();
   27.61 +}
   27.62 +
   27.63 +void KeyResetMessageTests::send_setup() {
   27.64 +    // Setup own identity
   27.65 +    PEP_STATUS status = read_file_and_import_key(session,
   27.66 +                "test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc");
   27.67 +    assert(status == PEP_STATUS_OK);
   27.68 +    status = set_up_ident_from_scratch(session,
   27.69 +                "test_keys/priv/pep-test-alice-0x6FF00E97_priv.asc",
   27.70 +                "pep.test.alice@pep-project.org", alice_fpr, 
   27.71 +                alice_user_id.c_str(), "Alice in Wonderland", NULL, true
   27.72 +            );
   27.73 +    assert(status == PEP_STATUS_OK);
   27.74 +    
   27.75 +    status = set_up_ident_from_scratch(session,
   27.76 +                "test_keys/pub/pep-test-bob-0xC9C2EE39_pub.asc",
   27.77 +                "pep.test.bob@pep-project.org", NULL, bob_user_id.c_str(), "Bob's Burgers",
   27.78 +                NULL, false
   27.79 +            );
   27.80 +    assert(status == PEP_STATUS_OK);
   27.81 +            
   27.82 +    status = set_up_ident_from_scratch(session,
   27.83 +                "test_keys/pub/pep-test-carol-0x42A85A42_pub.asc",
   27.84 +                "pep-test-carol@pep-project.org", NULL, carol_user_id.c_str(), "Carol Burnett",
   27.85 +                NULL, false
   27.86 +            );
   27.87 +    assert(status == PEP_STATUS_OK);
   27.88 +    
   27.89 +    status = set_up_ident_from_scratch(session,
   27.90 +                "test_keys/pub/pep-test-dave-0xBB5BCCF6_pub.asc",
   27.91 +                "pep-test-dave@pep-project.org", NULL, dave_user_id.c_str(), 
   27.92 +                "David Hasselhoff (Germans Love Me)", NULL, false
   27.93 +            );
   27.94 +    assert(status == PEP_STATUS_OK);
   27.95 +
   27.96 +    status = set_up_ident_from_scratch(session,
   27.97 +                "test_keys/pub/pep-test-erin-0x9F8D7CBA_pub.asc",
   27.98 +                "pep-test-erin@pep-project.org", NULL, erin_user_id.c_str(), 
   27.99 +                "Éirinn go Brách", NULL, false
  27.100 +            );
  27.101 +    assert(status == PEP_STATUS_OK);
  27.102 +
  27.103 +    status = set_up_ident_from_scratch(session,
  27.104 +                "test_keys/pub/pep.test.fenris-0x4F3D2900_pub.asc",
  27.105 +                "pep.test.fenris@thisstilldoesntwork.lu", NULL, fenris_user_id.c_str(), 
  27.106 +                "Fenris Leto Hawke", NULL, false
  27.107 +            );
  27.108 +    assert(status == PEP_STATUS_OK);
  27.109 +}
  27.110 +
  27.111 +void KeyResetMessageTests::receive_setup() {
  27.112 +    PEP_STATUS status = read_file_and_import_key(session,
  27.113 +                "test_keys/pub/pep-test-bob-0xC9C2EE39_pub.asc");  
  27.114 +    assert(status == PEP_STATUS_OK);
  27.115 +    status = set_up_ident_from_scratch(session,
  27.116 +                "test_keys/priv/pep-test-bob-0xC9C2EE39_priv.asc",  
  27.117 +                "pep.test.bob@pep-project.org", bob_fpr, 
  27.118 +                bob_user_id.c_str(), "Robert Redford", NULL, true
  27.119 +            );
  27.120 +    assert(status == PEP_STATUS_OK);
  27.121 +    
  27.122 +    status = set_up_ident_from_scratch(session,
  27.123 +                "test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc",
  27.124 +                "pep.test.alice@pep-project.org", NULL, alice_user_id.c_str(), "Alice is tired of Bob",
  27.125 +                NULL, false
  27.126 +            );
  27.127 +    assert(status == PEP_STATUS_OK);    
  27.128 +}
  27.129 +
  27.130 +void KeyResetMessageTests::check_key_reset_message() {
  27.131 +    TEST_ASSERT(true);
  27.132 +}
  27.133 +
  27.134 +void KeyResetMessageTests::check_reset_key_and_notify() {
  27.135 +    send_setup();
  27.136 +    
  27.137 +    pEp_identity* from_ident = new_identity("pep.test.alice@pep-project.org", NULL, PEP_OWN_USERID, NULL);
  27.138 +    PEP_STATUS status = myself(session, from_ident); 
  27.139 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.140 +    TEST_ASSERT_MSG(from_ident->fpr && strcasecmp(from_ident->fpr, alice_fpr) == 0,
  27.141 +                    from_ident->fpr);
  27.142 +    TEST_ASSERT(from_ident->me);
  27.143 +    
  27.144 +    // "send" some messages to update the social graph entries
  27.145 +    identity_list* send_idents = 
  27.146 +        new_identity_list(
  27.147 +            new_identity("pep.test.bob@pep-project.org", 
  27.148 +                         NULL, bob_user_id.c_str(), "Bob's Burgers"));
  27.149 +                         
  27.150 +    identity_list_add(send_idents, new_identity("pep-test-carol@pep-project.org", NULL, NULL, NULL));    
  27.151 +    identity_list_add(send_idents, new_identity("pep-test-dave@pep-project.org", NULL, NULL, NULL)); 
  27.152 +    identity_list_add(send_idents, new_identity("pep-test-erin@pep-project.org", NULL, NULL, NULL)); 
  27.153 +    identity_list_add(send_idents, new_identity("pep.test.fenris@thisstilldoesntwork.lu", NULL, NULL, NULL)); 
  27.154 +
  27.155 +    identity_list* curr_ident;
  27.156 +    
  27.157 +    for (curr_ident = send_idents; curr_ident && curr_ident->ident; curr_ident = curr_ident->next) {
  27.158 +        status = update_identity(session, curr_ident->ident);
  27.159 +        if (strcmp(curr_ident->ident->user_id, bob_user_id.c_str()) == 0)
  27.160 +            continue;
  27.161 +        
  27.162 +        status = set_as_pEp_user(session, curr_ident->ident);
  27.163 +        TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.164 +    }
  27.165 +    
  27.166 +    cout << "Creating outgoing message to update DB" << endl;
  27.167 +    message* outgoing_msg = new_message(PEP_dir_outgoing);
  27.168 +    TEST_ASSERT(outgoing_msg);
  27.169 +    outgoing_msg->from = from_ident;
  27.170 +    outgoing_msg->to = send_idents;
  27.171 +    outgoing_msg->shortmsg = strdup("Well isn't THIS a useless message...");
  27.172 +    outgoing_msg->longmsg = strdup("Hi Mom...\n");
  27.173 +    outgoing_msg->attachments = new_bloblist(NULL, 0, "application/octet-stream", NULL);
  27.174 +    cout << "Message created.\n\n";
  27.175 +    cout << "Encrypting message as MIME multipart…\n";
  27.176 +    message* enc_outgoing_msg = nullptr;
  27.177 +    cout << "Calling encrypt_message()\n";
  27.178 +    status = encrypt_message(session, outgoing_msg, NULL, &enc_outgoing_msg, PEP_enc_PGP_MIME, 0);
  27.179 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
  27.180 +    TEST_ASSERT(enc_outgoing_msg);
  27.181 +    cout << "Message encrypted.\n";
  27.182 +        
  27.183 +    // If this all worked, we should have a list of recent guys in our DB which, when we reset Alice's 
  27.184 +    // key, will get sent some nice key reset messages.
  27.185 +    // But... we need to have one look like an older message. So. Time to mess with the DB.
  27.186 +    // Dave is our victim. Because I have a friend called Dave, who is actually a nice dude, but it amuses me.
  27.187 +    // (Note: said friend is NOT David Hasselhoff. To my knowledge. Hi Dave! (Addendum: Dave confirms he is
  27.188 +    // not Hasselhoff. But he wishes he were, sort of.))
  27.189 +    //
  27.190 +    // update identity
  27.191 +    //      set timestamp = 661008730
  27.192 +    //      where address = "pep-test-dave@pep-project.org"
  27.193 +    int int_result = sqlite3_exec(
  27.194 +        session->db,
  27.195 +        "update identity "
  27.196 +        "   set timestamp = 661008730 "
  27.197 +        "   where address = 'pep-test-dave@pep-project.org' ;",
  27.198 +        NULL,
  27.199 +        NULL,
  27.200 +        NULL
  27.201 +    );
  27.202 +    TEST_ASSERT(int_result == SQLITE_OK);
  27.203 +    
  27.204 +    status = key_reset(session, alice_fpr, from_ident);
  27.205 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
  27.206 +    TEST_ASSERT(m_queue.size() > 0);
  27.207 +    status = myself(session, from_ident);
  27.208 +    string new_fpr = from_ident->fpr;
  27.209 +    TEST_ASSERT_MSG((strcmp(alice_fpr, new_fpr.c_str()) != 0), new_fpr.c_str());
  27.210 +    
  27.211 +    unordered_map<string, bool> hashmap;
  27.212 +    hashmap[alice_user_id] = false;
  27.213 +    hashmap[bob_user_id] = false;
  27.214 +    hashmap[carol_user_id] = false;
  27.215 +    hashmap[dave_user_id] = false;
  27.216 +    hashmap[erin_user_id] = false;
  27.217 +    hashmap[fenris_user_id] = false;
  27.218 +    
  27.219 +    // Number of messages we SHOULD be sending.
  27.220 +    TEST_ASSERT(m_queue.size() == 4);
  27.221 +    
  27.222 +    for (vector<message*>::iterator it = m_queue.begin(); it != m_queue.end(); it++) {
  27.223 +        message* curr_sent_msg = *it;
  27.224 +        TEST_ASSERT(curr_sent_msg);
  27.225 +        TEST_ASSERT(curr_sent_msg->to);
  27.226 +        TEST_ASSERT(curr_sent_msg->to->ident);
  27.227 +        TEST_ASSERT(!(curr_sent_msg->to->next));
  27.228 +        pEp_identity* to = curr_sent_msg->to->ident;
  27.229 +        TEST_ASSERT(to);
  27.230 +        TEST_ASSERT(to->user_id);
  27.231 +        
  27.232 +        unordered_map<string, bool>::iterator jt = hashmap.find(to->user_id);
  27.233 +        
  27.234 +        TEST_ASSERT(jt != hashmap.end());
  27.235 +        hashmap[jt->first] = true;   
  27.236 +
  27.237 +        // Uncomment to regenerate received message - remember to update
  27.238 +        // alice_receive_reset_fpr        
  27.239 +        // if (strcmp(curr_sent_msg->to->ident->user_id, bob_user_id.c_str()) == 0) {
  27.240 +        //     char* bob_msg = NULL;
  27.241 +        //     mime_encode_message(curr_sent_msg, false, &bob_msg);
  27.242 +        //     cout << bob_msg;
  27.243 +        // }
  27.244 +        // else if (strcmp(curr_sent_msg->to->ident->user_id, fenris_user_id.c_str()) == 0) {
  27.245 +        //     char* fenris_msg = NULL;
  27.246 +        //     mime_encode_message(curr_sent_msg, false, &fenris_msg);
  27.247 +        //     cout << fenris_msg;
  27.248 +        // }
  27.249 +    }
  27.250 +    
  27.251 +    // MESSAGE LIST NOW INVALID.
  27.252 +    m_queue.clear();
  27.253 +    
  27.254 +    // Make sure we have messages only to desired recips
  27.255 +    TEST_ASSERT(hashmap[alice_user_id] == false);
  27.256 +    TEST_ASSERT(hashmap[bob_user_id] == true);
  27.257 +    TEST_ASSERT(hashmap[carol_user_id] == true);
  27.258 +    TEST_ASSERT(hashmap[dave_user_id] == false);
  27.259 +    TEST_ASSERT(hashmap[erin_user_id] == true);
  27.260 +    TEST_ASSERT(hashmap[fenris_user_id] == true);
  27.261 +}
  27.262 +
  27.263 +void KeyResetMessageTests::check_non_reset_receive_revoked() {
  27.264 +    receive_setup();
  27.265 +    pEp_identity* alice_ident = new_identity("pep.test.alice@pep-project.org", NULL,
  27.266 +                                            alice_user_id.c_str(), NULL);
  27.267 +                                            
  27.268 +    PEP_STATUS status = update_identity(session, alice_ident);
  27.269 +    TEST_ASSERT(status == PEP_STATUS_OK);
  27.270 +    TEST_ASSERT(strcmp(alice_fpr, alice_ident->fpr) == 0);
  27.271 +    
  27.272 +    string received_mail = slurp("test_files/398_reset_from_alice_to_bob.eml");
  27.273 +    char* decrypted_msg = NULL;
  27.274 +    char* modified_src = NULL;
  27.275 +    stringlist_t* keylist = NULL;
  27.276 +    PEP_rating rating;
  27.277 +    PEP_decrypt_flags_t flags;
  27.278 +    status = MIME_decrypt_message(session, received_mail.c_str(), received_mail.size(),
  27.279 +                                  &decrypted_msg, &keylist, &rating, &flags, &modified_src);
  27.280 +                                  
  27.281 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.282 +    TEST_ASSERT(keylist);
  27.283 +    if (keylist) // there's a test option to continue when asserts fail, so...
  27.284 +        TEST_ASSERT_MSG(strcmp(keylist->value, alice_receive_reset_fpr) == 0,
  27.285 +                        keylist->value);
  27.286 +    
  27.287 +    status = update_identity(session, alice_ident);
  27.288 +    TEST_ASSERT(alice_ident->fpr);
  27.289 +    TEST_ASSERT_MSG(strcmp(alice_receive_reset_fpr, alice_ident->fpr) == 0,
  27.290 +                    alice_ident->fpr);
  27.291 +    
  27.292 +    keylist = NULL;
  27.293 +
  27.294 +    free(keylist);    
  27.295 +}
  27.296 +
  27.297 +void KeyResetMessageTests::check_reset_receive_revoked() {
  27.298 +    PEP_STATUS status = set_up_ident_from_scratch(session,
  27.299 +                "test_keys/pub/pep.test.fenris-0x4F3D2900_pub.asc",
  27.300 +                "pep.test.fenris@thisstilldoesntwork.lu", NULL, fenris_user_id.c_str(), 
  27.301 +                "Fenris Leto Hawke", NULL, false
  27.302 +            );
  27.303 +    assert(status == PEP_STATUS_OK);
  27.304 +    status = set_up_ident_from_scratch(session,
  27.305 +                "test_keys/priv/pep.test.fenris-0x4F3D2900_priv.asc",
  27.306 +                "pep.test.fenris@thisstilldoesntwork.lu", NULL, fenris_user_id.c_str(), 
  27.307 +                "Fenris Leto Hawke", NULL, false
  27.308 +            );
  27.309 +    assert(status == PEP_STATUS_OK);
  27.310 +    
  27.311 +    status = set_up_ident_from_scratch(session,
  27.312 +                "test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc",
  27.313 +                "pep.test.alice@pep-project.org", NULL, alice_user_id.c_str(), "Alice is tired of Bob",
  27.314 +                NULL, false
  27.315 +            );
  27.316 +    assert(status == PEP_STATUS_OK);    
  27.317 +    
  27.318 +    pEp_identity* alice_ident = new_identity("pep.test.alice@pep-project.org", NULL,
  27.319 +                                            alice_user_id.c_str(), NULL);
  27.320 +                                            
  27.321 +    status = update_identity(session, alice_ident);
  27.322 +    TEST_ASSERT(status == PEP_STATUS_OK);
  27.323 +    TEST_ASSERT(strcmp(alice_fpr, alice_ident->fpr) == 0);
  27.324 +    
  27.325 +    string received_mail = slurp("test_files/398_reset_from_alice_to_fenris.eml");
  27.326 +    char* decrypted_msg = NULL;
  27.327 +    char* modified_src = NULL;
  27.328 +    stringlist_t* keylist = NULL;
  27.329 +    PEP_rating rating;
  27.330 +    PEP_decrypt_flags_t flags;
  27.331 +    status = MIME_decrypt_message(session, received_mail.c_str(), received_mail.size(),
  27.332 +                                  &decrypted_msg, &keylist, &rating, &flags, &modified_src);
  27.333 +                                  
  27.334 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.335 +    TEST_ASSERT(keylist);
  27.336 +    if (keylist) // there's a test option to continue when asserts fail, so...
  27.337 +        TEST_ASSERT_MSG(strcmp(keylist->value, alice_receive_reset_fpr) == 0,
  27.338 +                        keylist->value);
  27.339 +    
  27.340 +    status = update_identity(session, alice_ident);
  27.341 +    TEST_ASSERT(alice_ident->fpr);
  27.342 +    TEST_ASSERT_MSG(strcmp(alice_receive_reset_fpr, alice_ident->fpr) == 0,
  27.343 +                    alice_ident->fpr);
  27.344 +    
  27.345 +    keylist = NULL;
  27.346 +
  27.347 +    free(keylist);    
  27.348 +}
  27.349 +
  27.350 +void KeyResetMessageTests::create_msg_for_revoked_key() {
  27.351 +    PEP_STATUS status = set_up_ident_from_scratch(session,
  27.352 +                "test_keys/pub/pep-test-gabrielle-0xE203586C_pub.asc",
  27.353 +                "pep-test-gabrielle@pep-project.org", NULL, PEP_OWN_USERID, 
  27.354 +                "Gabi", NULL, false
  27.355 +            );
  27.356 +    assert(status == PEP_STATUS_OK);
  27.357 +    status = set_up_ident_from_scratch(session,
  27.358 +                "test_keys/priv/pep-test-gabrielle-0xE203586C_priv.asc",
  27.359 +                "pep-test-gabrielle@pep-project.org", NULL, PEP_OWN_USERID, 
  27.360 +                "Gabi", NULL, false
  27.361 +            );
  27.362 +    assert(status == PEP_STATUS_OK);
  27.363 +    
  27.364 +    status = set_up_ident_from_scratch(session,
  27.365 +                "test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc",
  27.366 +                "pep.test.alice@pep-project.org", NULL, "AliceOther", "Alice is tired of Bob",
  27.367 +                NULL, false
  27.368 +            );
  27.369 +    
  27.370 +    pEp_identity* from_ident = new_identity("pep-test-gabrielle@pep-project.org", NULL, PEP_OWN_USERID, NULL);
  27.371 +    status = myself(session, from_ident); 
  27.372 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.373 +    TEST_ASSERT_MSG(from_ident->fpr && strcasecmp(from_ident->fpr, "906C9B8349954E82C5623C3C8C541BD4E203586C") == 0,
  27.374 +                    from_ident->fpr);
  27.375 +    TEST_ASSERT(from_ident->me);
  27.376 +    
  27.377 +    // "send" some messages to update the social graph entries
  27.378 +    identity_list* send_idents = 
  27.379 +        new_identity_list(
  27.380 +            new_identity("pep.test.alice@pep-project.org", NULL, "AliceOther", NULL));
  27.381 +    status = update_identity(session, send_idents->ident);
  27.382 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));    
  27.383 +    status = set_as_pEp_user(session, send_idents->ident);
  27.384 +                             
  27.385 +    message* outgoing_msg = new_message(PEP_dir_outgoing);
  27.386 +    TEST_ASSERT(outgoing_msg);
  27.387 +    outgoing_msg->from = from_ident;
  27.388 +    outgoing_msg->to = send_idents;
  27.389 +    outgoing_msg->shortmsg = strdup("Well isn't THIS a useless message...");
  27.390 +    outgoing_msg->longmsg = strdup("Hi Mom...\n");
  27.391 +    outgoing_msg->attachments = new_bloblist(NULL, 0, "application/octet-stream", NULL);
  27.392 +    cout << "Message created.\n\n";
  27.393 +    cout << "Encrypting message as MIME multipart…\n";
  27.394 +    message* enc_outgoing_msg = nullptr;
  27.395 +    cout << "Calling encrypt_message()\n";
  27.396 +    status = encrypt_message(session, outgoing_msg, NULL, &enc_outgoing_msg, PEP_enc_PGP_MIME, 0);
  27.397 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
  27.398 +    TEST_ASSERT(enc_outgoing_msg);
  27.399 +    cout << "Message encrypted.\n";    
  27.400 +    char* outstring = NULL;
  27.401 +    mime_encode_message(enc_outgoing_msg, false, &outstring);
  27.402 +    cout << outstring << endl;
  27.403 +    free_message(enc_outgoing_msg);
  27.404 +    free(outstring);
  27.405 +}
  27.406 +
  27.407 +void KeyResetMessageTests::check_receive_message_to_revoked_key_from_unknown() {
  27.408 +    // create_msg_for_revoked_key(); // call to recreate msg
  27.409 +    send_setup();
  27.410 +    pEp_identity* from_ident = new_identity("pep.test.alice@pep-project.org", NULL, PEP_OWN_USERID, NULL);
  27.411 +    PEP_STATUS status = myself(session, from_ident); 
  27.412 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.413 +    TEST_ASSERT_MSG(from_ident->fpr && strcasecmp(from_ident->fpr, alice_fpr) == 0,
  27.414 +                    from_ident->fpr);
  27.415 +    TEST_ASSERT(from_ident->me);
  27.416 +
  27.417 +    status = key_reset(session, alice_fpr, from_ident);
  27.418 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
  27.419 +    m_queue.clear();
  27.420 +    
  27.421 +    string received_mail = slurp("test_files/398_gabrielle_to_alice.eml");
  27.422 +    char* decrypted_msg = NULL;
  27.423 +    char* modified_src = NULL;
  27.424 +    stringlist_t* keylist = NULL;
  27.425 +    PEP_rating rating;
  27.426 +    PEP_decrypt_flags_t flags;
  27.427 +    status = MIME_decrypt_message(session, received_mail.c_str(), received_mail.size(),
  27.428 +                                  &decrypted_msg, &keylist, &rating, &flags, &modified_src);
  27.429 +    TEST_ASSERT(m_queue.size() == 0);
  27.430 +    free(decrypted_msg);
  27.431 +    free(modified_src);
  27.432 +    free_stringlist(keylist);
  27.433 +    free_identity(from_ident);
  27.434 +}
  27.435 +
  27.436 +void KeyResetMessageTests::check_receive_message_to_revoked_key_from_contact() {
  27.437 +    // create_msg_for_revoked_key(); // call to recreate msg
  27.438 +    send_setup();
  27.439 +    pEp_identity* from_ident = new_identity("pep.test.alice@pep-project.org", NULL, PEP_OWN_USERID, NULL);
  27.440 +    PEP_STATUS status = myself(session, from_ident); 
  27.441 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.442 +    TEST_ASSERT_MSG(from_ident->fpr && strcasecmp(from_ident->fpr, alice_fpr) == 0,
  27.443 +                    from_ident->fpr);
  27.444 +    TEST_ASSERT(from_ident->me);
  27.445 +
  27.446 +    // Send Gabrielle a message
  27.447 +    identity_list* send_idents = new_identity_list(new_identity("pep-test-gabrielle@pep-project.org", NULL, "Gabi", "Gabi"));
  27.448 +    cout << "Creating outgoing message to update DB" << endl;
  27.449 +    message* outgoing_msg = new_message(PEP_dir_outgoing);
  27.450 +    TEST_ASSERT(outgoing_msg);
  27.451 +    outgoing_msg->from = from_ident;
  27.452 +    outgoing_msg->to = send_idents;
  27.453 +    outgoing_msg->shortmsg = strdup("Well isn't THIS a useless message...");
  27.454 +    outgoing_msg->longmsg = strdup("Hi Mom...\n");
  27.455 +    outgoing_msg->attachments = new_bloblist(NULL, 0, "application/octet-stream", NULL);
  27.456 +    cout << "Message created.\n\n";
  27.457 +    cout << "Encrypting message as MIME multipart…\n";
  27.458 +    message* enc_outgoing_msg = nullptr;
  27.459 +    cout << "Calling encrypt_message()\n";
  27.460 +    status = encrypt_message(session, outgoing_msg, NULL, &enc_outgoing_msg, PEP_enc_PGP_MIME, 0);
  27.461 +    TEST_ASSERT_MSG((status == PEP_UNENCRYPTED), tl_status_string(status));
  27.462 +    //
  27.463 +    cout << "Message created." << endl;
  27.464 +    
  27.465 +    // Make the update have occurred earlier, so we don't notify her
  27.466 +    // (We have no key for her yet anyway!)
  27.467 +    int int_result = sqlite3_exec(
  27.468 +        session->db,
  27.469 +        "update identity "
  27.470 +        "   set timestamp = 661008730 "
  27.471 +        "   where address = 'pep-test-gabrielle@pep-project.org' ;",
  27.472 +        NULL,
  27.473 +        NULL,
  27.474 +        NULL
  27.475 +    );
  27.476 +    TEST_ASSERT(int_result == SQLITE_OK);
  27.477 +
  27.478 +    status = key_reset(session, alice_fpr, from_ident);
  27.479 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
  27.480 +    TEST_ASSERT(m_queue.size() == 0);
  27.481 +    m_queue.clear();
  27.482 +
  27.483 +    // Now we get mail from Gabi, who only has our old key AND has become
  27.484 +    // a pEp user in the meantime...
  27.485 +    string received_mail = slurp("test_files/398_gabrielle_to_alice.eml");
  27.486 +    char* decrypted_msg = NULL;
  27.487 +    char* modified_src = NULL;
  27.488 +    stringlist_t* keylist = NULL;
  27.489 +    PEP_rating rating;
  27.490 +    PEP_decrypt_flags_t flags;
  27.491 +    status = MIME_decrypt_message(session, received_mail.c_str(), received_mail.size(),
  27.492 +                                  &decrypted_msg, &keylist, &rating, &flags, &modified_src);
  27.493 +    
  27.494 +    TEST_ASSERT(m_queue.size() == 1);
  27.495 +    vector<message*>::iterator it = m_queue.begin();
  27.496 +    message* reset_msg = *it;
  27.497 +    TEST_ASSERT(reset_msg);    
  27.498 +    TEST_ASSERT(reset_msg->from);    
  27.499 +    TEST_ASSERT(reset_msg->to);    
  27.500 +    TEST_ASSERT(reset_msg->to->ident);    
  27.501 +    TEST_ASSERT(strcmp(reset_msg->to->ident->address, "pep-test-gabrielle@pep-project.org") == 0);
  27.502 +    TEST_ASSERT(strcmp(reset_msg->to->ident->fpr, "906C9B8349954E82C5623C3C8C541BD4E203586C") == 0);    
  27.503 +    TEST_ASSERT(strcmp(reset_msg->from->fpr, alice_fpr) != 0);
  27.504 +    TEST_ASSERT(keylist);
  27.505 +    TEST_ASSERT(keylist->value);
  27.506 +    TEST_ASSERT(strcmp(keylist->value, alice_fpr) != 0);
  27.507 +    TEST_ASSERT(keylist->next);
  27.508 +    if (strcmp(keylist->next->value, "906C9B8349954E82C5623C3C8C541BD4E203586C") != 0)
  27.509 +        TEST_ASSERT(keylist->next->next && 
  27.510 +                    strcmp(keylist->next->value, 
  27.511 +                           "906C9B8349954E82C5623C3C8C541BD4E203586C") == 0);
  27.512 +    TEST_ASSERT(true);
  27.513 +}
    28.1 --- a/test/src/engine_tests/LeastColorGroupTests.cc	Sat Sep 15 17:40:17 2018 +0200
    28.2 +++ b/test/src/engine_tests/LeastColorGroupTests.cc	Fri Sep 28 10:36:44 2018 +0200
    28.3 @@ -57,7 +57,6 @@
    28.4      pEp_identity * sender1 = new_identity("pep.color.test.V@kgrothoff.org",
    28.5                                            NULL, "TOFU_pep.color.test.V@kgrothoff.org",
    28.6                                            "Pep Color Test V (sender)");
    28.7 -    
    28.8      status = update_identity(session, sender1);
    28.9      trust_personal_key(session, sender1);
   28.10      status = update_identity(session, sender1);
    29.1 --- a/test/src/engine_tests/LeastCommonDenomColorTests.cc	Sat Sep 15 17:40:17 2018 +0200
    29.2 +++ b/test/src/engine_tests/LeastCommonDenomColorTests.cc	Fri Sep 28 10:36:44 2018 +0200
    29.3 @@ -26,7 +26,7 @@
    29.4  }
    29.5  
    29.6  void LeastCommonDenomColorTests::check_least_common_denom_color() {
    29.7 -        
    29.8 +
    29.9      const char* mailfile = "test_mails/Test_Message_JSON-21_Color_Problems.eml";
   29.10              
   29.11      // import keys
   29.12 @@ -137,5 +137,4 @@
   29.13      dest_msg = nullptr;
   29.14      keylist = nullptr;
   29.15      rating = PEP_rating_unreliable;
   29.16 -    
   29.17  }
    30.1 --- a/test/src/engine_tests/MessageApiTests.cc	Sat Sep 15 17:40:17 2018 +0200
    30.2 +++ b/test/src/engine_tests/MessageApiTests.cc	Fri Sep 28 10:36:44 2018 +0200
    30.3 @@ -26,7 +26,6 @@
    30.4  }
    30.5  
    30.6  void MessageApiTests::check_message_api() {
    30.7 -
    30.8      cout << "Importing Alice's key " << endl;
    30.9      const string alice_pub_key = slurp("test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc");
   30.10      const string alice_priv_key = slurp("test_keys/priv/pep-test-alice-0x6FF00E97_priv.asc");
   30.11 @@ -221,5 +220,5 @@
   30.12      cout << "done.\n";
   30.13  
   30.14      free(enc_msg);
   30.15 -    free(dec_msg);
   30.16 +    free(dec_msg);    
   30.17  }
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/test/src/engine_tests/MessageNullFromTests.cc	Fri Sep 28 10:36:44 2018 +0200
    31.3 @@ -0,0 +1,124 @@
    31.4 +// This file is under GNU General Public License 3.0
    31.5 +// see LICENSE.txt
    31.6 +
    31.7 +#include <stdlib.h>
    31.8 +#include <string>
    31.9 +
   31.10 +#include <assert.h>
   31.11 +
   31.12 +#include "pEpEngine.h"
   31.13 +#include "test_util.h"
   31.14 +
   31.15 +#include "EngineTestIndividualSuite.h"
   31.16 +#include "MessageNullFromTests.h"
   31.17 +
   31.18 +using namespace std;
   31.19 +
   31.20 +MessageNullFromTests::MessageNullFromTests(string suitename, string test_home_dir) :
   31.21 +    EngineTestIndividualSuite::EngineTestIndividualSuite(suitename, test_home_dir) {
   31.22 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("MessageNullFromTests::check_message_null_from_no_header_key_unencrypted"),
   31.23 +                                                                      static_cast<Func>(&MessageNullFromTests::check_message_null_from_header_key_unencrypted)));
   31.24 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("MessageNullFromTests::check_message_null_from_no_header_key_unencrypted"),
   31.25 +                                                                          static_cast<Func>(&MessageNullFromTests::check_message_null_from_header_key_unencrypted)));                                                                  
   31.26 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("MessageNullFromTests::check_message_null_from_encrypted_not_signed"),
   31.27 +                                                                          static_cast<Func>(&MessageNullFromTests::check_message_null_from_encrypted_not_signed)));                                                                  
   31.28 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("MessageNullFromTests::check_message_null_from_encrypted_and_signed"),
   31.29 +                                                                          static_cast<Func>(&MessageNullFromTests::check_message_null_from_encrypted_and_signed)));                                                                                                                                            
   31.30 +}
   31.31 +
   31.32 +void MessageNullFromTests::import_alice_pub() {
   31.33 +    const string alice_pub_key = slurp("test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc");
   31.34 +    PEP_STATUS status = import_key(session, alice_pub_key.c_str(), alice_pub_key.length(), NULL);
   31.35 +    assert(status == PEP_STATUS_OK);
   31.36 +}
   31.37 +
   31.38 +void MessageNullFromTests::import_bob_pair_and_set_own() {
   31.39 +    const string bob_pub_key = slurp("test_keys/pub/pep-test-bob-0xC9C2EE39_pub.asc");
   31.40 +    const string bob_priv_key = slurp("test_keys/priv/pep-test-bob-0xC9C2EE39_priv.asc");
   31.41 +    PEP_STATUS status = import_key(session, bob_pub_key.c_str(), bob_pub_key.length(), NULL);
   31.42 +    assert(status == PEP_STATUS_OK);
   31.43 +    status = import_key(session, bob_priv_key.c_str(), bob_priv_key.length(), NULL);
   31.44 +    assert(status == PEP_STATUS_OK);
   31.45 +}
   31.46 +
   31.47 +void MessageNullFromTests::setup() {
   31.48 +    EngineTestIndividualSuite::setup();
   31.49 +    import_bob_pair_and_set_own();
   31.50 +}
   31.51 +
   31.52 +void MessageNullFromTests::check_message_null_from_no_header_key_unencrypted() {
   31.53 +    string null_from_msg = slurp("test_files/432_no_from_2.eml");
   31.54 +    cout << null_from_msg << endl;
   31.55 +    stringlist_t* keylist = NULL;
   31.56 +    PEP_decrypt_flags_t flags;
   31.57 +    PEP_rating rating;
   31.58 +    char* mime_plaintext = NULL;
   31.59 +    char* modified_src = NULL;
   31.60 +    PEP_STATUS status = MIME_decrypt_message(session, null_from_msg.c_str(),
   31.61 +                                             null_from_msg.size(),
   31.62 +                                             &mime_plaintext,
   31.63 +                                             &keylist,
   31.64 +                                             &rating,
   31.65 +                                             &flags,
   31.66 +                                             &modified_src);
   31.67 +    TEST_ASSERT_MSG(status == PEP_UNENCRYPTED, tl_status_string(status));                                         
   31.68 +}
   31.69 +
   31.70 +void MessageNullFromTests::check_message_null_from_header_key_unencrypted() {
   31.71 +    string null_from_msg = slurp("test_files/432_no_from.eml");
   31.72 +    cout << null_from_msg << endl;
   31.73 +    stringlist_t* keylist = NULL;
   31.74 +    PEP_decrypt_flags_t flags;
   31.75 +    PEP_rating rating;
   31.76 +    char* mime_plaintext = NULL;
   31.77 +    char* modified_src = NULL;
   31.78 +    PEP_STATUS status = MIME_decrypt_message(session, null_from_msg.c_str(),
   31.79 +                                             null_from_msg.size(),
   31.80 +                                             &mime_plaintext,
   31.81 +                                             &keylist,
   31.82 +                                             &rating,
   31.83 +                                             &flags,
   31.84 +                                             &modified_src);
   31.85 +    TEST_ASSERT_MSG(status == PEP_UNENCRYPTED, tl_status_string(status));                                         
   31.86 +}
   31.87 +
   31.88 +void MessageNullFromTests::check_message_null_from_encrypted_not_signed() {
   31.89 +    import_alice_pub();
   31.90 +    string null_from_msg = slurp("test_files/432_no_from_encrypted_not_signed.eml");
   31.91 +    cout << null_from_msg << endl;
   31.92 +    stringlist_t* keylist = NULL;
   31.93 +    PEP_decrypt_flags_t flags;
   31.94 +    PEP_rating rating;
   31.95 +    char* mime_plaintext = NULL;
   31.96 +    char* modified_src = NULL;
   31.97 +    PEP_STATUS status = MIME_decrypt_message(session, null_from_msg.c_str(),
   31.98 +                                             null_from_msg.size(),
   31.99 +                                             &mime_plaintext,
  31.100 +                                             &keylist,
  31.101 +                                             &rating,
  31.102 +                                             &flags,
  31.103 +                                             &modified_src);
  31.104 +    TEST_ASSERT_MSG(status == PEP_DECRYPTED, tl_status_string(status));                                         
  31.105 +    TEST_ASSERT(mime_plaintext);
  31.106 +}
  31.107 +
  31.108 +void MessageNullFromTests::check_message_null_from_encrypted_and_signed() {
  31.109 +    import_alice_pub();    
  31.110 +    string null_from_msg = slurp("test_files/432_no_from_encrypted_and_signed.eml");
  31.111 +    cout << null_from_msg << endl;
  31.112 +    stringlist_t* keylist = NULL;
  31.113 +    PEP_decrypt_flags_t flags;
  31.114 +    PEP_rating rating;
  31.115 +    char* mime_plaintext = NULL;
  31.116 +    char* modified_src = NULL;
  31.117 +    PEP_STATUS status = MIME_decrypt_message(session, null_from_msg.c_str(),
  31.118 +                                             null_from_msg.size(),
  31.119 +                                             &mime_plaintext,
  31.120 +                                             &keylist,
  31.121 +                                             &rating,
  31.122 +                                             &flags,
  31.123 +                                             &modified_src);
  31.124 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));                                         
  31.125 +    TEST_ASSERT(mime_plaintext);
  31.126 +}
  31.127 +
    32.1 --- a/test/src/engine_tests/MistrustUndoTests.cc	Sat Sep 15 17:40:17 2018 +0200
    32.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.3 @@ -1,84 +0,0 @@
    32.4 -// This file is under GNU General Public License 3.0
    32.5 -// see LICENSE.txt
    32.6 -
    32.7 -#include <stdlib.h>
    32.8 -#include <string>
    32.9 -#include <cstring>
   32.10 -#include <time.h>
   32.11 -#include <iostream>
   32.12 -#include <fstream>
   32.13 -
   32.14 -#include "pEpEngine.h"
   32.15 -#include "platform.h"
   32.16 -#include "mime.h"
   32.17 -#include "message_api.h"
   32.18 -#include "test_util.h"
   32.19 -
   32.20 -#include <cpptest.h>
   32.21 -#include "EngineTestSessionSuite.h"
   32.22 -#include "MistrustUndoTests.h"
   32.23 -
   32.24 -using namespace std;
   32.25 -
   32.26 -MistrustUndoTests::MistrustUndoTests(string suitename, string test_home_dir) :
   32.27 -    EngineTestSessionSuite::EngineTestSessionSuite(suitename, test_home_dir) {
   32.28 -    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("MistrustUndoTests::check_mistrust_undo"),
   32.29 -                                                                      static_cast<Func>(&MistrustUndoTests::check_mistrust_undo)));
   32.30 -}
   32.31 -
   32.32 -void MistrustUndoTests::check_mistrust_undo() {
   32.33 -    PEP_STATUS status = PEP_STATUS_OK;
   32.34 -
   32.35 -    cout << "importing key 0x39E5DAB5." << endl;
   32.36 -    const string pub_key = slurp("test_keys/pub/mistrust.undo.test-0x39E5DAB5_pub.asc");
   32.37 -
   32.38 -    TEST_ASSERT_MSG((pub_key.length() != 0), "pub_key.length() != 0");
   32.39 -    
   32.40 -    PEP_STATUS statuspub = import_key(session, pub_key.c_str(), pub_key.length(), NULL);
   32.41 -    TEST_ASSERT_MSG((statuspub == PEP_STATUS_OK), "statuspub == PEP_STATUS_OK");
   32.42 -    cout << "Key imported." << endl << endl;
   32.43 -    
   32.44 -    cout << "Setting up identity for mistrust.undo.test@pep-project.org and making comm_type PEP_ct_pEp."  << endl;
   32.45 -    pEp_identity* recip1 = new_identity("mistrust.undo.test@pep-project.org", NULL, "TOFU_mistrust.undo.test@pep-project.org", "Mistrust Undo");
   32.46 -    status = update_identity(session,recip1);
   32.47 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   32.48 -    TEST_ASSERT_MSG((strcmp(recip1->fpr, "BACC7A60A88A39A25D99B4A545D7542F39E5DAB5") == 0), "strcmp(recip1->fpr, \"BACC7A60A88A39A25D99B4A545D7542F39E5DAB5\") == 0");
   32.49 -    
   32.50 -    // First, we need the fpr to be in the DB system.
   32.51 -    status = set_identity(session,recip1);
   32.52 -    // Then we update the trust.
   32.53 -    // This is not an external function. We use it to expedite the test since we don't do a sync exchange here.
   32.54 -    status = update_trust_for_fpr(session, recip1->fpr, PEP_ct_pEp);
   32.55 -    // Then we retrieve the new trust.
   32.56 -    status = update_identity(session,recip1);
   32.57 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   32.58 -    TEST_ASSERT_MSG((recip1->comm_type == PEP_ct_pEp), "recip1->comm_type == PEP_ct_pEp");
   32.59 -    TEST_ASSERT_MSG((strcmp(recip1->fpr, "BACC7A60A88A39A25D99B4A545D7542F39E5DAB5") == 0), "strcmp(recip1->fpr, \"BACC7A60A88A39A25D99B4A545D7542F39E5DAB5\") == 0");
   32.60 -    cout << "mistrust.undo.test@pep-project.org set up and comm_type is PEP_ct_pEp."  << endl << endl;
   32.61 -
   32.62 -    // Ok, mistrust away
   32.63 -    cout << "Mistrusting mistrust.undo.test@pep-project.org (BACC7A60A88A39A25D99B4A545D7542F39E5DAB5)."  << endl;   
   32.64 -    status = key_mistrusted(session, recip1);
   32.65 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   32.66 -    status = update_identity(session,recip1);
   32.67 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   32.68 -    TEST_ASSERT_MSG((recip1->comm_type == PEP_ct_key_not_found), "recip1->comm_type == PEP_ct_key_not_found");
   32.69 -    recip1->fpr = strdup("BACC7A60A88A39A25D99B4A545D7542F39E5DAB5");
   32.70 -    status = get_trust(session, recip1);
   32.71 -    TEST_ASSERT_MSG((recip1->comm_type == PEP_ct_mistrusted), "recip1->comm_type == PEP_ct_mistrusted");
   32.72 -     
   32.73 -    cout << "Mistrusted mistrust.undo.test@pep-project.org (BACC7A60A88A39A25D99B4A545D7542F39E5DAB5) and comm_type IN DB set to PEP_ct_mistrusted)." << endl  << endl;    
   32.74 -    
   32.75 -    cout << "Undo mistrust (restore identity and trust in DB)" << endl;
   32.76 -    // Undo it
   32.77 -    status = undo_last_mistrust(session);
   32.78 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   32.79 -    status = update_identity(session, recip1);
   32.80 -    TEST_ASSERT_MSG((recip1->comm_type == PEP_ct_pEp), "recip1->comm_type == PEP_ct_pEp");
   32.81 -    TEST_ASSERT_MSG((strcmp(recip1->fpr, "BACC7A60A88A39A25D99B4A545D7542F39E5DAB5") == 0), "strcmp(recip1->fpr, \"BACC7A60A88A39A25D99B4A545D7542F39E5DAB5\") == 0");
   32.82 -    cout << "Undo mistrust (restore identity and trust in DB) - trust is now PEP_ct_pEp." << endl << endl;
   32.83 -
   32.84 -    cout << "Success!!!" << endl << endl;
   32.85 -    
   32.86 -    free_identity(recip1);
   32.87 -}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/test/src/pEpTestOutput.cc	Fri Sep 28 10:36:44 2018 +0200
    33.3 @@ -0,0 +1,98 @@
    33.4 +#include <cpptest.h>
    33.5 +#include <iostream>
    33.6 +#include <iomanip>
    33.7 +#include <vector>
    33.8 +#include <string>
    33.9 +#include <cstring>
   33.10 +
   33.11 +#include "pEpTestOutput.h"
   33.12 +using namespace std;
   33.13 +
   33.14 +namespace Test {
   33.15 +	pEpTestOutput::pEpTestOutput() : _total_failed(0), _total_tests(0) {}
   33.16 +    
   33.17 +    void pEpTestOutput::outputCorrectPercentage(int num_tests, int failures, int width) {
   33.18 +        cout << setw(width);
   33.19 +        if (num_tests) {
   33.20 +            double percentage = ((num_tests - failures) / (double)num_tests) * 100;
   33.21 +            cout << std::fixed << setprecision(1) << percentage << "\%"; 
   33.22 +        }
   33.23 +        else 
   33.24 +            cout << "N/A";
   33.25 +    }
   33.26 +    	
   33.27 +	void pEpTestOutput::finished(int tests, const Test::Time& time) {
   33.28 +        cout << huge_sepline << endl;
   33.29 +        string header = "FULL TEST RUN RESULTS:";
   33.30 +        cout << alt_sepline << left << setw(header.size()) << header;
   33.31 +        cout << right << setw(56 - header.size()) << "+" << endl;
   33.32 +        cout << right << setw(30) << "Number of tests run: " << setw(7) << tests << setw(19) << "+" << endl;
   33.33 +        cout << right << setw(30) << "Tests failed: " << setw(7) << _total_failed << setw(19) << "+" << endl;
   33.34 +        cout << right << setw(30) << "Pass percentage: ";
   33.35 +        outputCorrectPercentage(_total_tests, _total_failed, 7);
   33.36 +        cout << setw(18) << "+" << endl;
   33.37 +        cout << setw(56) << "+" << endl;
   33.38 +        string finalstr = std::to_string(tests) + " tests run in " + std::to_string(time.seconds()) + "." + std::to_string(time.microseconds()) + " seconds.";
   33.39 +        int remlen = 56 - finalstr.size();
   33.40 +        cout << left << setw(finalstr.size()) << finalstr << right << setw(remlen) << "+" << endl;
   33.41 +        cout << alt_sepline << endl;
   33.42 +	}
   33.43 +	
   33.44 +	void pEpTestOutput::suite_start(int tests, const string& name) {
   33.45 +        _suite_failed = 0;
   33.46 +        _suite_name = name;
   33.47 +        _suite_total = 0;
   33.48 +        if (tests > 0) {
   33.49 +            cout << endl << huge_sepline;
   33.50 +            cout << "BEGIN TEST SUITE: " << name << endl << endl;
   33.51 +        }
   33.52 +	}
   33.53 +	
   33.54 +	void pEpTestOutput::suite_end(int tests, const string& name, const Test::Time& time)
   33.55 +	{
   33.56 +        if (tests > 0) {
   33.57 +            cout << endl << "Suite results:" << endl; 
   33.58 +            cout << right << setw(30) << "Number of tests run: " << setw(7) << tests << endl;
   33.59 +            cout << right << setw(30) << "Tests failed: " << setw(7) << _suite_failed << endl;
   33.60 +            cout << right << setw(30) << "Pass percentage: ";
   33.61 +            outputCorrectPercentage(_suite_total, _suite_failed, 7);
   33.62 +            cout << endl << endl;
   33.63 +            cout << tests << " tests run in " << time << " seconds." << endl;
   33.64 +            cout << endl;
   33.65 +            cout << "END TEST SUITE: " << name << endl;
   33.66 +        }
   33.67 +	}
   33.68 +    
   33.69 +	void pEpTestOutput::test_start(const std::string& name) {
   33.70 +        _test_name = name;
   33.71 +        cout << med_sepline;
   33.72 +        cout << "Begin test " << name << endl;
   33.73 +        cout << lil_sepline;
   33.74 +        _test_errors.clear();
   33.75 +    }
   33.76 +    void pEpTestOutput::test_end(const string& name, bool ok, const Test::Time&) {
   33.77 +	    if (!ok) {
   33.78 +            _suite_failed++;
   33.79 +            _total_failed++;
   33.80 +            cout << endl << endl << alt_sepline;
   33.81 +            cout << "*** Test " << name << " failed!" << endl;
   33.82 +            vector<Source>::iterator it;
   33.83 +            for (it = _test_errors.begin(); it != _test_errors.end(); it++) {
   33.84 +                Source src = *it;
   33.85 +                cout << lil_sepline;
   33.86 +                cout << left << setw(25) << "*** Assert location: " << src.file() << ":" << src.line() << endl;
   33.87 +                cout << left << setw(25) << "*** Message: " << src.message() << endl;                
   33.88 +            }
   33.89 +            cout << alt_sepline << endl;
   33.90 +        }
   33.91 +        _total_tests++;
   33.92 +        _suite_total++;
   33.93 +
   33.94 +        cout << "End test " << name << endl;
   33.95 +        cout << med_sepline;        
   33.96 +	}
   33.97 +	
   33.98 +	void pEpTestOutput::assertment(const Source& s) {
   33.99 +		_test_errors.push_back(s);
  33.100 +	}
  33.101 +}
  33.102 \ No newline at end of file
    34.1 --- a/test/src/util/test_util.cc	Sat Sep 15 17:40:17 2018 +0200
    34.2 +++ b/test/src/util/test_util.cc	Fri Sep 28 10:36:44 2018 +0200
    34.3 @@ -2,6 +2,7 @@
    34.4  #include "pEpEngine.h"
    34.5  #include "pEp_internal.h"
    34.6  #include "message_api.h"
    34.7 +#include "test_util.h"
    34.8  
    34.9  #include <fstream>
   34.10  #include <sstream>
   34.11 @@ -13,6 +14,58 @@
   34.12  #include <unistd.h>
   34.13  #include <ftw.h>
   34.14  
   34.15 +PEP_STATUS read_file_and_import_key(PEP_SESSION session, const char* fname) {
   34.16 +    const std::string key = slurp(fname);
   34.17 +    PEP_STATUS status = (key.empty() ? PEP_KEY_NOT_FOUND : PEP_STATUS_OK);
   34.18 +    if (status == PEP_STATUS_OK)
   34.19 +        status = import_key(session, key.c_str(), key.size(), NULL);
   34.20 +    return status;    
   34.21 +}
   34.22 +
   34.23 +PEP_STATUS set_up_ident_from_scratch(PEP_SESSION session,
   34.24 +                                     const char* key_fname,
   34.25 +                                     const char* address,
   34.26 +                                     const char* fpr,
   34.27 +                                     const char* user_id,
   34.28 +                                     const char* username,
   34.29 +                                     pEp_identity** ret_ident,
   34.30 +                                     bool is_priv) {
   34.31 +    PEP_STATUS status = read_file_and_import_key(session,key_fname);
   34.32 +    if (status != PEP_STATUS_OK)
   34.33 +        return status;
   34.34 +    
   34.35 +    pEp_identity* ident = new_identity(address, fpr, user_id, username);
   34.36 +    if (is_priv && fpr) {
   34.37 +        status = set_own_key(session, ident, fpr);
   34.38 +        if (status == PEP_STATUS_OK)
   34.39 +            status = myself(session, ident);
   34.40 +    }
   34.41 +    else    
   34.42 +        status = update_identity(session, ident);
   34.43 +
   34.44 +    if (status != PEP_STATUS_OK)
   34.45 +        goto pep_free;
   34.46 +        
   34.47 +    if (!ident || !ident->fpr) {
   34.48 +        status = PEP_CANNOT_FIND_IDENTITY;
   34.49 +        goto pep_free;
   34.50 +    }
   34.51 +    
   34.52 +    if (ret_ident)
   34.53 +        *ret_ident = ident;
   34.54 +        
   34.55 +pep_free:
   34.56 +    if (!ret_ident)
   34.57 +        free_identity(ident);
   34.58 +    return status;    
   34.59 +}
   34.60 +
   34.61 +
   34.62 +bool file_exists(std::string filename) {
   34.63 +    struct stat buffer;
   34.64 +    return (stat(filename.c_str(), &buffer) == 0);
   34.65 +}
   34.66 +
   34.67  char* str_to_lower(const char* str) {
   34.68      if (!str)
   34.69          return NULL;
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/test/test_files/398_gabrielle_to_alice.eml	Fri Sep 28 10:36:44 2018 +0200
    35.3 @@ -0,0 +1,87 @@
    35.4 +Message-ID: <pEp.PEW827.18NQTABD97IHX.3E6116A3-906D-4DAD-8BDD-3381606B4302@pep-project.org>
    35.5 +From: Gabi <pep-test-gabrielle@pep-project.org>
    35.6 +To: Alice is tired of Bob <pep.test.alice@pep-project.org>
    35.7 +Subject: =?utf-8?Q?p=E2=89=A1p?=
    35.8 +X-pEp-Version: 2.0
    35.9 +MIME-Version: 1.0
   35.10 +Content-Type: multipart/encrypted; boundary="d39e5287be3847623f45c9767504e45"; 
   35.11 + protocol="application/pgp-encrypted"
   35.12 +
   35.13 +--d39e5287be3847623f45c9767504e45
   35.14 +Content-Type: application/pgp-encrypted
   35.15 +
   35.16 +Version: 1
   35.17 +--d39e5287be3847623f45c9767504e45
   35.18 +Content-Type: application/octet-stream
   35.19 +Content-Transfer-Encoding: 7bit
   35.20 +Content-Disposition: inline; filename="msg.asc"
   35.21 +
   35.22 +-----BEGIN PGP MESSAGE-----
   35.23 +
   35.24 +hQEMAyZOqBcoGwQcAQf/QDYBUnJ8ASNE+aEOr/gKS1My4WXVbyCMtjLDHu2Ag0Rt
   35.25 +a7OKZNfJePc0DzNDAkj8Fj2OXVEBLAnpoE0E+Rs3V/rKsFjkQ0JXpK8LdstR+yC0
   35.26 +rqvRj8ga5lDkJMUGezk/bEJvsvdWTRiCsNqDOgR7FKo05Ize9Ce9NfxYjMDQrYfA
   35.27 +QaHcgb9naKe7VV8PJn4dtRHxHz0ZalyT2cTx3tge4MPv775I6ZUnLv8po3FUjx23
   35.28 +PFbjQv3lsV5BrzdBwYhZDbYUY8L7J3FJcHsJB0xQtlCPShfq++pEmuccl7KdV8fv
   35.29 +1Y6sv/hQstyAeAaI7g/QHcpYoOLqZq5isxjhTjsIP4UBDANaAgXZcwg/TQEIAKRc
   35.30 +MRhs9M0X4pZKd/q0K1/A7ey7AwbtjiBKV96hUS7rl/kpxtQrdzUJimpfylhDInUw
   35.31 +JRjJcsMXWrupcEwKr5UoXGgS7XfP6+by9qQYSJ9tKNiH0Mtu1BSXtLtx0b4Qoo7t
   35.32 +1i8qAGli4F96swXfgGQYtJAvG8RmSZHLNPe64WEaXoag9llKBHxzaNs6jAd4uTvg
   35.33 +iON4fv/YCUqv4ZS8VWVAw79xJDFIGSUFS6y+Zew01NOrIqQgRf6JmgGzcTTOmvlu
   35.34 +AyB2hTu8clTvGj9ux1GylspIAjQmDKbOmcbD7W2OYlUNJwfWlHu5HQoVOhvd3RnY
   35.35 +LBZnUGs3DTJYj5lUeg7S6wF+eM5HSqkBXvaUF1Xt2TdKEGPf1w57L8U1DXut5Sc8
   35.36 +GGtSXVFis2oV6thluZk3qCcAOyzBEf+Dl+yfRmguOAYsSCdSW9RYrkDZPV+arvGa
   35.37 +8jlsgANzpGPxoqHwUZUqYaAYseO3he4zYUmfWn62YFdeJryuqH7Gme4PxojVsgZr
   35.38 +TQBiLndaoI/aWlgDpXHnhKYsIRGGQbuxHOaLkAxZtzxE0ikhyeHIuY9TLMCrbnlJ
   35.39 +LhFmvidn2m0KB4KqLgv7m8vycaLGxOS0hgNKQPitOLYgV37QL44gZ+H6AwW6pV6r
   35.40 +e+V+FXh68h5AACJ/Ehk65Fl2MLt2XIg1IHopu2a3d6RjKlDnVWGoAZ8N0BkgVt79
   35.41 +2eSZ0I7FNIqmzKTNF94uUOvnFG93y8Dy9yr1bK8GQnHx6SxISfR1cl2c/KvPlVVe
   35.42 +7PO5hlVWvWbEyY89UcvTPn9lr22HXa5Ra2tAcUrw2xvjd83bxeBXigyjyAuzeDEZ
   35.43 +ycl7Jx+/ByrDpbjwUOoTfFUOkG5cHbFqGD1spO29iCUtnizA0oKawr74IvljnapY
   35.44 +cG2Kmbnoh2y+01aOv/BD0rzy6xO77HBUbH9VaKlnpyhgVu9dtDFYQCVYYimpY0aA
   35.45 +VQcLo18zMAsLOhVnWlFicrP1ghEq85bti9CopfkUnNxVIPIzzmXXUFb7tQQglfE6
   35.46 +2+xcC1yqwNp/Pa1EECCEJgfQMg9EhKk5F6AGAkrDuGIIWGWXCgHtbKOmOVUByVuP
   35.47 +pRVJmbNuq9t/qhp/PMrBXPOizcP1h4uLcGA97IbjDXkxOGQG7Tv1pPw/76se8wd9
   35.48 +JtUSd4a1UkwkjTzlGuToO0L0re0yYuLgloDpPftV47aa6JGITXoZ2FU0xk4C0bwM
   35.49 +D0+lVaUBHDcIbSGK0hw+s9RFOe+TG3zqNJF50f6wOy5s+M0CRhYC3ivk6CBmkGBu
   35.50 +hh/PMs4BXcSbyRxIIWYOPRKwa8XnRZRtsbh7FZpySkBITD2KfcNo3u3GV1R7aju3
   35.51 +7/NjF5nLScqNJ1cCcftXD42G7Ifm0VzqJvOwzTI9Dg8y8lxrQpYKGjxKAJGHfs2V
   35.52 +AcjBYcGinGeLZzxlV/YSXZ5rmTyVw6uELuCKSEltyqcdn1rOgQDLBLrbuVSkUJBd
   35.53 +emmHzIvlcSdvx1ObworrbTx1LH063u0fEcP8g9mLq5hL5y7uK54h9OO0mbcNvhAA
   35.54 +x8HrkKge8FXtb24T4s9qgn5Zt8elv9EqtNo0rSg1s5zc+Axy84lxqSCxBONv2uQG
   35.55 +bIQLO0CQHjehD7ALMlyeQnkgOP1VnvOxF/4L5RF8Giz6rmq+Q+UWGTEjS6BE3jyX
   35.56 +cZXVmbBT0HP36jToiJ6VqkO/oGPIDJxqBQXZYXeQRHr4P0WST2axoRRJ8Oq1ZImU
   35.57 +V8dbsHmfYQLXg2xf3ano8polC6Bovfl/15Wvhok5Dk4bNdwuNbEUIPUORfYw5+O2
   35.58 +QIXDDE3D0EcJJkS19sOqcSSfzqHNR2h9eEEKoKCLdjrehK6NHfwSbjHfi0C+J6D2
   35.59 +P6jGCvLbng7TgXpJk3z6/wJuZZkCTqP9xgPUpkrHuRaT4YISXxHWS5BgU852O7rm
   35.60 +gtQJF1mSIe5yrh/Ge7PdqjavMzDiLGmi89K013WpABy/0i8MyrhjYoI+3Xm4qX5a
   35.61 +cPzRgDcP0x6jxG3MCd3UxSnUpesnTcNqHtXTmvwBbVg+7c2WNyA/PUP8cYgpn7IN
   35.62 +VVAnzKN5tFCbmKoeVmycdqfiOq09RJ6hYp3qAJPcytSLxQXmxUdRt48yLzCBoqG5
   35.63 +N3kjFe62uMkx/foXEepAm6xFy0/H1n6q/pWeYehzcXtk0+AQaruM72ujMdEN3Ztc
   35.64 +ewBbsjwpj7mxkJqLb7OkCvXuVnk5GUtadweflyxbBkSh9dBZxpvPfAXbdI27VrPY
   35.65 +aUqr+x31rxq6E9mUfLfWLXEf+jXOpOyxI9E9JNIHPn8rbhPDykzin/4w/DcETjHd
   35.66 +6HmMYi0xu5++HLAf2gDk5V1oqfdmOgJTj6bZYCuSqpeWcUQ+PfflgfYOm4KcMcw4
   35.67 +gnHYQYLDFh/N5npLB0Q8gorHCNttZMjFHZWAwScgbum9VNb/P7bndUntPR1Rujb/
   35.68 +VwfAU7wRt2DaY2AP38XDcNVdKPL3aohnWItsH3P09rxaLfSt/gSQcfMsL2+TNi6A
   35.69 +OH/s+2m/M1B7bwjcPOg8bYYDrJwYATs/H8VKWy4uwpjvfll/CJijdJhPv/8uOzRq
   35.70 +0UFsfFYnhsh0CAL8sq2YHx/02nSiE9O2zdSMq5poqWUObzBXiRjGpPDaPoIYnDw2
   35.71 +/vDAFJmfvN7WMKQ9ipkktQAumalbf1nugzw5E9QjBLa0ZVAbreYW79KRFkQ9rJri
   35.72 +qtJHruemulHmYcw7JsCZacw2nfB/rm1TV+pt+l3rtWZpHVXuWAV7OxBf/OuYkZcZ
   35.73 +A4SGItArxaAuDD14GI7O+PiZLUml8hesfrQLwnn3a2bmt4wRE7yt0S1O6kkfb3kY
   35.74 +As2Zaauxt0lZF5Sm8WwSI/7L1gemox7cLErqlSZ83brqrB7AO/wc4rUsX9FQXKvl
   35.75 +AuTnUGJBw475+IRMy4cM5fmLHqbD/E/nbaXjhMEXpgni9yC9HnTvmF152Z/BzwhT
   35.76 +LJ1xmxcMuf7TDEe1YNq2uu+V7LlfkMsyuGLbErLU5KzHBTfh2drIISgB8XJPRcx/
   35.77 +QLAlI4pYre0pwxbW5RNq5X5C/drD0CKr0LYqmcP3rkpyzo3y7DpimwNSW4qfY1I1
   35.78 +wJG6X2LO0dUmiFHnGVZlFiA6XGO1kq6ElQAJICbztCJHBoXzEXXW8opkOTSTz510
   35.79 +1IKI1XbWONGX+XJptzRJPIEBJ4Pno0TcXmEKWiUuIK1MUxdvxH9mXvc9IZZhGu+z
   35.80 +zandg98QxTB0tyNW/htc7frdRKxRi7y/sY/Z9rhTXoEI1Y9DN+A1JsO8Mflk3s/A
   35.81 +alNpx31dbH71s3nvq8vjMEBQkMlhgyKz9vq/ZMf8lXHrkRd+3gUklbMDfy9YwabX
   35.82 +jq1+nbB6QCYZNcE2BEuwE2qv11PEoIjuRpP5oafg6ECjoRpyyH3vTUPYsKBSl/VD
   35.83 +JrzxvdRlrXPBOzkhug6WwlKnBnazuuQ135aiXT3NajiY2ftLG2y4IutrG/ttX39o
   35.84 +RH5IaaK+/fJMDMpc6BDueO27C4A1FfnF6SNLymh1b2hg8zVKeVUPctxiYNoHWC6F
   35.85 +6ihY
   35.86 +=/YtR
   35.87 +-----END PGP MESSAGE-----
   35.88 +
   35.89 +--d39e5287be3847623f45c9767504e45--
   35.90 +
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/test/test_files/398_reset_from_alice_to_bob.eml	Fri Sep 28 10:36:44 2018 +0200
    36.3 @@ -0,0 +1,115 @@
    36.4 +From: Alice in Wonderland <pep.test.alice@pep-project.org>
    36.5 +To: Bob's Burgers <pep.test.bob@pep-project.org>
    36.6 +Subject: =?utf-8?Q?p=E2=89=A1p?=
    36.7 +X-pEp-Version: 2.0
    36.8 +MIME-Version: 1.0
    36.9 +Content-Type: multipart/encrypted; boundary="41fb875950ea35e61360a605caa7977"; 
   36.10 + protocol="application/pgp-encrypted"
   36.11 +
   36.12 +--41fb875950ea35e61360a605caa7977
   36.13 +Content-Type: application/pgp-encrypted
   36.14 +
   36.15 +Version: 1
   36.16 +--41fb875950ea35e61360a605caa7977
   36.17 +Content-Type: application/octet-stream
   36.18 +Content-Transfer-Encoding: 7bit
   36.19 +Content-Disposition: inline; filename="msg.asc"
   36.20 +
   36.21 +-----BEGIN PGP MESSAGE-----
   36.22 +
   36.23 +hQEMA5Jd4qLmEMkZAQf+OnDf3f/QjoHqkMz/WdWwu0Trr4uN1k1QpNXgZEl8VpAk
   36.24 +Jlj1Akv3ksKMgNVRkdPGOSu14PE/xG7YxDDtzu4e0ruw3uFPl462i0WNz7fOmEdZ
   36.25 +YnMpfn4fNMf+H7/sG5BvaUs/Vdto7uhZ1+ebgeIcwVfKwiOs7NEvGghiJUMOteo/
   36.26 +Jqki9TMytX9sb58tL8x5d/dKbXEewNs1jqt28DKjAP+TCa+F2APN3z86GWBqaRse
   36.27 +JMnw5kOqDXEuyQ2XKA+nlLbThxMZ/5y0+4r4YeKmDqJdcqmSwggLet0LROhZajlV
   36.28 +O+UgkmIEpqKkj5yjG1Aobl8i+RbDSgcN2EcPjG+dHoUBDAOK25E37BudTgEH/1aK
   36.29 +OKh53th8VkK0XSnWqb3Th30X6/4pJNTi+gPM6jHGxRJmlcDgETw3oPii6Q9unWGF
   36.30 +LxFidBJLy91nfO+hxLwb/xVttQ8Gm8JO0ErjTPqdLC13sEN30nD6pBLl19CFPuYX
   36.31 +cq05KtFlSoip9T4Ie9Z9RfI3iX0FKYcOBUImXd41WD9VUMRghPKUyxILspkT5Lzr
   36.32 +hHHsAoDLMjAClwrJi+jFQ0tiBZXxA5E7g2uBvEWkI6zXlahR8LqFtczZRUKtkaUW
   36.33 +4B6SUhe/lhEysZ+OQeyicLN+UypYjHKOWRhZQ/c5ZCQ9WYQ8/fuvAW68vVauCVQz
   36.34 +Yi/Q+zUFYHuI0grCvCvS6wH1lh7lW+O6N6Q6yZEiuWkrKY/vPPsujSLSNV0rnhek
   36.35 +YIy/Dv6smWbmTmT0J4pu4LBOFeSxmoMPRqKvgGuxderlNd846y7y4UIcvHdZ7iit
   36.36 +bWQlTVvZiAUs3fZDRDGIHc55woaTaShHuQKsWq8Bz85gyZQyhf4OmqBKVdiV4Owx
   36.37 +5jdsFey96y+pK6hjMZxzBLDj5uLPtv9qpUAEw+2/GvX44RXf9gD+UEwo4KLx7iA2
   36.38 +lfktUa/93Ib3oFLFt0daej1bQVS6X+hREwt5djd2ufLitSzYQXGhDEKQ8PXnxT4G
   36.39 +oEaLuGS70CbQGk2WoWc5Lpb99K8Q6jCowh8YtcN+OKmjTvpeJlo0+bcTq1UJcbah
   36.40 +8vAmV9hnyJsOelCwKZnLGgx9q7ti86qtTHxtyRsvw0Pw0IFsUQBW9ZkIybOZrUfz
   36.41 +bPxt+de+jkbAsHK8gRhug2SWmb2XtEfhEoU6EMGZvaRwLF8GNvL1N5EOXFXKJ/dK
   36.42 +YR4mGDLBFjahq42wUlL0TADulj3E2vE89bLaUD23SI3yK2+Bva5JegI0YOg0cgKq
   36.43 +IZEpb29VeAxzae9/Gkmusp06GNsgjBqXgkLeO2rpPhzfrqgeKcD6I4UpTleSAP0U
   36.44 +ApdxisSnZlFjmOyxIqxbNV3JjYtApaeUi+B8nGmHnHE/lE/flSc8SdZne7MTq2iw
   36.45 +1pJMLDZNhWB+S2Ch6bhgYbnmiwBMJq+b/yEWOev8aL+ZGgWTAsWr2Kc//mdH0htH
   36.46 +Rk2Eckz/pyTJ7q0d/Tk9aOXVc5/Q5mWzrttrfoo40oJlR8IN3wcq5eKT+ZU3SygP
   36.47 +KRVt1iLWdj9/9TgeixtMlRUX7kXaBWRV/x0kX1mV9INEulzDvtwqcJiTRSX/pqPY
   36.48 +rTm+9FdpsPv+Rp1ep+iKkoPZRlzJh6z932+gZ6jam1eQz/UdBS4ttKMLvhxdaBgG
   36.49 +Rb29XKjIVRXdItq48n9UaBk91rGUT0Ol3i0NtiBIj5Z87tph+dq4XSLmhr720Imn
   36.50 +QvEl627xGbhb4xOE/MBxh0HYhSi1F2arxsIv+7c0YK5agbCqnl2+b+8L4Hlljlr3
   36.51 +FUu/GbkzOfkGDBYHYBfY48/VwEbDqoCDTef9uBJ7XQDFvwfhGwvKBOBnv5WW3j8i
   36.52 +pUVKby2x9oWTjH+7Tdn1oL4DiNcnyOGhmDOisWYhIDxFrWH02fHI5Ag9jvbY3mah
   36.53 +nrdWm8PNqnKRaS/fe++LYW3zKyo08+5TDGzQJqrOJ3wPK8UK51pXsMG1N/J3wxXr
   36.54 +saEBTzwhlPdc7bd734Grn0mmc/lBbBKK9VzgjwxS8lGRr0FOIdDTRdMJU42Zq5dC
   36.55 +vJ4fRDDx+0QlAos6+srlgYcmK6KFcp/9OpU+cNztQYolp4HNdZRPaG2TSdnl3SBi
   36.56 +e/DhE5JsVPVvlHXYPwPE1s4voxEQqce8BsbvNPBSCdN+UKd9/NAL3yCxqgQa+MPV
   36.57 +Cx7fJoIVD0Rpu4jBhga6ePxntuA16nNDefHh0BNKoptkbD3Ls0fWBAf0RC/kQbU8
   36.58 +wEeFwQfjIYES/OHKex51qhdxG+6yF3w5yehzbPoUPUM+Rmriwiq6lDEYDVfnJrK+
   36.59 +TqTxyHcDhLtgsCEo1DgS1wUMbbY7RbLXqfHUj+0VSpD65mkG6+0gu3gQLYGtTYDu
   36.60 +ssX/vYD63kuj2r2dYbN7muQrfPpOX4SGoh8Ao5e39A/G91+pD5MTrw4JUQ49EV6l
   36.61 +1KeewEivDBJ2inFPzg1ijRuQG5Zj/mDYCu2wkks0V2kqtikSIUAao/DK7UZ7fC1p
   36.62 +1NIYZcRjgL54P3fqize+0FW+a6FheLtBlzrcRXR9JXjpQHh/9zRw4PkGJOJsXv1L
   36.63 +GXcuPOL60wo5YF8SVrsmd6xzcrt1CB8egcQGFzdxOXrMC6sBCJ+xyWySZShotGvG
   36.64 +6/rwv1s7/Hl6ls5Pb1ii4FuxKSdrz70Fz01z066RszL7W0xqtgGcPw49/pBp1gCr
   36.65 +tqj/gD9/xM9j1N8gKtc9ABZVGS+fldUVxQ01S2Cg2riU0JpDAG6hVJyT/qWl6myQ
   36.66 +owLWdJOWcczyEa/aOiH+ls5yO7NT7hwT+EGWDx5B7VKA1JsouTBOK5BZbWLGI23G
   36.67 +SVVqVaRHiAeoqhIxmIHrzZK3hERohOG9T+IyMfOlMiGCfqPUUf/q7+LS3djTjQ2t
   36.68 +dEKfCpEdKmUOMQpb+I/lrbxP3dV+wEhmM7aSrRKke6PjiUXjfZMiGR/02evumhKi
   36.69 +aRqtwXy0s/QagTzo6z5Jp6ZqiALqZ2jopb390X+6Hz1GNvDZ1GSDX4KASlI7dnGA
   36.70 +8JzbKRwA1+H6Z+tgKFzl+96/56gtXTz6E1ynRF6tIp00j8sukBpTdi3lpZPAte/K
   36.71 +E3Ke7Ts0AyMHD5K35QJ0+zcunPrQ1AVfa7lBmUkBBE9Vf6jIgtAou+jWDMXZr5O9
   36.72 +u+qC4kSNoMglD3P2RO/XiqIdBCpcQigaVd+CTL+3vLUzm7swn36bRX+LYaHLDSUi
   36.73 +AKuhJ0UzRwetuxnUBQP3h7L8BzkfceixpUX97itmm6ZBZP3vl24eWPL8UKQwFboS
   36.74 +UuYzd4LOhv3G4nKSgFQcPj4isQlCJZyKsPZ95UHsA7SEuTgXQM/WXzWz7LtO2zOW
   36.75 +0tTVkBOyVADjqgXpihhA0hXYMJJAqhV99XRhiCc9LNOHqwPb72GZai3qQa8TC4gY
   36.76 +WXAzLM2oLI/DzhQNF1CRrGfj/tKfqrG6b9wH+NuW0fD2TapgsGF8Xgu8fMP0lcMs
   36.77 +6n5yJNm2Ocgu+j5nXMT4ovK10a/+ndI/oAB3a/YE7Z6pgnp7X6/fIkHLlwrAA3/W
   36.78 +jlH76PEFeVSBSWZy/1FwKYRHW33Dgync4SjK0UfTJdzU+N0CYetNYKGLvLV0Ffws
   36.79 +1CEqeXTNT0FUoeTNhdaUsgwJWmdRcIXZq5wduRFTWjJ69sRyHTGrFemg3WzUCpdm
   36.80 +AL/Ozbs2kC11bBjHovc6dne9SAXTQR9nZtf/+Zvu8Yyoswi/yG4WeRCIsEk1XVBj
   36.81 +SzyXRHCVMJC/HMGFTwNc4Iff/rcQnbFiTPvhjTsLC1vLgr5eLitF7QQW6Q9KPugH
   36.82 +VHmpNxlejj5nYIqUBal4w0TE5OvS+P9HPatwJCNcMjOh/NYdAIYv2lYRS+EepeC+
   36.83 +46EKB4s0o8hur5e1AHfhlsbrVZ6fyPPvNT0QTdAH6hgpHEZ/AUzxoJ6pTaN1smsJ
   36.84 +GIyqCPPy5Pq1VTv1fAx1wVZ7Xh3XZYDwv49qFO4swoYRspAAB47bW1sUGkI/gcSo
   36.85 +gtYWDYceP+GjsPKbLlfSfFUWirw4xMsbRH5BEmh0IGSGdycFv81PC1ii5VpWULFz
   36.86 +8M5qt9omY99EOppe6xVhw8gHRV09pT+ewizvJ4kQNyMs8/YqP3HUrPYSTaRnVZmG
   36.87 +AxJBQubYQyYx8r7sZnZRnorhlhBbl/0hY66eBbdU9kQpXDDE/S+Nt2iJ0I5c3hFt
   36.88 +Cs8sgIB0rsErIxjlefEo0nkfNgriF6ZGIIs2/NPjkxN5YDRLP6Ksbsq8SR+FFWCI
   36.89 +yhpd9478VilUfhd6c1uz8sLm5w7nQMTyBkjSS6rW+4XYa7uPu31EaVfm9bfodO8e
   36.90 +vKSZpvfcGsgZTuDx+CQkEpo/tAUsglnglvienoyoqFt33VZr3DaqQj6HZNsR/cZu
   36.91 +xt/72vHwhaPcFJyOn+qbbJ/P2rgsvbdszQhBJTfn4j63GPdHV7tVAChUFtX3fseR
   36.92 +PgpPcZea6JlaR+0CprUKRCsOQ7WZHNJIHjthavxegXi7qFJjfHN+/zrT1GUdyos/
   36.93 +NvEmO5ahXrmWVxfUjn5CTsByAkqzxInBsM+WS5iI4fq1oCsTsOyiVlCQi97+dAIi
   36.94 +3OIC+GDEsQbi+id2FJsMfKQuKwjmPCUrF6FYqpEUzwv8DKb+9Nb8OlKdFxayetGC
   36.95 +zkMvbuVsdEt7/Fale9RbiWkRqpSmgDFovFWEjJ73Ri/QZFP8Li3XjjnNt4cndc2Z
   36.96 +BoB+hAzv+FrpTInxGhrrCKGyBrEnKxRiCD9DDR0tKfiIbe3ZAXOo1MeZDDpCgr0Z
   36.97 +rAwb4AOkoAakS65sJ6ADtmTE4Jv4U2ulZABk8QG7yl5vxVSQcyJ+ZeVWXhW9S4rA
   36.98 +Kf+lB8I8T+rE69PKA3Y+ehPpFaRTx3rtktHfKfM3HUXz6OEcSrsqXreKE5am5qBM
   36.99 +QQ//vD9sHmkb9TTyrBYl0an/4DdxGDTxh+8lnhI/4bLrSrMluhkw6mRjow5yjA/+
  36.100 +zOYAwP15E5Xq+d7OHJomqTSnUtdFVLNs5ljIQQEXIsVDGU/UifQW6MycLREntHCW
  36.101 ++TZNRWk+H8JwVEPOnOEQCNzdCTwRhlhJkykxY8swaQezsdkG3ryNTqfT3ITRPOoA
  36.102 +l/huOyjHnWLo8496QciMLg6oBPieQhk9Ti93Mi2a5o8zDnOFvPc2etFWhYh3FdHQ
  36.103 +bMCESq6IqjVwz4u/terRQ+tZN751pGjhR5eS3/qJL8hvNHuRO2SoD7qI2SFo5d2H
  36.104 +8LtgQBMWWYQkF/WFieaLqvS+h/yrvXntfpv5+5O0Ceqk3rXWlC9Unjmvib4AUqPX
  36.105 +PUgbCJ06seSUS93Oy1VV+WTMxqi+5vvQ2stpudhos2BDQbpCIQL6wjcO/mQ3OAdr
  36.106 +SgRT1DJvq+n9JoRouyJHpnQuFpBZF5fMXy2sAoDsGqksy3sHvSjlKgZzwSetwiRk
  36.107 +Kixdan1Wbz5yp0VIcebyxQORTQqYHSicdTHmSzM8VrmgjeSxl+WWrn/uW36yJFP2
  36.108 +uCPoNKtF9BfgFu6sWgAOxXd5jTDR8LVFzi5oA9C2RCL5sZo4vZuQtPE1bSJYiKuW
  36.109 +QwnAFaNs9zV79FAmvvxjgoUWyjwB83yVtrrVaAyh/7KGzhF3tlGry/XN+kqWk2lW
  36.110 +bTpcLhSgzABkv0X12caWgV5uIMCDXxJv0h+x+P7C99+t/6xAGf0rR+5xmbN/EZjK
  36.111 +zJgnl/XNS18P7vciphoEcUSdQ7fTQmUyJIqBlSKlBbmtld7bph8nht9kEZdsfN+G
  36.112 +aSmWYw7HRaCXoq+IqVJeFoykvC35dBX/X30BV1d0HrO3kgTS87Fdl/7nF0boO528
  36.113 +ICgsOg1vvjXDZLqEyHrjxMCHpZiCNBksnQ==
  36.114 +=0apO
  36.115 +-----END PGP MESSAGE-----
  36.116 +
  36.117 +--41fb875950ea35e61360a605caa7977--
  36.118 +
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/test/test_files/398_reset_from_alice_to_fenris.eml	Fri Sep 28 10:36:44 2018 +0200
    37.3 @@ -0,0 +1,121 @@
    37.4 +Message-ID: <pEp.PEW17L.0RC7XPI9ZPB8X.97B39B40-10C2-404B-B8CC-54B79229F8FD@pep-project.org>
    37.5 +From: Alice in Wonderland <pep.test.alice@pep-project.org>
    37.6 +To: Fenris Leto Hawke <pep.test.fenris@thisstilldoesntwork.lu>
    37.7 +Subject: =?utf-8?Q?p=E2=89=A1p?=
    37.8 +X-pEp-Version: 2.0
    37.9 +MIME-Version: 1.0
   37.10 +Content-Type: multipart/encrypted; boundary="7e23a74c7397f0666f31d87d17b86a89"; 
   37.11 + protocol="application/pgp-encrypted"
   37.12 +
   37.13 +--7e23a74c7397f0666f31d87d17b86a89
   37.14 +Content-Type: application/pgp-encrypted
   37.15 +
   37.16 +Version: 1
   37.17 +--7e23a74c7397f0666f31d87d17b86a89
   37.18 +Content-Type: application/octet-stream
   37.19 +Content-Transfer-Encoding: 7bit
   37.20 +Content-Disposition: inline; filename="msg.asc"
   37.21 +
   37.22 +-----BEGIN PGP MESSAGE-----
   37.23 +
   37.24 +hQEMA5Jd4qLmEMkZAQgAj8cxagENLesYZm9tPxJWZv70pPUxrVbFG8U0of9V7Q+i
   37.25 +mypRO+/WoKg/fU7f1+JniBGb62ijwn8YuuZyxEch4TFQQrQ2u4BoJesy2nXr/JFM
   37.26 +wFLt+QcMwWbgAe9rmaPZ6E0TXpKFphz3Gz6wa6+21JNQiAlcUqv3UL7aNI8C7t0d
   37.27 +Oh0J9JxboAdJ2pi3AfDtaSb0vie6EcmEN+AeU3P+LnQlYyT9NK4AqaYGOgKa515e
   37.28 +NpCuogpAbnoRChlcRJGFlEBOJR1fuFKnY9VVpUppVQLSUm34BtIAIexsAfiiexXV
   37.29 +A/5XlqN4fzA/erFknlo/zl2jZGnsd5MVHZ5XClVeZIUBDAMSIv439cLEHAEH/RK1
   37.30 +OJ8G+vI+X9b4SZbcNrE6P1rnC6iZMqlIn+13fmnf0HE4ctLaAPhsazBB26mE+/pn
   37.31 +anby34JepDVvdplZHwKBML/053WeAo2luflrF5cZKoX6BE5P4/L5gTRWbYPWgPz9
   37.32 +uGiE8udceViK2PQyrPRXSGmoVxQ13mWVvIRK3hxB9HvK4YSAWf2Dd5ydMr8xUWUy
   37.33 +Mu6elZNT7fUGuFyfla4X0Jskc/dLr+zRhn4Nw2OdUwQ6ya0KPjeKwFLamyPa5Bat
   37.34 +u3q9d0YQJ+4GRRA7r++d/5EJvb8iT+YybU0IKgeaEkIGaUD51GNa/nUTHIn0Gdd2
   37.35 +o1AugkXRMyJIpsSRsi/S6wG/NW4D+ZfEevTFHnXea61aqwPeoQTwOScdjjpfRW9c
   37.36 +BQCEsygUP69n3Y0Ote+xuAsBnDw2oZh2OsRWbI6enedZhaNq3sbOj56KsE1lsHvz
   37.37 +kp9Ox9e519a4vE/kaQyHVQTcllDNttzLoLluWufs4kjZuyZ1Q97rTK5Fi4JJUyFk
   37.38 +stXdFLa9IkYxIJLg8iT3nls/het8BCHRJIsK3GU7sKPQJvcKOBmQvDfwpfYfXYOb
   37.39 +y1UhzNH31TlLyHLnfBex0RG909HmdFQC1lQ6cqE4cLjT2pC15aKjeTcP2igt6V7A
   37.40 +z2lGwZmtVqlCc0uyVKXNCe6jBrac+GTGyJjcWWYrkGY2MAC45893YwEIrqf93eGf
   37.41 +Wu1HPoV67B2X6xHDvvcehi3xldSZMsjd/HbcQ3w3HHH8meffsF27h/wmei1dSTj6
   37.42 +xsV0M0AnP/Ck0qm19XGindW8rgVP7khPG7yjI2ETsHKeEOdebgICFcoQY3lPv3F2
   37.43 +/26+i2AmF+SGfGW/t/I5Vpx3XuUFAKaP5fIQSZf1FRq4bZ3ctud5kT3/UC+pXedc
   37.44 +ItbFZIK4W+GFN5QfnyZ7qGOm0fO0mSFuhZHXzjLHIZB4NxW7SnCbBA7/MBM9QdyO
   37.45 +L/lXNLzW+f8JJyBRa/ro6ANv5euTzT20F4XNRZu026U2qmsDS0UrqMMkd1q6w0jn
   37.46 +fZggBNMgKw3k4S4VPGgICTDx7o9NkkuEP9LmOST1N9XhbIrGJXYj9ot05BwXp4aK
   37.47 +1saVD5v0OxSgQu5rqseT0ToElLD0te1kPjaFsxWSXqxgd6M612elm8T2gt2pcbOA
   37.48 +blJbqixncctuwWcmdh5Sq391gE+Ut38Wj/mJuJwlXbedgvMRGbVNjPMNg/wWWP4Z
   37.49 +awRk5b7rtAJ1F8bV3nJMQHUHJOG63mfRAOd0hpwA3VgVZpuVBwH3R9lW3t6b4RaH
   37.50 +hPF+J7CZyoi6FjgcuDob5F9T6BWzCx/gR8yVat/FNQu6mHc8JtiF5y8CYHyM7oLa
   37.51 +rNBM4Oaoc39N3wJx9bO+S7bc2A1whhtQom4o2VrLe1W0vxXMsW+v+mS3FAeG3QP1
   37.52 +88Mc3lQvXdQCAGiWBTUQ+CMcfFYaGVpIhQPZ2jW63CTkhX6adtHD0bBupfwxTz9p
   37.53 +KJcqhqDk29f52PPFb0HROvd04aVIhTUAlf6j9f8+1txP/6frRHOxwLKmI0OhEJBj
   37.54 +VsX5tB9K787fA4rd1vBScFi1pZ4k7HCKnTheeXxSp6DeE7dslgc4dQoyXPeny3ol
   37.55 +JugW8hB8lmZrEmYTJPcsglHbv6toUaTufkE2KFfkjpogwYLxMDLShIXgLAiQ5SX6
   37.56 +q/RWpFBr9o5un+z2D5FCwuhW9a3HVcWWWuxZ8YkWU736sKaLmZ8Lp7SsJKguUhpb
   37.57 +N/R8UddrfpbCCmIzAo8g2+XhcnfpPVw62yROFKkM3fNHOBgfeY0z3FY281V0/ytd
   37.58 +RH8E3CnGm7yBwn0XCx3uC9HtvOQL3Te5f88fCfSyEZJmg5EiXqBhf3uNw2QIj2x6
   37.59 +VwNGoVNd3QDJu0JeSAzzYfGcGkTQyEKgEs5zNr5YA7NeraJdv+CRzUu/kc7GNl94
   37.60 +8MWgb4oDgk6Mv6+uVxO0njyDQiIDTVnGItCxnsnllvvEW6zRyVsrm4viZmMSkVVf
   37.61 +X/kYDPIpmR//lJjjhYcJqFSieDYurkWs2BvZT5Di8xWZhllcGc/yB02BtK/uLkFT
   37.62 +RM3PsaLIef7OK2WZ/7Y4XuwIwFYCGK1gCv4TAiYkrrN+gzySMz2oId1BJLlA8CRL
   37.63 +DPAEW2QTucDXLOEpl0XFXSosiLUAf0pbZgVimWS1FdFV5M3SRxymoRFHUvJmaFKR
   37.64 +p7FjHmGxR4PhDrMOveDWa5331LYU8Ycvdbh2q7Cg4ZTt1UrqlPyZwbwxdSamPFrI
   37.65 +MhsTjUW6FuCmJ2AmmTbIafL+HohLAMG/gGMSK6qa8hjV9S3QEOmv0ieOce5Tlzka
   37.66 ++Jim//j+X1AGYFIb1Ho5YwBMY35GHTmRFQFeobAuFdmlKI6eziLi6gB0GFMGoViJ
   37.67 +yxEoLO0HN5iXnMPJ8jKw0dUg+qTNDAqS+8BS2CI1u0Ez7BtVuOqdCNCCT3qaBu6x
   37.68 +eFYJfs8eqQIwPmyDeShvYX1+klPvoKaut0HY8JOY2waI86wvfI6IKJKHcdCsIau/
   37.69 +EuHkoK9xAAx5YsvMXAiLBHQn+sdnrJ+iBweaLdBN5cmg6TAMlcE2gv5OTkL+mkz/
   37.70 +nHvBOR7qdbh5yxvlJd+SlI+hJrFuiM/MIwRmhTFefQxscOj16sDnIz7IHBEPhDoi
   37.71 +RGsJAwbj/pV5Sgjk2gFjgIQ+QvPzb5WYioY1GMOJKXJuea1ATrk35Fufg4y0aQZf
   37.72 +JtlrTrYz16jq7v+iFFD70zBuwIWAvvkNR2jyYT+meLkKmYugOVtlONJiwPqBQf9p
   37.73 +Xy5vsD3By/k2HFPEubVIS7w6kj21dPvbhugdAU8MT2oQZtPSyFUV/MCZRc6zu309
   37.74 +jZp84E2JWmF5hlDRXH6fiOiVaIJVdLaQ0aJA+75YzF1ilOJM2TSFXKyFOAYr6yQN
   37.75 +foOdXJ4ZPapCFKrIKmxEwhBMtN17cc7r0OOpxQMbhu6OOAup01UIc1d99qWWUKLm
   37.76 +2c+etOskQU7WMZisLtlfoVZtxalVjHmaCM18Zz0RxrjMnRnupYSH2WqXDC0xNpK0
   37.77 +6tHsBhct8vPMlWNB7gKtn6dB7tHFkeNUbR5a9wiM8VN9Sxck0F+RGr/Jr1A/s/jC
   37.78 +6todAmkDqenqun/3b5P35PMU2N4KzaOvlp9oDU6I+aGuhG4Q055aRXfHL5pmj6XD
   37.79 +t08D8HbRzXBxEqHn+b3vtlq+CyHX24Zf87HRCJTzNaG2vZt7xmIRfagImR9y8UzN
   37.80 +S3pNw9yCOL8e4VsJIAHQJ+nt2Gs1VhNb+El0CjYb6Uvpa+AkmLU4T5V1bKswiFO1
   37.81 +Q0SedRcBxmH+/UzkfT1eyG1RreSvhWZohOrLShu7kw+GKseDzXQrepBg1TLPcxgA
   37.82 +BVzf+1lQVqPCFTur4mt1bUGvcwgJ7ydFhZqp98JyFNRKH6Dp0FHOlBG9dEitKCG8
   37.83 +4SIiWO0o3Qor2OXK1f4hMrhnPuW1GHMuDQKLgdOv99C+C3DzbtOVDzUiFRG/qYmD
   37.84 +MM8Y9bWELwW0ofI/0N4J6cqZmIXv3qY9hgiWWZKvSnOTfgQ31T0ErSZ3LTM04UUo
   37.85 +OaxON34Z1X3O2vZW9nPgNagY/Nt8YhZL3rOgVKwDM1eLD++CNJUIjZFafBT4otv8
   37.86 +EX11LgJxIzz4UvezobqUjXQvYKdSz2sHvz+NXPcvfqUf8SwG+Cfm6lmAr/ZBskNw
   37.87 +M0mDCaRQbcOJ6mxNsOh3uf3VlzZeDpML11D1OskcnHC5aZw/0f6xzzGkYtvLSZmM
   37.88 +UsLoP62sANMgWdLRXALorFNp54gypkmFTi6FPI+8TK52pS+p63i3n21LZgSFY43r
   37.89 +2Rs/JiUZkfQ4CTHIhhUNtEU9G3W4b713zNAa47coaKW8DkxScnUgUNR6Jai/CLnP
   37.90 +lBt3MTs28aV/HEG3efguUzVZhUnrSsU3tTVy4Ok2P3+a88wN8bj30aFSsGq+v6Mc
   37.91 +M2eT6jK30uUpz144BSGMuOobauQI0JI2QgDu2UeuNdk5wQbsGuTs6/p8upFNg863
   37.92 +9a0PsEnpf0LteJB5voY9uy7FMNRF6kgoj/axa38VpWNx4WD2xAWI35/za287Vgm9
   37.93 +nS2r1TXiOnX1xHcD2gID3onVJrzD8VPYJcJjsfPzUfBsRp4KLl3gxdS4xg0YEVvG
   37.94 +utnOIPsKDK77kWWf1hmuI48xfALnN9EcBCJ4Cv4gQGQlaiIaAWMJJio562if3Nzw
   37.95 +sOcqqGn71kLw90v/xMl871vZtGFeNWBh8qFPO48w+5rci8KO5f8ya2dGsquMvuIw
   37.96 +7lEjLlpaQdKui/Fh68zWSmf5LzqjRCr0HiMFg53P46YEVHpDnyvPBPgzPrr9WKOA
   37.97 +CA2hB2Raf5bUgBPQnGor87w9QRcETlctFmgROSsysr9YBVQYYrqe69W6bq8kYfXN
   37.98 +G2gSOCItYJfSJiAgjZDlUpHwPdd4JaY6WwtfvcJbQJswAL6LRi+Yr7VHY0RyPX0c
   37.99 +rVSs8dtcelWTkl27IQ6OKw7pikDT2jfUOlQWGSatTOxGu5qsfR5yJQ8BY5wKHAkF
  37.100 +bpeg8nRHSF1wdbwssS6wJWFrn7vbTmZYavU3yLuQYAc4+wfGFwfv+BULfLBbyD0w
  37.101 +Hy+1aahhFg+aWs/0162xOKAO4d9+T6Woroy89Sr07Mn+wFROiPvskmkTEt3plJZl
  37.102 +mv/HWbOIY6PofKRXPsXZGpVgmmpnhiEvuvmbXagGpna65E5B5dJrFPhRccZi36k5
  37.103 +tNgpVEHz5Fn9l/hgEOs8j7Rw9yUiE862RD/LaiOwlOu/RqQbIf3yM4SUkFQ8Ef5Q
  37.104 +hi/rpmggBJD/Wc/2FJW3CHamXAoUdz72lKUSHf8sq0LGIqrIo+fP3NOr/7dywWPk
  37.105 +JBC0gODOKZGD3ZVfhWigcd6BQFMnkq7vFun67bz21x3n4u3m3eCDGMy5dS5cxx+C
  37.106 +kp2nq8p4qlsavklJPX72euPqli4oBNMb9EAVuzURsFPDAaXFxhNssTe20bU8FCic
  37.107 +/ghLgfv3Wot9yUcbZeVlikVANJeQ94Y1qphmGZ8UMJYfeoU61coj1W0fLwlbbkzO
  37.108 +otPBhe5GKRhe9dN0jTrXDXmBc+jVh02nc59LdJEyCsyIrjW5ypresxIJZf7M0HEx
  37.109 +JEfZ+Po/N8L9B/8h2I6xad7NUk0wrjROHsNUbHzOnYFQRQmlShZc8nV5A+YHSlzk
  37.110 +FP3A9grsvolwjkF71xbCNmsiH0tVosF6R0qteHeNHfdfLSluSRYC40BJqzq+sc7v
  37.111 +j6rdzjjS4AAsSwdvnz94BKUuSpD/0+ebiGcoQNg/8rwiZOXASNZqnoP1jX7A/cP8
  37.112 +e8OaBk1enYyQdNv4dq8G377rO5D3r9Vu3yX0D0UoYsvFX6LSniAl4385gyHw/1g8
  37.113 +T6EVLR5NOes+3L2HmEa454uQo6yOnYg9FaybX954dLWou3WgR/2p/K/0yWMGuCN8
  37.114 +XigjIc2E5Mt/VyrVImheLQ44i4u8x6KutcINzFbSjiJG0hIThCUOl5RKjzgKqrGj
  37.115 +dBbjq76p7FR+sJoTZVZ4qfd70Nmdi4ccQWfRXICLZGxnmYymMjfCc9A7JfEDl4E6
  37.116 +wGqDf7AKfsW6EhFNuT6a6d69OTAAYdL3ZhixbEOiNxOzrS1PS4T+g9/TMbTkCzHR
  37.117 +48ZJZb0/HS/idd9WXmUj02tSWYVtewxBSgbfes+fk0pM/zbiOjOqXgNMnPo0yngH
  37.118 +HBPs+/tkZX63EY8fk23UHm6U/6qpuMWFs62JR6kF1sb0MYCYY0rVxygrbVabFp5W
  37.119 +Gbdayy1g6mwuZA==
  37.120 +=ncTl
  37.121 +-----END PGP MESSAGE-----
  37.122 +
  37.123 +--7e23a74c7397f0666f31d87d17b86a89--
  37.124 +
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/test/test_files/432_no_from.eml	Fri Sep 28 10:36:44 2018 +0200
    38.3 @@ -0,0 +1,492 @@
    38.4 +Return-Path: <SRS0=Imtu/Y=LL=pep.foundation=krista@srs.smtpin.rzone.de>
    38.5 +X-Original-To: krista@gnunet.org
    38.6 +Delivered-To: krista@gnunet.org
    38.7 +Received: from vmmailrelay1.informatik.tu-muenchen.de (mailrelay1.informatik.tu-muenchen.de [131.159.254.14])
    38.8 +	by sam.net.in.tum.de (Postfix) with ESMTP id 35CD81C00C7
    38.9 +	for <krista@gnunet.org>; Tue, 28 Aug 2018 14:34:04 +0200 (CEST)
   38.10 +Received: by vmmailrelay1.informatik.tu-muenchen.de (Postfix, from userid 109)
   38.11 +	id 54A621C038A; Tue, 28 Aug 2018 14:34:04 +0200 (CEST)
   38.12 +Received: from vmmailrelay1.informatik.tu-muenchen.de (localhost [127.0.0.1])
   38.13 +	by vmmailrelay1.informatik.tu-muenchen.de (Postfix) with ESMTP id 309F81C037B
   38.14 +	for <krista@gnunet.org>; Tue, 28 Aug 2018 14:34:04 +0200 (CEST)
   38.15 +Received: from vmmaildmz1.informatik.tu-muenchen.de (vmmaildmz1.informatik.tu-muenchen.de [131.159.0.87])
   38.16 +	by vmmailrelay1.informatik.tu-muenchen.de (Postfix) with ESMTP id 25AB31C0376
   38.17 +	for <krista@gnunet.org>; Tue, 28 Aug 2018 14:34:04 +0200 (CEST)
   38.18 +Received: by vmmaildmz1.informatik.tu-muenchen.de (Postfix, from userid 109)
   38.19 +	id 241CB1C2DD6; Tue, 28 Aug 2018 14:34:04 +0200 (CEST)
   38.20 +X-Spam-Checker-Version: SpamAssassin 3.4.0-tuminfo_1 (2014-02-07) on
   38.21 +	vmmaildmz1.informatik.tu-muenchen.de
   38.22 +X-Spam-Level: 
   38.23 +X-Spam-Status: No, score=-1.9 required=7.0 tests=BAYES_00,RCVD_IN_DNSWL_NONE,
   38.24 +	SPF_HELO_PASS,UNPARSEABLE_RELAY autolearn=no autolearn_force=no
   38.25 +	version=3.4.0-tuminfo_1
   38.26 +Received: from vmmaildmz1.informatik.tu-muenchen.de (localhost [127.0.0.1])
   38.27 +	by vmmaildmz1.informatik.tu-muenchen.de (Postfix) with ESMTP id 10E381C2DD4
   38.28 +	for <krista@gnunet.org>; Tue, 28 Aug 2018 14:34:02 +0200 (CEST)
   38.29 +Received: from mi4-p00-ob.smtp.rzone.de (mi4-p00-ob.smtp.rzone.de [85.215.255.5])
   38.30 +	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
   38.31 +	(No client certificate requested)
   38.32 +	by vmmaildmz1.informatik.tu-muenchen.de (Postfix) with ESMTPS id F26571C2DC6
   38.33 +	for <krista@gnunet.org>; Tue, 28 Aug 2018 14:34:01 +0200 (CEST)
   38.34 +X-RZG-FWD-BY: krista@darthmama.org
   38.35 +Received: from mailin.rzone.de ([unix socket])
   38.36 +	by mailin.rzone.de (RZmta 43.21) with LMTPA;
   38.37 +	Tue, 28 Aug 2018 14:34:00 +0200 (CEST)
   38.38 +Authentication-Results: strato.com; dmarc=none header.from=pep.foundation
   38.39 +Authentication-Results: strato.com; arc=none
   38.40 +Authentication-Results: strato.com; dkim=none
   38.41 +Authentication-Results: strato.com; dkim-adsp=none header.from="krista@pep.foundation"
   38.42 +Authentication-Results: strato.com; spf=none smtp.mailfrom="krista@pep.foundation"
   38.43 +X-RZG-Expurgate: clean/normal
   38.44 +X-RZG-Expurgate-ID: 149500::1535459640-000020CD-236E2DC3/0/0
   38.45 +X-Strato-MessageType: email
   38.46 +X-RZG-CLASS-ID: mi00
   38.47 +Received-SPF: none
   38.48 +	client-ip=131.159.0.36;
   38.49 +	helo="mail-out2.informatik.tu-muenchen.de";
   38.50 +	envelope-from="krista@pep.foundation";
   38.51 +	receiver=smtpin.rzone.de;
   38.52 +	identity=mailfrom;
   38.53 +Received: from mail-out2.informatik.tu-muenchen.de ([131.159.0.36])
   38.54 +	by smtpin.rzone.de (RZmta 43.21 OK)
   38.55 +	with ESMTPS id f090f3u7SCY02qG
   38.56 +	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (curve secp521r1 with 521 ECDH bits, eq. 15360 bits RSA))
   38.57 +	(Client did not present a certificate)
   38.58 +	for <krista@darthmama.org>;
   38.59 +	Tue, 28 Aug 2018 14:34:00 +0200 (CEST)
   38.60 +Received: from [192.168.0.102] (ip5f584961.dynamic.kabel-deutschland.de [95.88.73.97])
   38.61 +	by services.sec.in.tum.de (Postfix) with ESMTPSA id 6A14A1008E943
   38.62 +	for <krista@darthmama.org>; Tue, 28 Aug 2018 14:33:54 +0200 (CEST)
   38.63 +To: krista@darthmama.org
   38.64 +From: 
   38.65 +Subject: Message to edit
   38.66 +Openpgp: preference=signencrypt
   38.67 +Organization: =?UTF-8?B?cOKJoXA=?=
   38.68 +Message-ID: <b651dc6c-513c-b584-7309-49eca57c5fc3@pep.foundation>
   38.69 +Date: Tue, 28 Aug 2018 14:33:53 +0200
   38.70 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
   38.71 + Thunderbird/52.9.1
   38.72 +MIME-Version: 1.0
   38.73 +Content-Type: multipart/mixed;
   38.74 + boundary="------------D703284A94612CBD63CC1F3B"
   38.75 +Content-Language: en-US
   38.76 +
   38.77 +This is a multi-part message in MIME format.
   38.78 +--------------D703284A94612CBD63CC1F3B
   38.79 +Content-Type: text/plain; charset=utf-8
   38.80 +Content-Transfer-Encoding: 7bit
   38.81 +
   38.82 +This message will be edited so that the "from" field is missing.
   38.83 +
   38.84 +--------------D703284A94612CBD63CC1F3B
   38.85 +Content-Type: application/pgp-keys;
   38.86 + name="0x34346730473419EB.asc"
   38.87 +Content-Transfer-Encoding: 7bit
   38.88 +Content-Disposition: attachment;
   38.89 + filename="0x34346730473419EB.asc"
   38.90 +
   38.91 +-----BEGIN PGP PUBLIC KEY BLOCK-----
   38.92 +
   38.93 +mQINBFhFRHMBEAC9MOXvvFrVJWpK2SDYfeDsft4ExuI9lLTvi5bzQKyvr3PkctEW
   38.94 +w4Cr3kdNwbqIXO7diMSnbEJvh8OvvrII7hJcStpNSIIYZf9UBAAIIaPJelm26cxI
   38.95 +JN9SsBxAYuPrY3OzHAgNS+/QGnkXjQxI3a6rJ38kVsMavl+q85Pm5m3WUcNko+gE
   38.96 +YkSu5F7Fb4h7wyeF4uyHgPoSEA/qaQcqUoLT+xHyWDTUb+NBZhc4jO6W38FP2Gbh
   38.97 +kNwDwKQrrgbMizEys4qmysdZOYOFWvyBNcQ3/qlkF9BbefPwDTnez0wKy2W4jr62
   38.98 +l3mc8k3MU1+NBEa03uoAaHCHr3MeEbOSwR2MiCshiBzE4HSeadQFIeruPCYHD8Vo
   38.99 +kV5wwbskVPs900ILDuSSsjamKsQROSIK2F94yqB0U6cTEc/cbZY8cNLLZkYsziSd
  38.100 +uI86H++ohEJ+apr2BkIYWnccuziqTzIIFixDHdYe3WBkR+hooL5i327mG4uRjAnT
  38.101 +hcgtCPzxzBC//0ktF1aS63Q8FrpjQ9MFBZEmYNl0Tae/b6nO1aVh9evyeoAx+Bmp
  38.102 +7rl47FWNjQl6zBbBrLoWmz3D79e3IxQs0l7niqDphkOuQy4hAFoLCy21QCxXJ0FY
  38.103 +VRB6F9Fd6Ha8SL4lMBjfYpG0yU5EGJcCo7gMV1D/cdQ8KCHSEd7jUopBVwARAQAB
  38.104 +tCZLcmlzdGEgQmVubmV0dCA8a3Jpc3RhQHBlcC5mb3VuZGF0aW9uPokCQAQTAQgA
  38.105 +KgIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAIZAQUCWwwDoAUJBokmLQAKCRA0
  38.106 +NGcwRzQZ61u4D/9mRxSKqrCgblgJrZ4YYBV5FWIcD4yIe8TZ3vzqOyHwtftVWERF
  38.107 +3LbKYwYfaOAZRpL+nonA0UZx3DlSIRvnT5Ne/5NSHHsSrU/6OzBooHFWAn2lqsGO
  38.108 +ADL3a9w/Acdx14E9a5NdyhDyZZVr02ipyxtwKUgKae7i+mdjTvBBLrPfjg1kKroN
  38.109 +P8obk3qNaUeLHlG46WndLosAAEVrU8VHnpUCpxRU5s6JWu0omtPcpmWhaSfowogw
  38.110 +HGzViwoe3NxQLYwBZuZuOp5QmhemqKU2sBNxX0ZaNijGctYLjmO7qTgKK/IF24df
  38.111 +51362TNoQ8gBUQGVKiOM5dkm9YsXMoAL+ClsvNtMwasHvtvnXviTkPvjs8FnjX2P
  38.112 +UGGZhFvrgqvIO4eR1GyuvasOIQjLcTG58sWPuZLvEwcMtyinNVyvzpLPnkOlhaRH
  38.113 +F88plA5xrQT0bKLuqN0ve8jZvLJT/As9MRSm2ftZMTwmaR4HN0JduMsBrE4Boef+
  38.114 +9UQHzfL0Ivq3G/TzkmTIyblaPUvKLKfsZJoq+jjp2viX0EfnEG0rZt/dse9Z0C2N
  38.115 +hQrJfSAV/yN/uXriXinYb9dQ0k4Bd9+zHPE/mhZ9Cwv6EO4fNgy+1GRfy11NeJWK
  38.116 +D4EzDFuUY7gAkJkcv3vfag0WW65rwn2pOoe1NUPqlHxqW0fOYfZYVzbf2YkCHAQT
  38.117 +AQgABgUCWwwGVAAKCRAFca+8pUk1U2y+D/oDA8Q9X7BtRuVQFAvS9QjqxI0ZsN9y
  38.118 +kVhq6CnJ7e8Fk1av41ztWtUy7yo3DiGur71Fd+4tCcGX7ofqGGv4LhUDCUOzSxih
  38.119 +1LNKPsMjRZo1gMZH/TSyVYLVhW/A5LK2Zvpmyc34DN4iFrb8uJ8a/sW2LlAXHEou
  38.120 +LGnJ/qTzHtVxZtrnaKmTQdRovWfrDgdFSbK5ZXM7tfxfeeUVv2TZwZngM4MTdaTa
  38.121 +vcOM/jGjvX1CjbZYePllU8WkxgLPh+Uwrdqzlyc35gzR7agT/MvWbmNFcA3myjis
  38.122 +5CRW5b6B67EM6tqxC2i4jau2P/TRPoHZaGLxkhgfdbsBDxgndUDi/Rgav7FdXmu0
  38.123 +etgJRvKEfthpHFt7/U7BYeChg0mweJkKSRKWNj+P9aR7YKgFLtD8iNLd7lonEtit
  38.124 +Vxj22n8Kw4cZRyB0m9l5V1FkkROEVd++sOUhivVCYWP4SpGjUiqkpcW5UL4Envjx
  38.125 +7CKAgZxGUr4qwAIUsET2y06zEqywTPvxarbZy0ltQrEpBAflOkJ0NuwIoBaKSE0G
  38.126 +rl6YaCZ0JvjkFV79eFcmNA4apjkZ2yBhxqUjw7HZ3L3JU13Bw4y8iYiiWx5HZdBe
  38.127 +BEQcSK9abdyxqX+tH2ZL+n/FSIJ5QTxeQzpnihjHHXARaHDrFdUWU4JoVdPuIwsz
  38.128 +QQpPh74u6lPchYkBMwQTAQgAHRYhBArpqj4yBZXPkylr36FVrEkczPxBBQJbGj2e
  38.129 +AAoJEKFVrEkczPxBn4UH/Rxsl+mZSfqGFS3aRdIFM1JTEFZC53cfUxmbAk//V4j7
  38.130 +o9h27LE22T4n8UqT60fYelSg1Ks1TluR4SoHFsZMiT3hzWTu3LHydsaUW6NoG/ie
  38.131 +O8PuMPge0NVTmF40PRcUSgy8aqA+Q2BeTt4itcLyro/pZz4lbkZ1oJt2WG8b5qKj
  38.132 +VJCILCHuZZnJHDVN1dqv2g17UQbzfor7DWO71/+wdEsnsLXYWp6FbZJsnq0S3ENn
  38.133 +hcy0ylXnZbXmaAd4PctJvsuGkB2km64F1bE98ljSz1QmyNfvB2Tgr2w5nULZl9Xf
  38.134 +z77M+qo27OyaWMT/GEROVM3+a34cobKnjSFcK6aixCa0L0tyaXN0YSBCZW5uZXR0
  38.135 +IChw4omhcCkgPGtyaXN0YUBwZXAtcHJvamVjdC5vcmc+iQJCBBMBCAAsAhsDBwsJ
  38.136 +CAcDAgEGFQgCCQoLBBYCAwECHgECF4ACGQEFAlodK0gFCQO5GlUACgkQNDRnMEc0
  38.137 +GeuE/A/+Jvgu6WhQhPv0yhvpO5NFSYDT/P9Ez/BGAWF+Vf2yHufv3WZS0i/MyU0b
  38.138 +DEKHdvDOWnPGzU4kxGWwftkyGtVKA47Vs1p96m37PzbsSQh1gyedSHy7BLFt/92g
  38.139 +OXY5/Lt+5MEDLJSqmnW5rt4xc0zkg6gKlIYiu8LCYEtG/OAW7WDx0mHWV/bXEKBu
  38.140 +aprxU4A+1sN/VFI5SXILUHW15t+CczpX7yrcIlelB17+sgeBa37ynAcxBABxA83+
  38.141 +at+90s3Pxur4iYaWrAbKnrG62VV3W0uuYQNLfV7DKPgaXM6XbOhipIE+yS1EYnf3
  38.142 +JKzQl06G40atPPmb35Nkvfk/JgPF5byJ+uKO4ntsqa8XKt3GbRY2/mKiO2WVvd0w
  38.143 +RfyuEYW3H/gvv1TZJBEqDtbjmgAEbdnGdkfldV5UAcYLzzM6GC9zrKrPuGrKUkdm
  38.144 +9FRKooKJ5JS6CYfHlZfKipdAyQ9gGyfZT5Tz6f+1/xJkwO+JpWsZV5LUua6XzfJn
  38.145 +vA2lVT5RPRZ7y1D7XKzIs24cfnf1Y4YSIAiwl90DpFLKJjISQTlAJ7Bd/yhyv8/J
  38.146 +csqIgA19Lqpr7jApk9/YNZyj9AjFmJ/ce6L8LYTum+a/ccmI4x+tmdXGtyjTsH5n
  38.147 +mjxBrhiCct+NpR6paLZxKKtJZkLX8V3Cfsq4JajIccUOUcN7w3WJAj8EEwEIACkC
  38.148 +GwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAUCWwwDoAUJBokmLQAKCRA0NGcw
  38.149 +RzQZ69e4D/4xYImZNBUCADolemNsGn4lcGdgbeUtamUx9oycUEGBFAHIzTOkGtf3
  38.150 +P9Lhq+GCgS9Fi171RUwtlLpjriu+GPOltwTPKx4G4l30YrrmouNVzJlBOozp+jB4
  38.151 +OsygcNTxJqPywkGlI9F+O8zuBE15imjavSINV63y9Ypib+LnpPIOs34t4iq/jCdK
  38.152 +pVbMvNzyzgqBHOymyKh1CIq6UCpeWdbokJsBhknwhtWG/ZuY1aH6JwmZXBSfGsqh
  38.153 +241a3n46tIYWRbF4TCpbAJiWM/Yg5Es4tvT1tZMzIg2Z6TCQkZhbv9yv4vPyBICl
  38.154 +OPSH79J24hmbWF6hDdi8DVi0STDmi/bxA8kKROdhgc9ZKz5bHaVlyewYdNNPGH3I
  38.155 +/euATdTUBPs4g7n/i0P43XuyLvtOBG9m2KfkJmODOiwqlf1/RSDYOWn1uepAxOQ6
  38.156 +vfUm7ELwPx3DLE2J7PPa8fxg4Iph69UP9aF7aOXt61t0fn1Olttc5ANjZuTHYyvq
  38.157 +aPeRPoAmJY1RM26BAzhSdLYwZViEbUhPdmGmTBAJ98PnsvXV4UHI4oyDiZOtg5B0
  38.158 +CRc1jcdabl7YvnBauWJBGs0saHxvFOHXdBftC5cx19kO8vFfoUS6wdM6Ots8hZee
  38.159 +MIOIJZ+xwZSdVA1CMq4v5PrEzbfrHh6oSZ4AkJnFpvne6zX/7TAnlIkCQgQTAQgA
  38.160 +LAIbAwUJAeEzgAcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheABQJZLp7LAhkBAAoJ
  38.161 +EDQ0ZzBHNBnrGgQQAJRnVH0L6X3aNkmLwZrvtWlrfSNG56g+WNRH9KN3NsQ6l4dC
  38.162 +t0IHq9wXZiydTvM+knRnzhpkKNA4bE+mFpSngiC51huE9kvXa4K0s0/oJqfZGfrY
  38.163 +JeaeEWDOxZQ+c0cxAquRL8gB0L+nbEx0KwyKeXexi29Wrxq53Jc3DBJPeeC1zDkd
  38.164 +z1+K0GcnmSBnH1BxJwXqgXg+8wo3CmQD4yn8GiY3L7pRYG+XHgnNLLsm+n6fAyFV
  38.165 +H1Xsk/BRWEu1kWKI1PHaVL8l+/xd5c7Sa3duL41z0W86VHkD0uDdKwyaH8fcV58J
  38.166 +gUEAS0E6VdMO4GnA20hbcX+IqIK/Qpp7FtT0CdcPktJhMUu6e2BXgtL75Z+pmnk3
  38.167 +LpFVSd6pCUavRQCoXO3EiDgKRypqkr8MVKE5IDdNhxo5EHq+7oHyU2lPRLkAieUf
  38.168 +9ZEun+vFiYEaV+T7hqfX4pcFw6dTDvOfl/4lxzxErvrRf+F5KHIdsMtso2clS4FW
  38.169 +GzcnuG3EQqDQe4RFRyo9smCR7KfyYJmM00c+NSrb/SJ/YOfcqUErKpVsKvlS+wY+
  38.170 +M4UkFqOshspv+v6P9b5sDVWY1dwGHAgq+bwIlrkT1BuYKsNa8Il2J2h5caoc7k+V
  38.171 +221dFV8OQa3TQX92ftuLo8ayxX5XvlKRkI5lV2ExlWNPblMjsO83/5cXGm+oiQIc
  38.172 +BBMBCAAGBQJbDAZaAAoJEAVxr7ylSTVTL6EP/0PoDMuttnJMIK76lE5/JXM/H2+Z
  38.173 +dgPUN0t8YgkaKEjvTTcBsiJlt9cnxsTxGHuTi1fdkLQYO5c8LRIVV57aY5ocntl7
  38.174 +kIEoMiUUhiVlHMSaB9PE9HQYMalrtYqhtJ/c0YfIYt0yw1CFYYaNZjKqI7O1zbM8
  38.175 +yHCfauSYOtUgX8oTs+i0/MFUed1qP4EC5W9nRzLhSkzt8jqIn3O9+jksZLAGUUm5
  38.176 +X/4F9DIesdinnsZgYIBXWVVR/04WkLnBwz/f5EhXIq/lhvpde6fNNx009mXtUwez
  38.177 +NG01j+mqm36szmj0Q8+QGhNxuL9i6EGXpoT5HKYM+f+HqO6TCYIiZIBvL1N9J87p
  38.178 +NA49TldwwHDGxNJjUPGT6t+/UcWZ7oKylr/6GyWT9si4JwlUSNMRX2l/kELit3r4
  38.179 ++QcLyxCHcyS8x4pTmnf0jP6xFjqiCJShOo6FuR/BR3bTSwx4G1H1WRpEdeammKFA
  38.180 +GjMFoskoNY8N81eST6AIR/OSZ8RoBUoSb2XTgzwr20G0xz8UefGcViA2NwNYALPh
  38.181 +FY315+zUqyfRuqu7wFLjy3rwX8LZveXIWcRW8mH2ZWk+HkEsmWs6LFqu3OHqeyO6
  38.182 +afLSylzT4U/SoG5VHA6xTNeKMWPkLkQLdvsqU4CUF/RMdq6YFJqV3NGTaZ99yHxa
  38.183 +D6L1FnATnV+nbJOuiQEzBBMBCAAdFiEECumqPjIFlc+TKWvfoVWsSRzM/EEFAlsa
  38.184 +PZ4ACgkQoVWsSRzM/EElPwf/VxjzbUg/AMLIRjmLVScLKiHcwFfH+uCcFK3aw0FJ
  38.185 +J8abKS3FrTru3HwYBF7A6NmUX+/rgPBkKFDbQfz6rhLw6i72y9lkPYUd7MYsl3rl
  38.186 +kO/LIylYYdk347MJ8EQCkxSTwWYSK5SYvVecPtdLLiCJD76QOr0SmaFsCq0ad8bI
  38.187 +2iu7leQrGSfV6JITIoeQBhSLWDSfennZ7MJLg4yKskghpSwjLzZ3oidebIwxvmTi
  38.188 +nUomgTtP2pTnfSgO7wdU7ApgfQ5lTQIhfGr3LC/7F2qoeR8nJcbiE/sw0ZDvegJu
  38.189 +MJgu7Z9j26UzqakdZtCPABTJamzx6CwywTEZ24Viaf97i7Q5S3Jpc3RhIEdyb3Ro
  38.190 +b2ZmIChw4omhcCkgPGtyaXN0YS5ncm90aG9mZkBwZXAtcHJvamVjdC5vcmc+iQI/
  38.191 +BBMBCAApBQJYRUWcAhsDBQkB4TOABwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AA
  38.192 +CgkQNDRnMEc0Ges1ZxAAqJwTf/BK530mkJwU1gF/+7JbIE/PD3aed5pTQV4mTvEJ
  38.193 +fn6m+CcXCG4EpvHeetw1qLmmliGQP21VcgSgmI+fjTq/y9o+m24XUT45txsDGb6r
  38.194 +HHESh9IKhrPJtaSK7IyicUTbWo4Guvt0hEC5sFU0aKZkZEc0SS6ouPc2O8df5bwH
  38.195 +sDLNZ1ZIS9Er3VcQbEwelmFYBUowXxlabftQqFAM77Bkmio5ekMP9jK/6Zfqnw9+
  38.196 +wwb2vVW6XQ/W2mtVhNNgR+PJ71OuX1FeeKD4EGVQ8yE6HNSKB5bzDaW2+6beZqkd
  38.197 +7yvZ/c2hiz5DnY459BYEIAjkFDCNQk5/sAo9ApGENQYm6yScM08W81yiBq3BPG/l
  38.198 +Z4lhonIsG9FnL/FqqpUHKdNZSBmW6EdyjIZxg8liS9iha3JKDFanMcSOVGEquCbH
  38.199 +xV1WxVT/DSLHRgWiiqauqxZ3BHAcrnsKJySYEZzQ3i2Vtp1o1rlWSCRvn0Fh7883
  38.200 +e8j0iVyh6W8uLHq8VkgcMw/M2Y3gfdsRckWOrNkpmBeg+usZostPaeIj2AsYu1JH
  38.201 +hvLjNfQpwCwWngopdpJWexs/DClsAj6WcJYVwkl++pKqRfEKbFCPEriqxzZ4xQo5
  38.202 +eaVZcEcOxIt6kcC6XZNLorPAARd063ShcQMvugXGy5OMDO+mCvRBfjtx88jCQ4uJ
  38.203 +AhwEEwEIAAYFAlhFReMACgkQBXGvvKVJNVMKQhAAn5dYlKDWUp7c8BpYg2WQzNPZ
  38.204 +G835CbxkQ1rNWZbsxr6cjYpX3UNjhnFY7hlIWXdKB+qpURAQD1lgj3hpx0p97e+K
  38.205 +qqUroF/Y+hoLJ0j48G475TEKiL2HLSx4Gp1497BzH7yw66NDvAby0ujW8mj9AgfS
  38.206 +oo17qRukZgVkwYnz2zQ/cgXrnATi9TejimjgxucP3j5KQMbyIL5gvXk8bU4GWJ38
  38.207 +Y3HFWFXauUms+XZpP+J1B9Ucw6WylsblPGJ8ra6h9K4bVMAHP//PjK0jQsGt15Tb
  38.208 +sv4IFQ177/lJ2QAO1AlYAuuRginDQy7T9nXfpEXewbHbTWash0j3Yj0+paYLp7x/
  38.209 +5xEbLr2eG+gZ4Et2a1qeJJWjVhP1WNTtySGIAtJVAub1XcTApoq47KTxxLpBGOJM
  38.210 +eOzs728QWe2DAGXCu3Mevnjokzmesvx9nwhAq+bPaguheyt/PMWDkMxI9GgwlsDa
  38.211 +9FuAMZ6Ia3MM6CNkTxcg3PyD8/iRx0dUb5JXvXlwgw4QTUA/2UGf9qLqHTTxTV6F
  38.212 +vGRrrCvKx9jqYYpY1+hlmBEpPFOc4eiwH7yLugh8M2aAzvIHGtrSMHWe8sCEaure
  38.213 +jWWx7znH4KBe6JjaEIVHGVz14FBxvkUGO2ET+VybsTILhVECnxTM1LonEVJkCpTz
  38.214 +lB5XZxhPT/i7uGofUz2JAh8EMAEIAAkFAlkuntQCHQAACgkQNDRnMEc0GetR1A/+
  38.215 +J2phQTJYEqeKgWOzRV206dK1m+pGYWzM1Es8wtJS45hbV8xXrnWlo14JBUVC/mmh
  38.216 +j67/jrmPCnKMMnRfVtEMoB9MULR2s1M4wVzl6TJkemDNtAdgpBLyC+dBQQZyH0v6
  38.217 +TTJVhiUKsWxDR24C2Hkr54Z4KcruQv4QhHd0zUgSjyihTYdOjMpO//VaOmODCCoX
  38.218 +p48BWN2CMDeGCVDs9nvFuMDrQ1omFZCL+qZcAJbqOg5LJ/FEl+bf8noGIZ8BZphF
  38.219 +pVB+yW1sNRo/yFYboW9LiDdqENhc3Wjx/Qy9qZsThNaUuWNqLR+CdTpPZdhm5PnR
  38.220 +yBBuxb+hIfI4P1Vk1vlwcNkyu5z6gyeMOkVwEv69+olKvpwX8UhYsrE/t4NwVQCm
  38.221 +z5g/DYrGbJfz/x8cLl8h/DvO4lPAKkB0VgxDSUd3kIPQEgYgJQ1xarN3DKOyn+pL
  38.222 +/EEuWcYsiI7tA6NLS4vIxgojN5+G9EuCew6WALJKKfEgKXz6ExIgRMaTYbp01YxI
  38.223 +zXn7N3dQ22Orz14/hESncImQyretdKAtb5HuoN8fJKubvw8nJHihp7EqM64hYhUz
  38.224 +KyJa61/hXKhRK8Dyimwj8k2tTJqIG3bcax0XhhOHvurAFxV4YlQOdKeTk5m0tJ/4
  38.225 +kpVY3f9JWRY/Ug1zzPa8CeKNb/78v3Ul58S1fPnMpcy0MEtyaXN0YSBHcm90aG9m
  38.226 +ZiAocOKJoXApIDxrcmlzdGFAcGVwLXByb2plY3Qub3JnPokCPwQTAQgAKQUCWEVE
  38.227 +cwIbAwUJAeEzgAcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEDQ0ZzBHNBnr
  38.228 +Q/wP/07yFuVEWLuSDmsqKuCXhwH8NxG5eQoS/0bOGp1PQLe9Pi0PW3ivXBznFh7N
  38.229 +lgVLcFbWJ18hfbXh72+zX7EsZK7z4w11ELViGvVT+9BFpMmtXVbnfEAigEqMs4F9
  38.230 +yDZVnR+d8SKS2XsKEvOyRMjybGNezPB/of4dJr/ZDRaisz1nEoEBwx+oOyzokeDb
  38.231 +AnD/0hffxqjvkMuDIPDFn/u3W2l3As9vABqF88Wwu/anPja3+d9Xv6MsBxXMz77D
  38.232 +nAghUsJ7446VEWVW3u+PZRSqN6F+LFChoMUHqHyXUkOMoYZzqTRckGyAzUQtu8sA
  38.233 +Ep0GjWezp/8Hj3ChqgLfjVurJudJd16ez0Jk1PqKemxgwzNc5McBIp3nWC1PuJwk
  38.234 +UXwBcyypfjjEckUfgtRsPRhUwabnUwK59K9ieHlyk2VJdVkhnAIBvnxoAjz4tE2J
  38.235 +o7R7dzRffbKQD/ob4kkNjCZYFGI+MkFFdAqP7iWgNxljQ9CzDWH1P9SdIAwSfMWu
  38.236 +4LFdSV9MhDt6CveCX8l9hQI79HK7HdhszCTqDON1zRK3KPtmvcl29LCtL0L2CIUX
  38.237 +uxhQ+laV/6lALQBqg/wCmA3DQt9tDmhj7gwtAuo2RPAQB90LBFrGvdN1bX4qGx2q
  38.238 +xIvGXlLSYWfuFA0mxwla90MHAHEGpMNDBqlrI7Z+zs7kKNXxiQIcBBMBCAAGBQJY
  38.239 +RUXzAAoJEAVxr7ylSTVToxYP/0ug4SViM4P8PrhjT8zuwI2yuYkY7PTSyhJi6OLW
  38.240 +/ngkXdpVmDy5TjSX/GE0QYbARa7MHmjzKM73PA72o0de9EFqNxU0rOMRj7Hxh50F
  38.241 +17fw5iwvYepKdku3JeZUB8xZkqQxFOj8Xar05Y3TfdWgCpneEwMqhtOG40DMHUtp
  38.242 +m29t8q/hEHUG5zI8j/wgNnxQFS3Z5vfsQvbGoDiPMb8qEfEzYlO/CEQhPGOQFgVh
  38.243 +ooYUJWNu3ZWoroyvGys2ANeibH8yLhnOPMVWMBMoI35ypmLLaier5n0bF9LQmPV0
  38.244 +ZRifzltfWhITIh+MDjAnQM81QiGSG+a8AaWB9mjH27C6VIoCtjrvBj3WfeHbeDwh
  38.245 +I6jmTXj2QCbiyHhb7Dym1Is11j5pL1m6rK6H6kF446hmaOielUXazASrUxmRsMLO
  38.246 +s7QiP+KC01KATEOtmRNXbu8rSbaePM3Y2Y5Hvg5d2GFloWraRQnSRj+gRcDFJtEe
  38.247 +ZAz7rCrEw5K6FxDBuO0IVY5WhJ9m1oXkepNqfsNRQxxrqYobP7IxlojVnF2guCuy
  38.248 +9xEO9Hv8b+1htoT7ERm7UlGvu8p4OqYp89gAYUVXVWiiesxMItCxWX75lPVLVnKy
  38.249 +k77jHz6N41aPYBwnzt4fQx0iT+/Ss6+zEZA0Swboz2p9dfws+uPIrUwTYZoxVLx5
  38.250 +GdPHiQIfBDABCAAJBQJZLp6fAh0AAAoJEDQ0ZzBHNBnrXnIQAIA2U6ct4eFyhDhG
  38.251 +mVmARMaddXWpaPS5xNFgWCvbZqWfVMUxEe1/BeHiA4Gkd3ew0Hudz9GXkt43LFi8
  38.252 +2uZBUV20lL1cxneacQt8o4XUGP5+oiWmuTjpSJmG16uqoEhHIpKnZIoZPDgaEtZD
  38.253 +P5TT8ioKOoM49OUT9nWmRu8dSGdCRqny4cn3Ygxnkvw645ZLL+BV49d46jLRIg/E
  38.254 +uGsDviM9lnF/rPaHgDqaZ7LyLQ/ZIHt8sJNXYl4JHWhspw9o0rlVosir2Kw23g85
  38.255 +a3wl1945bDod79PuVUHknAGdEAxhLz5TLFlGZAn354QCQdhAAU/LjjWEhz7lfXoL
  38.256 +TEWwZfu28zziPrFKuGjo6+Uhrvn87Gznb9crNpYyao+hUxWRVY+eORqIT4mnt3no
  38.257 +u+sZXFQqbrJPsWFpAU8NUtrz06psLLuAAbH6fU6xp8L7aEwvKYzaDCfz2nqMSTKt
  38.258 +yxFG4omAcfKG4ygilDYq7PdRJn+AI3jt32s3tKZwfS7VlF2yo63lSqq5AVpzUm3c
  38.259 +iYmKdMsuJaugsmOnMUTuMOQipkIt5QJ78DM/LmNy0dta38I24DTT1O4/jF96yqx0
  38.260 +S/2+AjK/2mvEDCpR/C6NPrhk6o0QfzCQLas0XbIwxI3z5GVM2D2kZ3+fW6NHi5V7
  38.261 +OW8EVGlsfArj2fr83jqfo86NrZgMtDFLcmlzdGEgR3JvdGhvZmYgKHDiiaFwKSA8
  38.262 +a3Jpc3RhQHBlcC1zZWN1cml0eS5uZXQ+iQI/BBMBCAApBQJYRUUcAhsDBQkB4TOA
  38.263 +BwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQNDRnMEc0GeuAxBAAhKxzf5kj
  38.264 +W+YA+pRA2r+e0R9sK3T4MvJm3tGlVxTr2yT3xLYyKm0KZ+2XeVpMf8WxJ7yZy0aR
  38.265 +R6z9QPBaXO5QUcbk+BvT4kSQEfMYgHZtzBp7tgsyzGV5HogLG3S9Z12V08tYVcD3
  38.266 +TSE0462gZfxrvYfvb/yP4J/0PFz17XwC7ATrEbeSllx9D3m9xi8BhGfkCgR45V2r
  38.267 +7A/oTNhZSaHtxkHb8a9+nzMNd8mgtOCdhOng+pzn2YRSdP6iBA+qabunCY3op3VB
  38.268 +RXoOPpz8CIMkBK5nB/+45Fi56stnCzblXlD95ec+DahW6AYsqXfQCIF3ff9f2KAR
  38.269 +JB+9tdp/8ppxpy0RxOz2uKSDSDaRVVfsG7qj0SJvqSH2auN7awgGpOXC3x2hfA7L
  38.270 +eCb0lISbWgNPlpguY572LpZwGFKz1xvwMSRARVsPrYaH8TDnTDWZcnQEasyxpsHX
  38.271 +TZrnsEZcE6nOaOWDjQp8jsOrD/4gUrIAdgXd2blZGxnD0vuhBVS5MQwn6XpvWEMV
  38.272 +gMMDpACi8eUZ15cRlGawmkw4zjCrX5tyRCaId5EMvYhBW3Vnw8PnQc/S+4P1XRwO
  38.273 +vFC9ijE6zEGYLGl6NoZdBhhUCJnNtP3hCO5WnMifkz2SfAhPxxslRhtdPhAo0d0v
  38.274 +3An8JzB/E9nnHUCbBeyzRw9TWpfSLImvRrSJAhwEEwEIAAYFAlhFRfMACgkQBXGv
  38.275 +vKVJNVMVvA//YfKpjSmjs9agqWzJVhyP5yES4pAPKP/FRC9Mm2gUHw0eTCwN5pqY
  38.276 +DcRkyhfEq0yOdfKTWrS4g8Z1fCkaQS576oTv8L4msrb43skhQVl1QUWGNAcNQxZD
  38.277 +4p396YnqPDGkkftr4ac4v+SNZFJntNs61Rlp6WwKcF7rKH2qIE4kmirrQisNiuDZ
  38.278 +5Y87bujhgtHRc+PN+5uu9t2gymH8ydf3R7x1lGYbF6AmRvEg1cW8UBZAF41b5TJo
  38.279 +hOoXqmuUZaHmeMBaELiFDbCJ5h012xT2wbjQeok5+DRVRDqPASBRN/Y+xvjMPB+r
  38.280 +U7LHCLRdQa2Jdd6X22QiQafQbY8TIuJ8wZcfSdSCtpKnxEPQcPMQ+NbTrmLZk3fb
  38.281 +nO8qJ7TYZ+YO7dUlT17dO8Et+vHWvF+0WFsFFcw/u/gUzztrkcpNaTRV59GSOsta
  38.282 +KCVs10NXiPmMKBRm2yEAX3lxUnxvLTPfCkwI1aHuz5IiaLPQpSjtTbP6LVtrK7z7
  38.283 +x/N/R8if+XofbZ3DoyMykD8mY71vMz5h3iOk4JjyfBo0W+SLAPhxCCfAV96OVKUx
  38.284 +oRjViYUAevnXBG8KtRNVA6p1SUzAx3XhI6tbm2DWFQIFNpxqVX9fPdBLewx9IXup
  38.285 +sHENq1BiOsdasn+Rn+jjbNAle3NUoHSP3rnJDUkJL07kE/Dv6bbo3amJAh8EMAEI
  38.286 +AAkFAlkunrUCHQAACgkQNDRnMEc0GesyVQ//RwC6CO8a8Qk4OL4DGeOMIVAYS+Pu
  38.287 +nqOSL9U6bk7HggYVgbK1vJS7hbrtuXp2RMBl16Dr1HQXNwflTBB81GkXJF2EIp5K
  38.288 +oG+zfXFElOrjyU7/GJbSlI13RPSWvqlZxdGDiK6gqPx/jVYKjeOwhBf4AZ5NZOc3
  38.289 +3kHEFZeRJmt+0PAQa0mNtAPw+Zrfg4yuS/V6c33Q5GV0J7Hrmow7QTrLZK0QLF2F
  38.290 +6Axv96aF4G3E3qlFWWMtyDWB4asOl40XLyWLdHseV+dj/k37fZOeeC1wJat/rySC
  38.291 +kpC27vT2NS3TLT8M1wy8/Vf4QWlPKjCTxbV36H733pVT/uIr6fEckBrujSh9PTt/
  38.292 +UqzNE+NC2HMrmR6SgTtSxQe/pVfB/iNwjhi7ZGoXQLvv7ZFRtZlrhYjMOZNvCQHf
  38.293 +JV5jx89p9B5eUuVlEBs0LTPeGhMkXemd5awnPoDenmbQUiquqqurfqFJY7xICVrB
  38.294 +V6yIcbyQIhy+XtZwMBMCZgBiJ7kcprIwNIBIZwqmuoh/51qADEpjSQzu+NgS6/DG
  38.295 +Qv9wJva+Kj177EN4WrzgvUynhivn7XhQT5OpqtgA5FPTdqKZFvzODsMvBuyzwyek
  38.296 +F0QWNIhdqvcp3i+fRvXMfDtX5YYX0rrgr1S/5Umw9e7sMDoVAdwtciO25ZvbGNrE
  38.297 ++kgsSGxu/ItTkcS0MEtyaXN0YSBCZW5uZXR0IChw4omhcCkgPGtyaXN0YUBwZXAt
  38.298 +c2VjdXJpdHkubmV0PokCPwQTAQgAKQIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4B
  38.299 +AheABQJaHStIBQkDuRpVAAoJEDQ0ZzBHNBnr6acQAJgaFd2ISl6tK9tPx51zh3vV
  38.300 +YUYv99a82sGU25geOc3TKVfssnpLkMzHcXbEEckVyn2lvs1Q9TaymC2j8BDs5xwD
  38.301 +esqu2uw6b0R01mlYhy1+Cuz4XNo434LUyT1/YIOYzduhrlBmZ5B2Kp6tSBF49H7g
  38.302 +MmCZ1BokjwI7JO9ogyzFdx8zPJ1S8jbV5ADf4QoS4p/GkywpPzCEgOkzMAkZ0B5I
  38.303 +epnmQPNtfPzAHEUnUGZk0Dnvw3BoxH0PeacpKNrByJDMWhyQa71f51ooM9vVm+1D
  38.304 +kjptImQ24/K3k+MCKO9aMeE/2aOkSsT8btvhLga5iXBGHygYfhwRduXJTLcCuMjq
  38.305 +S2E9kogaLm5eQktwXswTivhZgBIgKetFot0hfdTnZpc/AANqajZeE7TzDs2J8TxM
  38.306 +yKL0YpyEhZM7Qa7BIAP94STZfKoRN84CCz5pfxp0e85NN7Aka5wnYdsetNqK5Arn
  38.307 +tYqDuChNKurjRmvj/EJPiQpOTDevQJIUBXYMlPj/l6WW6imSzyhMqu0dhYV/KDvO
  38.308 +mqC50mTSypL7GI4VL1bO5OxAq86xwwrWlnLF0K2yUfS9bAVT49ENL+n45Z2k811x
  38.309 +5gPADqp+thfT+JvQQGQU/KnnOc//AqEA4lryvd+IPNSYKdiPCcMjfr06ZTSFxl+W
  38.310 +Z32r1lgcD0ItVnnpIVtGiQI/BBMBCAApAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwEC
  38.311 +HgECF4AFAlsMA6AFCQaJJi0ACgkQNDRnMEc0Get38g//QbNpYEHXttxg+4FKRnnJ
  38.312 +LPasl+Vgn7S9b4ivDLtcUwYbd2lk4l7KXBPGBPz8G7k+xoPdooMyojIkj3mjyAVZ
  38.313 +BSMZ+rJJVzC/u8YYmuY7GEuMEHxWPLJGLVFwGAjvEewtPCQlS91w5IrIlkLgrVoP
  38.314 +HC9yhtGfcaavKZ2+UHf2ISyZ4eTJpEQ8w2WiOHXS/JN/o32r3aLvsIvbfyEAPh13
  38.315 +U24lYtEL2z5n7HMtuh3mthd6uI9V5+WAq9vRKubhyPj6eF7SQKa/2ry1yspHo/LV
  38.316 +a8pvUEL7uihZxAwg0p2+z7fEYyau5ce2x6lGHI3IimRN+kozLXpFHRZqtmTnfkIm
  38.317 +w2k/e7YfzGBql5AKpn8WSs1P+2LQbXA0qkOlIhgLcfjGUfRUoLyRF4DTm6MEjGZW
  38.318 +N7awVmuIxsmLlVc5i6CUcaxWTE8hT93ssfrL7hVEzb+wH/9ckF6FH+gba+pCvaUq
  38.319 +Ssf0NWW8nNga95qBW1Ii3XYH8SF8XI0qVGC5MDqHbUrzCLHH/V9U4lyFde8Luvog
  38.320 +3cpiPt51IwmLPoo1v/bu7g6696HPRiPaoAKjZsPOejinmsFVmCVcEkylMLx3ycoB
  38.321 +KzxdVKNGlD4gJA20tysfTv25ZOaj6/WXI5rGhTu905w5UoWgB5keZ/npRKhDH7+M
  38.322 +nzMmuOhpIOUAbJY9TGCQaL2JAj8EEwEIACkFAlkunsYCGwMFCQHhM4AHCwkIBwMC
  38.323 +AQYVCAIJCgsEFgIDAQIeAQIXgAAKCRA0NGcwRzQZ62qQD/wKX5cKoICueycy8MMR
  38.324 +0YlSgji8cu017P9EsAVThyTeWAgjd9GQJ2dsWxDrPynU7uKEJ7a0GZXi5xyrGFiM
  38.325 +tKhgwVegbWt6OPknUoAKZGzjGyghoIfRNxQJLJ5Hq085A+Gyh+6jIP1ahhL7OTAA
  38.326 +4fZnC4SqLCdoOdcx9+Vucr3wUHBCayrU5HR8GiHdlj5J0eZij5FuGGHIx+sbXAiE
  38.327 +NBPM5B4eXvKhTvCKUs8h9/upcrPfk0ZRxeoh/BxQUOnTsz3J5QXaJHc0xwg3cfXO
  38.328 +0vE0/+6fpCCpniMliDBOfTsX7PbD8UYbCV693+rjFVkOnipyBY3Zz4aXR8Bojpt0
  38.329 +jSRuzFmVf6cqcCJ4knz/ekPmebNayG/NYkAEkAkmGIh1VbQCngufDrFius+sBzkt
  38.330 +Hrmi0VVZRqF0r5zSMVM8VAowzlmnmO4QR9fJGtJ6DjLBImLPJAH0CiNthDChtAU4
  38.331 +XPegZmbZIY4Ox3K95yrKzmhbgE0RhshSERm1D74WTfcohWZurLQ2/bJw3OFWOUaG
  38.332 +GYylV/f6Gzz7iMx7s22PE1xBlwjD55eTnszQ4HiQYGV+2TaQIfRVm3vB/+NQ4LZB
  38.333 +q5l5idrNnE/MOut4XGbes78Q4pRtXQ1yJ65ciPeiifkBd5eE0hL8trRRoObj1JPo
  38.334 +Cl03ggiT2+mEj3/lTB4mgcJKzYkCHAQTAQgABgUCWwwGWgAKCRAFca+8pUk1U9wM
  38.335 +D/9c4liSGCPFbBqg2bppnxPucZU5vc9fyY2u1D7l9RNlXAok2InABdswoy7iUEn4
  38.336 +8TlxuTU0+0PK/fSNnkCAVfYPYAp/Okmn5B8g9gkBqMgTd8freN9VWTp2lSlxaFf7
  38.337 +0u02rpYx7nMCawTRmWhDOtl3hTEpEvtKuNjdjtW0Mz8zx+FnT9L2+e33+ykOEfYK
  38.338 +mIO01tirfyPdKwWAsUSa7C9WGKR2UwVvTcZVd1HOfCktMh4ELAnHaV3jMERbySsO
  38.339 +XEuCmMJU642yvVAKOFt1bRQcvpl0xVtvBph5kNuSksugY6YRUDSBq/bKyegAcjz7
  38.340 +OtdWNzU8jVUbBELe/w2U4D1C18fSJahkikEnemIBZAdTQqBPKtlvFbmCnEB2pQO7
  38.341 +7SpIJrKQzD2LV13vlqfY8FsqIBJ4kQ+PHDWVLrMx7kGF/Sjl0Y5lN+kXz3UNlJ4x
  38.342 +R1yV56gmI8ZM+tqcCxE3cr8brmP+xxkEC0KgmDO11vYwrGdrSC0PnIRrqpCu85qx
  38.343 +KmkVuE5rgNVfNJ7qygPcoQvgum91OQePIfHNusw1Ms1D+D/k6Hab5cC/oOCB8QEp
  38.344 +s4vH51MN6+z32W5vXGWTCA38AvkeDc7AqrPCfZfln94HoUP1VtDcSRjyw6vXnzRe
  38.345 +/ndTSemOjQaVOCYA22S6wpDs5GzjN+0t2GcQk4bSwRLWwYkBMwQTAQgAHRYhBArp
  38.346 +qj4yBZXPkylr36FVrEkczPxBBQJbGj2eAAoJEKFVrEkczPxBZPkH/i1MI+W8srfk
  38.347 +pO9WMyo3bTwRM2LEEN1LCVfXhXxqUbzbjERy50fpFHpqhBGcUssCZrmwwpDrtisG
  38.348 +eNVX/SqHRj05qJW9sF4psuoh+jO3h5lkvQA0Ub/iIaQ4wKgqs9oVwKrMTwxbgqZa
  38.349 +DH4PbZdpMILISeokXIvJ2+cKSpNHXLDFQZGQaFiuFIrDKRG1mnmZrfpYekEXHp1e
  38.350 +FZXXx2znmYOL9UF47TaEvUl572f7rWkNcXVaY8xSvOqOo8vdsv3Spjkjtjn7+UJw
  38.351 +l1rTLAa7geepzFYv2T2PNFYByBGUe/XCe83TxFgp3EKzrqu5GOvkQhYlmltkxKSt
  38.352 +YZZLGCA6iPu0OEtyaXN0YSBCZW5uZXR0IChw4omhcCkgPGtyaXN0YS5ncm90aG9m
  38.353 +ZkBwZXAtcHJvamVjdC5vcmc+iQI/BBMBCAApAhsDBwsJCAcDAgEGFQgCCQoLBBYC
  38.354 +AwECHgECF4AFAlodK0gFCQO5GlUACgkQNDRnMEc0GetWoRAAmr2v4Fe2vUn/kv7t
  38.355 +dPRvQK5fCvuOpAvaJLOjwePobuJa+ItCxM5rGTkCKoCX6hRGc/wpKdZB0Yd2dv9O
  38.356 +SiAdiyoOQOnAtt0+pFvcJ7w5bOjWURi8sWxj9nYvXyGBiVACUvq6ApU0pEifziE1
  38.357 +GmwfCiftyK2nKq9my8vEnPr4pkVzF8CkJdxmO8Ufu1ETKJC+4LW0R7pwWtvTnsmZ
  38.358 +xHd7A1r93mpygMDV7qzDDz6RRy1bz+HrwUGuNlyCqbsHEjgOE1EiyhblocGFI8yk
  38.359 +YG+vzSdWF48Emz15CBVKRTfnkN/QWsxEJZAhTHvHPb8McDpQ0C94cNuRGL1P6+gV
  38.360 +aRDHq4fWJc8V+kKSjB2HammVyZmk0LYWUaWMBoNlCOVrnloDrOjWyoyeh4zPfbWU
  38.361 +k1H2Tr2VIsYjXTa/ne8LorDGWFKDrbl5Y2VzOMl2FYUF8WXwuC1XEud3YZ6SLPs/
  38.362 +c9/FBhWHg6ZXnFshgJkiIPZty76o0mGBWsImt6SvRcef8fBmEBmjFAt6QyP0djWL
  38.363 +qUGQ2Df7cfFLMt6wjesEcyjQGaAJgXAAlN727F7bOA0lyaCRKx5W4leQhboj3khy
  38.364 +gL9P7HG70iF6kDE5gw64YPe5AhV8nPO/D7wHo+dqrl1TvJGF7Bmbw25cMbHwBwdV
  38.365 +Ep6Xf0M3fBrrf/dzEZ2D+pGkVhSJAj8EEwEIACkCGwMHCwkIBwMCAQYVCAIJCgsE
  38.366 +FgIDAQIeAQIXgAUCWwwDoQUJBokmLQAKCRA0NGcwRzQZ617DD/sGjFOBPWitPl1X
  38.367 +ufY3xkkrAEAnVXSzQsLT4y6HF0SodmPNgn7lOMT67GmDDRRUCKhzG9+vRcjzswTf
  38.368 +wo031/ciXYxG1FrdA75NtvDRNio9yiyRurLJTt6nbZgX4TqV0ug2ucysxGZYVNt1
  38.369 +d9H1v8FwzvJvsE2mDw108mv8dVTjLsLL/BXh3Qsb0kJ9PSamY1WRtabz+BQtv5gj
  38.370 +NRNzOaGFLiw7iWdIPeq7dFjdzyg6I8dLlazolFsidtZQIlnfqNTrBwBVLRwe9IkK
  38.371 +VkmsTW8jBCZ8je4GSop8r6V/Uysq3w17/ecsH5VPwuNVRtQIEEV+ojXCFTXCCwKk
  38.372 +xCUYLsrZQG+3Cr5ZtIBH+xxplx7dbC55DWcC2Rb/+iBR3Z5pyDrzVlD5lTZ1Qxru
  38.373 +2340WVLWcE4EUhHkgKL51+1wUh8SPJph8WiyOTHY4Ncs4ZzHwrwsT82zBhpMIyD6
  38.374 +gpz0697HFV6gtQN5tpAHPfvWDgZdsquu6xnHAPWwDWVKjQqssOlkSOayN3ibTULq
  38.375 +VW+FHXiot6no99vY3C7MwBMG8H+DiiAuwMZvjwu7QF/K9e/GtcVMIjixa3JkMcK1
  38.376 ++KeBoLhC9K7Re3M+usBMVl661js21w0US3AFtwhi8JAD6CV+f1EnGZ89pbPgSDYl
  38.377 +EI1oh+J54bj6Jt1wWXB69Q20BeFpj4kCPwQTAQgAKQUCWS6e8QIbAwUJAeEzgAcL
  38.378 +CQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEDQ0ZzBHNBnrVZUP/RAOy8P2I0ad
  38.379 +eV1tGLLd/n9M7f6ntl9vRQOQ9f23xFk3F2iK5JgYX7sCute2lPwqjBewUgxt0PC/
  38.380 +NnTWLhkb5DsJgEfD0RVqWu/KslWRI/kKvcWE7+s4M1Iv65eLyuMWMGmCLcEpRnPE
  38.381 +XOs9qu83W0N1Mw359yc7Z1LUOZdvp2uVXCYSJu52NHV66Lc8tkPcua5VjpD6NrcA
  38.382 +QGuHBtvzu/XpsJZ6AAWskD/gUCCYvFvgIzJ9IFFB3SQXC/ZTKveginNAcKifkJzq
  38.383 +ju8d5nJo8N0D22sYsP7EbaqZbHl4YzwmiELz0uDg5KJSVj2sC4IzWXm1aHnZDV8m
  38.384 +FdflUTSeG1NR7uoey+yf5xRht5AL5AmbOdlL9aWQzje5bqj1oXb9HqAWfOAshsrx
  38.385 +Ygz4PT7u9FGCpZ9alho028yEpZZkWZejLi07M1fQc4kaWMHHfi0aMlYdELsQ43o7
  38.386 +5aspJ9i39aVA1JRXAAB77b/FDNEPX4RbkcX6dyjDdU9GqhE7CQcjJyabxUGwR5DJ
  38.387 +NB/XjFubVe5CCczliqAFY0FHjXEaBoZvsrE6mkc3mGhdyU/016Mpx+lbQgTi8rNa
  38.388 +WmOrnQmdoHhKAuC4KFhrwlalez1fiLdl3tdFXqHuDehB4zLj+cZcdq/5VriKGzI6
  38.389 +5Qrq6HidIvFfJsK67aC1l9dGbfqgvgSUiQIcBBMBCAAGBQJbDAZaAAoJEAVxr7yl
  38.390 +STVTFUYQAMUyyDQO9gMbS549V4qpl7mVzzfqtyWmfYApsKuqrvcYVZZMO1Xl2ICy
  38.391 +LypNsZ4+Z+8HWpPc0gxWpWcdwi5uShS38OEoQN9Oj89EJzZE/guZmqfTK8W4prcp
  38.392 +hoPYOdKWNeF/pHqef9b19TEQfiQqktNsD5YRuvuvUObAWm9JQdDB2C4iJRy12zhG
  38.393 +2Y8NNnq8eZbQa1MgK1EJPvQo4oIOh+e6sJ/G1swFZevsc1DzZX7WWd07g60HVXTo
  38.394 +ous9yHeqrm3xEsay1c9tSvuWWIyEDqTiwp/smjpPMcwt4vAp2cEZDNylB0TeNifq
  38.395 +4PWYAQkSib+B0VEYSPxtjiA76T8kQn8+m6m89fcQWBm9ldgxVO5IY7P6WTTZsnRW
  38.396 +TOXx6tFXVC2c1XktUGxUtqHwOGh4E99Nlysl9f4N7DLEd9wAdwmTcEYpFQp5k73w
  38.397 +briLCmkn88kN1Vu3pVovmRIaImP9nTbIe1jYQcQrIzkdqIYdYENXvlfPHLT2+2z1
  38.398 +z73CxDTsOScwS2m8MJPGrMB9YzzwoCv6kf79j19BzXcjpteddR8z4o2e+J9X+Hlo
  38.399 +plwOKIlwwHM5bYRwq0A96sHyLzP3KkTZbruZbE5wyG2e/hcftQ5pYZ9HfnwuqN8b
  38.400 +Z7bB7p3rvBOy5p0eR1a20RQidw8S3gkSzKuDMsdcZZN2zamHkCmTiQEzBBMBCAAd
  38.401 +FiEECumqPjIFlc+TKWvfoVWsSRzM/EEFAlsaPZ4ACgkQoVWsSRzM/EFtlAf6AkR6
  38.402 +FJ7GSwq/vaSSuZWkHylgSxCLpzXePFmmvJLSuLr1GNATwlxNpdaoN5wGxvFBRlD3
  38.403 +tAZ8y2JpOx4vFcBKoRkGLpn2E+S9TS00JDXVQVE1wB74sG8REm9UwXv2jeAA/VI9
  38.404 +xlADtSbKB1qM1QMCeysBY0pJNilwe1lgSatLB9DXxpsth1hs/o+Eo9pR/3aW6U6i
  38.405 +jOBl54q7Y3oqcXUrwlc+jWgXl/HJWP5OPllikxdG3jFbT0ChrmQAekICk9WOmXa+
  38.406 +vO131CWUgXhzQtHKa3fuPfledIKopH8vDa402q2I7GsRXqkBV8ETa4lSRvoMHEd3
  38.407 +YyGCRl+r4SngBAiE1rQuS3Jpc3RhIEJlbm5ldHQgPGtyaXN0YS5iZW5uZXR0QHBl
  38.408 +cC5mb3VuZGF0aW9uPokCPQQTAQgAJwIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIX
  38.409 +gAUCWwwDoQUJBokmLQAKCRA0NGcwRzQZ691lD/9ySDQYaodPF9pyRDEIjJyjtC+9
  38.410 +62a37kQAg5Z2/8HxbpKdlaIKJ0NQxbaP3v75Yr0uvHCokdqTi7QLCntRk7enIi4c
  38.411 +OLAfzSlYplJouFULWT1AHf++e7Ydvl//TsmSyO1m/cwrE+5BkQYwpNwwHK50UQ/P
  38.412 +qU5USrc4vJ98iUg9wDvKqTrHA3ql09qeYC7vvzecZyb4OVPsw3mP+LX19Jz+13A0
  38.413 +4mNd9+7g5ohe9v+4+SkSi0ZTgT2HCHP2gusHdd/QCnr3PacHmmNBYrJOkebYt5Wz
  38.414 +mOKIXYpa0s0sHn3iJfDeEGi3Yfua2ZwDaiDvdzCPERliv+oFk0vYC5t9BrbvgJTD
  38.415 +Anr9JJmyevZ+QXKjyhUqguSZ6lzhwWLKPi1W2eGg4Pzg7I3yZPqOlux1xF4t6t4n
  38.416 +gczdQEqPIqy/7ZqumjhDN4BGlOYJEeQzdgi2tMl4U5WVsp5cZ2RlJHXpQlcKcuD2
  38.417 +W3QKzLXLEZr9o00igtTlWXCh8jzA2Bry7qtwnS7JjELLVmge3/tOYSZvFe9xXNcK
  38.418 +wdPLkA22OA4dm488pwlmTFKdE+DE+Inft2QSsmzK6L184pMFcqGGPqfEEPNlxqPC
  38.419 +L2fuNyca5oKSWR5m5LPidT4wJ+F4ddhq9AIVn5WSHNZRfHJg2QbIEWct7T6/tq2u
  38.420 +vsdUwaMvR3/ibzehi4kCHAQTAQgABgUCWwwGWgAKCRAFca+8pUk1U9n0D/9axwQ7
  38.421 +QSAYUVglXYt92EAE6jgqk/cWf5uX9av9GzzrzIPTB86KLrOL+yUqIY75mzseMncJ
  38.422 +aEf4mfULdcM11M07YOdcoHT56WkIyFHqN6kgxApu5LQHJQmjpjPe38+3tbCMQbDU
  38.423 +lnFdxmVxvhfVp5yz/luvJzXiwFZ6f8lmrBOJcOw8JNIMldo/LZ4oHHowDwgIB90x
  38.424 +e+CLfw0FQRsuEAjmsyCwO10ur0O07wLrh17/RhgTPZGT1Q8886THN0BOtWImRphc
  38.425 +sRp38MjqV+UrWCd6oUDO/tbucctjtohj75D55CU9bqJfByX5mNG6hQwsKPK9hc10
  38.426 +vAStvk1/Z8WQ+a6nHcL13pi1trZOch+XH1R67w9WMbfw9DyVgup+AumkPsRqsqF5
  38.427 +WKtrXOUb4kc13aWFMsIm/nWn3AHR4NL7BZk+YUNsA1tSRygSwgOAVNXQ9W2xH3VI
  38.428 +hiAuP1CnUJr9YsLfteF2tbVJTBSFlpcpZudBtrKVC4odPD52ThITMj58SXZ67THS
  38.429 +YAtOHzzIKeGnDGhb0tXj2Ca3WZVttIRKkH24w926mVh8HcaF0V52ETv6xPRUEH5d
  38.430 +jI+y3Wi6yUQIwo3+LXXuhjAGhV1owhpwo4J85zR04eAKet8XpEX3S0dxHkD8JRB7
  38.431 +hZeVZJfdkorYeK8pmLeBtpyOo/Z6Gc34GjsocIkBMwQTAQgAHRYhBArpqj4yBZXP
  38.432 +kylr36FVrEkczPxBBQJbGj2eAAoJEKFVrEkczPxBuyYH+waLTZgUlfaAd+JeLrsn
  38.433 +uS9kYvG7RtBZNpVLtG7XJ3td+xiCLS7APwXmUmG2si9UxYrj1bNHJd6CNgt9tkWj
  38.434 +n/V1tCsLcTpwUUnEnq1doYxkzFnJACItKBPUEOaHZuH7heFw+vdjBsdne1wlq0EU
  38.435 +ECgfF8BoAMI0ohfoOf6j9VZat1Vh5GrZa525mVwTgw7exvTjlo8K3lIfIXag4ylp
  38.436 +4hxw+tqTAhV7s3+Ju/f/GyIYgJ4gCgvXIosFWSWc8Ar65R4NrF/y9wsETBNmrpYN
  38.437 +LvfpAEqAiiPtTJFuMl8DffsbLLN9VkeKDMh1aZbn58QOVrTy+Y2BFiwn6z/LT7nD
  38.438 +uKK0KUtyaXN0YSBCZW5uZXR0IDxkYXJ0aG1hbWFAcGVwLmZvdW5kYXRpb24+iQI9
  38.439 +BBMBCAAnAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheABQJbDAOhBQkGiSYtAAoJ
  38.440 +EDQ0ZzBHNBnrbjgP/RDgsbGW0HHfRzqRICYk6sD86aylqXh+PSG+DFd1BV6kupxH
  38.441 +EHZUgma7q5bmYAnCyhePKVjwfbN0KGITX8WDWHdx0be92iVPTFg16kwemGllqewJ
  38.442 +DZD2a71MsmOYop0Hwifdzn+eOtAk9Bs61WYklhbDNxMJ9PUR4iujCnUby2VlX/zF
  38.443 +Lv8Sb2p4kPEikesHMG8doiaxRi5e9rSa5N29y8bBkTVYf177Gc7bWcDZ1F/aBm0W
  38.444 +CklFR3W7Oe9ugkeW8A5yIFOhiXG1bXbjBss6/PbdcOD+/DGtVHRv2jHEQgmID66s
  38.445 +a5vanHrKNw6W6h1OaCpRsD/3eLB8YPkm6dOUAaYZNaCHAbzOwyHRZsLDL43M2lYi
  38.446 +yyyyJFN5bjWvuj4QFa0PKKZUwO30uy96u6IMQlm4m0FX9uCiEy/Vt25NdeTi3FC0
  38.447 +B4iVQd8xMPP5PoMqC0F/6qDc1aySzYnvVgd/a21IpCIc9qqg+ABVKBsvBVM0fIen
  38.448 +HYlDjIUFPGpkgGO2WABmr15PEgFS6dGZy7m1MsfZBOJ46Hsvpvkd8FzLX9/qTYS6
  38.449 +0fbSF/5B9wTYIQgYoe7uWs3AAzzInciv/kNvAxdgwcahoQhPyo8+thOiKt1dLuTL
  38.450 +EhpmV8XcPxETPRu2M8tAcbGTV1QolOWhzbMDA+7m65zv0wQPA+a7lROBqtdciQIc
  38.451 +BBMBCAAGBQJbDAZbAAoJEAVxr7ylSTVTtP4P/0VAO7cH5J435IdkHwZXzwMtW+mt
  38.452 +roIQf36GD7eOjZe02aQvGBAy6VkqE+vUwpHlBImPLmpsRbKqF9BrnaoQFsBW7x0L
  38.453 +DRg1loL8izxABNZdo7pXx25J9u5IS4B69dxEiVakJj8Rw6ZEaWKyILNskNXGoV3g
  38.454 +F0x1uLujOLRFx77sl/BoKQVdnmsk1bgPcLpoPbC/7zASKKak2C+vW3eg9ruQzaWK
  38.455 +ODPflyboT5p9hHpH5kUd/5mYhgpAdyfTOyb3h0WIhKcCRsMHTVwIC9SmnOpoNkie
  38.456 +BDpUkiqHjjUxWjbWY8JhJP5eXHMAtX2ffKy5vWPRlLphg3MV8j3y/p6lUOXRnISm
  38.457 +ELV5zOuqIUP4OalNSSi8HV/6wmWmvRZeNGJveWwagI1d9jLkyCUUF2kHYirXgMK4
  38.458 +MXoK1jNtwEHE/hr+pj1qYPEIl8ggdUHqkKxme3TZov7SH3J/k/uGjkBxYmP4SCq6
  38.459 +D4RKDsgwwcuAt2MlCRMO/6nhWaa5wY1BcD4R4sFGJw5ondM64SoupldfuneVeQ5q
  38.460 +HpjvQSl8TEv9W4Dt4sJ3lnnaBfKXo1DCVsAPDNOASl79/RDdlxn/+tDaboxQoILh
  38.461 +bwjqL/zD9o6SYmjBo8czaRMVKz6FGfjGUl7MBQN6JOmIIiB+f6GRsX1aJ3pBJpys
  38.462 +I4mPZrpvw9PBwXcxiQEzBBMBCAAdFiEECumqPjIFlc+TKWvfoVWsSRzM/EEFAlsa
  38.463 +PZ4ACgkQoVWsSRzM/EHlmQf9GYMMUtbi2b3vXLXKCYjmvG9aoAigVPOzxGVBeTBR
  38.464 +Rwj/TTcsWdNgKxXKPQ4R3/uI5NYCnt/sAa5rNpUWfgkAW9++ZmhtWCw06dd1hWs8
  38.465 +7ziaF2pytaJVZoYauNhKkz9wVKWlWvQglCPK2x68RytmbNxrDK2/bQKAZ7o/b0KO
  38.466 +rCXF5lhHXtTZV9X6/wKmKlDxtGOYybDr9VvfliyH7Y7HPL02FuaqOHB2IQKkttlK
  38.467 +86UcbQRFgC0DGUAb6x+NpoZfwIhrIoTSfw49P4Doqr6WNUfAFQC1Fa8CXIg4a1Ru
  38.468 +aAPCZDa0yf0lh7FaGpdugLe918QINlSdsjwn2PHJQm+lMbkCDQRYRURzARAAwm6P
  38.469 +rA3k0gpy7jcd4LPKebL3xIN+oOp6E4jQMcbBWtYQigfMa4gOjVNi4eeL/FaTky/N
  38.470 +IEFYleyHWp0bxET+9W9L/BNjDt6R/LWBDLKtQVmqrC0p8rNTqCo1LI0CsCEu/Zzy
  38.471 +bVd24x+w/VUj1Y2dkPEP3R7FpcpSDMzllM+kLYGXa3+R0PAMniAzDamfMTgicv9Z
  38.472 +LIODKjDTBXCzFFTTKwev/nirD18k4vBqTFsssLnV9MMxanSW/yFTQcGm0A6PiiKS
  38.473 +Y4Bsk3T4OAHr/CR33ebeWvmcCTgF0u72zUG76XXwRHHjxEG9n5BwDxVfiq/2niXA
  38.474 +2Zua8nDx6wmYLvzugFBrmS2cA3epuNLDbnhQ5oHR217SZY/pVTKLmEXEanY85ISF
  38.475 +yuKCmZx1H7Rhcnr/SJGcmcTyXoZUQHimhWnXvMOpGUZ7+dIqTaSgBC6D4D3KWFVl
  38.476 +FywjpwU10PVJQZRSHwWsO6z4UCOrEHq1F13EUe7RJnguhaCoPdFfZNM4i6MxRSCo
  38.477 +xV4bv1+WxT1trY3bodnK//p6/7OXPrhIj0dmtdFELHeWKes9w6E26pWLpzk9TaAK
  38.478 +Jp4jSGh5awjgFCsz3GT09HDy5pjesXa7TOMbsc9dbUUX3Z+JiyZC47F+hmwrOOek
  38.479 +4G34/GXz2RxJdV46lr4nfuU8y1P649202BbKxQ0AEQEAAYkCJQQYAQgADwIbDAUC
  38.480 +WwwDoQUJBokmLgAKCRA0NGcwRzQZ611iD/48dFaRj61CvBuYsed+Kk3uo9pCs04W
  38.481 +SWiUarnd9zKlx3ChN+YtYMTDRpQcH7JEP0N3OifA3nOSgLgd7/HrPdt6Aim5k7v4
  38.482 +Fw7AwEuCbP3w92hzot4OetOyya6IHy8xpiqRj2etPzNAbB0kBEvwmNKSOZMPVRZ8
  38.483 +0Pegz00OI5OMGopuYgZcyAd/R5ZhqJf+8EmHsNXwT3g3ifX7QtXOXlfK8cCExxTa
  38.484 +4xreoP7UWIAUHmWz0wFnPFNQlTt42oA9mF3PjGgCmJ7j4XF7cvEyO0GDRZ1ZGWbE
  38.485 +xrk/EdGKrBQBwlCdxc/1Q87B6Kl2igXAi6rvOeUSWD5TAJSoi5M0gZYB7/6Ve+1Q
  38.486 +04sTmRt3ev6mLLb2Fu/glT7LpVUcMbpLrOB+Pm2d0eOZxVeElO7RV5nJQ8LNwtrl
  38.487 +uBlk644rn9mWiVhfdhfmP/eluXvCyps8BUFwZQu/LZB7lAFiIF0cr+7dKiLRpgMi
  38.488 +RLhTCQht6SEO1rreSb1gF7Em+aJzv1hpvbzQp46vUOqeUGZr1iF840W0b7n/s4Bp
  38.489 +xED67TQi25vFfEYYBtEzYqTCgI2v1h5ixtBkovFbXv28RYZPg5bWfAOQIwb3AnYv
  38.490 +FGBN2XdeO0ytL8rT7qKhvcS63E6ap605r5IvpgpJFap2KhWh2mwHYvNTWPnf1uTO
  38.491 +KgBhWHuSC0CEbA==
  38.492 +=oYD/
  38.493 +-----END PGP PUBLIC KEY BLOCK-----
  38.494 +
  38.495 +--------------D703284A94612CBD63CC1F3B--
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/test/test_files/432_no_from_2.eml	Fri Sep 28 10:36:44 2018 +0200
    39.3 @@ -0,0 +1,492 @@
    39.4 +Return-Path: <SRS0=Imtu/Y=LL=pep.foundation=krista@srs.smtpin.rzone.de>
    39.5 +X-Original-To: krista@gnunet.org
    39.6 +Delivered-To: krista@gnunet.org
    39.7 +Received: from vmmailrelay1.informatik.tu-muenchen.de (mailrelay1.informatik.tu-muenchen.de [131.159.254.14])
    39.8 +	by sam.net.in.tum.de (Postfix) with ESMTP id 35CD81C00C7
    39.9 +	for <krista@gnunet.org>; Tue, 28 Aug 2018 14:34:04 +0200 (CEST)
   39.10 +Received: by vmmailrelay1.informatik.tu-muenchen.de (Postfix, from userid 109)
   39.11 +	id 54A621C038A; Tue, 28 Aug 2018 14:34:04 +0200 (CEST)
   39.12 +Received: from vmmailrelay1.informatik.tu-muenchen.de (localhost [127.0.0.1])
   39.13 +	by vmmailrelay1.informatik.tu-muenchen.de (Postfix) with ESMTP id 309F81C037B
   39.14 +	for <krista@gnunet.org>; Tue, 28 Aug 2018 14:34:04 +0200 (CEST)
   39.15 +Received: from vmmaildmz1.informatik.tu-muenchen.de (vmmaildmz1.informatik.tu-muenchen.de [131.159.0.87])
   39.16 +	by vmmailrelay1.informatik.tu-muenchen.de (Postfix) with ESMTP id 25AB31C0376
   39.17 +	for <krista@gnunet.org>; Tue, 28 Aug 2018 14:34:04 +0200 (CEST)
   39.18 +Received: by vmmaildmz1.informatik.tu-muenchen.de (Postfix, from userid 109)
   39.19 +	id 241CB1C2DD6; Tue, 28 Aug 2018 14:34:04 +0200 (CEST)
   39.20 +X-Spam-Checker-Version: SpamAssassin 3.4.0-tuminfo_1 (2014-02-07) on
   39.21 +	vmmaildmz1.informatik.tu-muenchen.de
   39.22 +X-Spam-Level: 
   39.23 +X-Spam-Status: No, score=-1.9 required=7.0 tests=BAYES_00,RCVD_IN_DNSWL_NONE,
   39.24 +	SPF_HELO_PASS,UNPARSEABLE_RELAY autolearn=no autolearn_force=no
   39.25 +	version=3.4.0-tuminfo_1
   39.26 +Received: from vmmaildmz1.informatik.tu-muenchen.de (localhost [127.0.0.1])
   39.27 +	by vmmaildmz1.informatik.tu-muenchen.de (Postfix) with ESMTP id 10E381C2DD4
   39.28 +	for <krista@gnunet.org>; Tue, 28 Aug 2018 14:34:02 +0200 (CEST)
   39.29 +Received: from mi4-p00-ob.smtp.rzone.de (mi4-p00-ob.smtp.rzone.de [85.215.255.5])
   39.30 +	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
   39.31 +	(No client certificate requested)
   39.32 +	by vmmaildmz1.informatik.tu-muenchen.de (Postfix) with ESMTPS id F26571C2DC6
   39.33 +	for <krista@gnunet.org>; Tue, 28 Aug 2018 14:34:01 +0200 (CEST)
   39.34 +X-RZG-FWD-BY: krista@darthmama.org
   39.35 +Received: from mailin.rzone.de ([unix socket])
   39.36 +	by mailin.rzone.de (RZmta 43.21) with LMTPA;
   39.37 +	Tue, 28 Aug 2018 14:34:00 +0200 (CEST)
   39.38 +Authentication-Results: strato.com; dmarc=none header.from=pep.foundation
   39.39 +Authentication-Results: strato.com; arc=none
   39.40 +Authentication-Results: strato.com; dkim=none
   39.41 +Authentication-Results: strato.com; dkim-adsp=none header.from="krista@pep.foundation"
   39.42 +Authentication-Results: strato.com; spf=none smtp.mailfrom="krista@pep.foundation"
   39.43 +X-RZG-Expurgate: clean/normal
   39.44 +X-RZG-Expurgate-ID: 149500::1535459640-000020CD-236E2DC3/0/0
   39.45 +X-Strato-MessageType: email
   39.46 +X-RZG-CLASS-ID: mi00
   39.47 +Received-SPF: none
   39.48 +	client-ip=131.159.0.36;
   39.49 +	helo="mail-out2.informatik.tu-muenchen.de";
   39.50 +	envelope-from="krista@pep.foundation";
   39.51 +	receiver=smtpin.rzone.de;
   39.52 +	identity=mailfrom;
   39.53 +Received: from mail-out2.informatik.tu-muenchen.de ([131.159.0.36])
   39.54 +	by smtpin.rzone.de (RZmta 43.21 OK)
   39.55 +	with ESMTPS id f090f3u7SCY02qG
   39.56 +	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (curve secp521r1 with 521 ECDH bits, eq. 15360 bits RSA))
   39.57 +	(Client did not present a certificate)
   39.58 +	for <krista@darthmama.org>;
   39.59 +	Tue, 28 Aug 2018 14:34:00 +0200 (CEST)
   39.60 +Received: from [192.168.0.102] (ip5f584961.dynamic.kabel-deutschland.de [95.88.73.97])
   39.61 +	by services.sec.in.tum.de (Postfix) with ESMTPSA id 6A14A1008E943
   39.62 +	for <krista@darthmama.org>; Tue, 28 Aug 2018 14:33:54 +0200 (CEST)
   39.63 +To: krista@darthmama.org
   39.64 +From: 
   39.65 +Subject: Message to edit
   39.66 +Openpgp: preference=signencrypt
   39.67 +Organization: =?UTF-8?B?cOKJoXA=?=
   39.68 +Message-ID: <b651dc6c-513c-b584-7309-49eca57c5fc3@pep.foundation>
   39.69 +Date: Tue, 28 Aug 2018 14:33:53 +0200
   39.70 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
   39.71 + Thunderbird/52.9.1
   39.72 +MIME-Version: 1.0
   39.73 +Content-Type: multipart/mixed;
   39.74 + boundary="------------D703284A94612CBD63CC1F3B"
   39.75 +Content-Language: en-US
   39.76 +
   39.77 +This is a multi-part message in MIME format.
   39.78 +--------------D703284A94612CBD63CC1F3B
   39.79 +Content-Type: text/plain; charset=utf-8
   39.80 +Content-Transfer-Encoding: 7bit
   39.81 +
   39.82 +This message will be edited so that the "from" field is missing.
   39.83 +
   39.84 +--------------D703284A94612CBD63CC1F3B
   39.85 +Content-Type: application/pgp-keys;
   39.86 + name="0x34346730473419EB.asc"
   39.87 +Content-Transfer-Encoding: 7bit
   39.88 +Content-Disposition: attachment;
   39.89 + filename="0x34346730473419EB.asc"
   39.90 +
   39.91 +-----BEGIN PGP PUBLIC KEY BLOCK-----
   39.92 +
   39.93 +mQINBFhFRHMBEAC9MOXvvFrVJWpK2SDYfeDsft4ExuI9lLTvi5bzQKyvr3PkctEW
   39.94 +w4Cr3kdNwbqIXO7diMSnbEJvh8OvvrII7hJcStpNSIIYZf9UBAAIIaPJelm26cxI
   39.95 +JN9SsBxAYuPrY3OzHAgNS+/QGnkXjQxI3a6rJ38kVsMavl+q85Pm5m3WUcNko+gE
   39.96 +YkSu5F7Fb4h7wyeF4uyHgPoSEA/qaQcqUoLT+xHyWDTUb+NBZhc4jO6W38FP2Gbh
   39.97 +kNwDwKQrrgbMizEys4qmysdZOYOFWvyBNcQ3/qlkF9BbefPwDTnez0wKy2W4jr62
   39.98 +l3mc8k3MU1+NBEa03uoAaHCHr3MeEbOSwR2MiCshiBzE4HSeadQFIeruPCYHD8Vo
   39.99 +kV5wwbskVPs900ILDuSSsjamKsQROSIK2F94yqB0U6cTEc/cbZY8cNLLZkYsziSd
  39.100 +uI86H++ohEJ+apr2BkIYWnccuziqTzIIFixDHdYe3WBkR+hooL5i327mG4uRjAnT
  39.101 +hcgtCPzxzBC//0ktF1aS63Q8FrpjQ9MFBZEmYNl0Tae/b6nO1aVh9evyeoAx+Bmp
  39.102 +7rl47FWNjQl6zBbBrLoWmz3D79e3IxQs0l7niqDphkOuQy4hAFoLCy21QCxXJ0FY
  39.103 +VRB6F9Fd6Ha8SL4lMBjfYpG0yU5EGJcCo7gMV1D/cdQ8KCHSEd7jUopBVwARAQAB
  39.104 +tCZLcmlzdGEgQmVubmV0dCA8a3Jpc3RhQHBlcC5mb3VuZGF0aW9uPokCQAQTAQgA
  39.105 +KgIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAIZAQUCWwwDoAUJBokmLQAKCRA0
  39.106 +NGcwRzQZ61u4D/9mRxSKqrCgblgJrZ4YYBV5FWIcD4yIe8TZ3vzqOyHwtftVWERF
  39.107 +3LbKYwYfaOAZRpL+nonA0UZx3DlSIRvnT5Ne/5NSHHsSrU/6OzBooHFWAn2lqsGO
  39.108 +ADL3a9w/Acdx14E9a5NdyhDyZZVr02ipyxtwKUgKae7i+mdjTvBBLrPfjg1kKroN
  39.109 +P8obk3qNaUeLHlG46WndLosAAEVrU8VHnpUCpxRU5s6JWu0omtPcpmWhaSfowogw
  39.110 +HGzViwoe3NxQLYwBZuZuOp5QmhemqKU2sBNxX0ZaNijGctYLjmO7qTgKK/IF24df
  39.111 +51362TNoQ8gBUQGVKiOM5dkm9YsXMoAL+ClsvNtMwasHvtvnXviTkPvjs8FnjX2P
  39.112 +UGGZhFvrgqvIO4eR1GyuvasOIQjLcTG58sWPuZLvEwcMtyinNVyvzpLPnkOlhaRH
  39.113 +F88plA5xrQT0bKLuqN0ve8jZvLJT/As9MRSm2ftZMTwmaR4HN0JduMsBrE4Boef+
  39.114 +9UQHzfL0Ivq3G/TzkmTIyblaPUvKLKfsZJoq+jjp2viX0EfnEG0rZt/dse9Z0C2N
  39.115 +hQrJfSAV/yN/uXriXinYb9dQ0k4Bd9+zHPE/mhZ9Cwv6EO4fNgy+1GRfy11NeJWK
  39.116 +D4EzDFuUY7gAkJkcv3vfag0WW65rwn2pOoe1NUPqlHxqW0fOYfZYVzbf2YkCHAQT
  39.117 +AQgABgUCWwwGVAAKCRAFca+8pUk1U2y+D/oDA8Q9X7BtRuVQFAvS9QjqxI0ZsN9y
  39.118 +kVhq6CnJ7e8Fk1av41ztWtUy7yo3DiGur71Fd+4tCcGX7ofqGGv4LhUDCUOzSxih
  39.119 +1LNKPsMjRZo1gMZH/TSyVYLVhW/A5LK2Zvpmyc34DN4iFrb8uJ8a/sW2LlAXHEou
  39.120 +LGnJ/qTzHtVxZtrnaKmTQdRovWfrDgdFSbK5ZXM7tfxfeeUVv2TZwZngM4MTdaTa
  39.121 +vcOM/jGjvX1CjbZYePllU8WkxgLPh+Uwrdqzlyc35gzR7agT/MvWbmNFcA3myjis
  39.122 +5CRW5b6B67EM6tqxC2i4jau2P/TRPoHZaGLxkhgfdbsBDxgndUDi/Rgav7FdXmu0
  39.123 +etgJRvKEfthpHFt7/U7BYeChg0mweJkKSRKWNj+P9aR7YKgFLtD8iNLd7lonEtit
  39.124 +Vxj22n8Kw4cZRyB0m9l5V1FkkROEVd++sOUhivVCYWP4SpGjUiqkpcW5UL4Envjx
  39.125 +7CKAgZxGUr4qwAIUsET2y06zEqywTPvxarbZy0ltQrEpBAflOkJ0NuwIoBaKSE0G
  39.126 +rl6YaCZ0JvjkFV79eFcmNA4apjkZ2yBhxqUjw7HZ3L3JU13Bw4y8iYiiWx5HZdBe
  39.127 +BEQcSK9abdyxqX+tH2ZL+n/FSIJ5QTxeQzpnihjHHXARaHDrFdUWU4JoVdPuIwsz
  39.128 +QQpPh74u6lPchYkBMwQTAQgAHRYhBArpqj4yBZXPkylr36FVrEkczPxBBQJbGj2e
  39.129 +AAoJEKFVrEkczPxBn4UH/Rxsl+mZSfqGFS3aRdIFM1JTEFZC53cfUxmbAk//V4j7
  39.130 +o9h27LE22T4n8UqT60fYelSg1Ks1TluR4SoHFsZMiT3hzWTu3LHydsaUW6NoG/ie
  39.131 +O8PuMPge0NVTmF40PRcUSgy8aqA+Q2BeTt4itcLyro/pZz4lbkZ1oJt2WG8b5qKj
  39.132 +VJCILCHuZZnJHDVN1dqv2g17UQbzfor7DWO71/+wdEsnsLXYWp6FbZJsnq0S3ENn
  39.133 +hcy0ylXnZbXmaAd4PctJvsuGkB2km64F1bE98ljSz1QmyNfvB2Tgr2w5nULZl9Xf
  39.134 +z77M+qo27OyaWMT/GEROVM3+a34cobKnjSFcK6aixCa0L0tyaXN0YSBCZW5uZXR0
  39.135 +IChw4omhcCkgPGtyaXN0YUBwZXAtcHJvamVjdC5vcmc+iQJCBBMBCAAsAhsDBwsJ
  39.136 +CAcDAgEGFQgCCQoLBBYCAwECHgECF4ACGQEFAlodK0gFCQO5GlUACgkQNDRnMEc0
  39.137 +GeuE/A/+Jvgu6WhQhPv0yhvpO5NFSYDT/P9Ez/BGAWF+Vf2yHufv3WZS0i/MyU0b
  39.138 +DEKHdvDOWnPGzU4kxGWwftkyGtVKA47Vs1p96m37PzbsSQh1gyedSHy7BLFt/92g
  39.139 +OXY5/Lt+5MEDLJSqmnW5rt4xc0zkg6gKlIYiu8LCYEtG/OAW7WDx0mHWV/bXEKBu
  39.140 +aprxU4A+1sN/VFI5SXILUHW15t+CczpX7yrcIlelB17+sgeBa37ynAcxBABxA83+
  39.141 +at+90s3Pxur4iYaWrAbKnrG62VV3W0uuYQNLfV7DKPgaXM6XbOhipIE+yS1EYnf3
  39.142 +JKzQl06G40atPPmb35Nkvfk/JgPF5byJ+uKO4ntsqa8XKt3GbRY2/mKiO2WVvd0w
  39.143 +RfyuEYW3H/gvv1TZJBEqDtbjmgAEbdnGdkfldV5UAcYLzzM6GC9zrKrPuGrKUkdm
  39.144 +9FRKooKJ5JS6CYfHlZfKipdAyQ9gGyfZT5Tz6f+1/xJkwO+JpWsZV5LUua6XzfJn
  39.145 +vA2lVT5RPRZ7y1D7XKzIs24cfnf1Y4YSIAiwl90DpFLKJjISQTlAJ7Bd/yhyv8/J
  39.146 +csqIgA19Lqpr7jApk9/YNZyj9AjFmJ/ce6L8LYTum+a/ccmI4x+tmdXGtyjTsH5n
  39.147 +mjxBrhiCct+NpR6paLZxKKtJZkLX8V3Cfsq4JajIccUOUcN7w3WJAj8EEwEIACkC
  39.148 +GwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAUCWwwDoAUJBokmLQAKCRA0NGcw
  39.149 +RzQZ69e4D/4xYImZNBUCADolemNsGn4lcGdgbeUtamUx9oycUEGBFAHIzTOkGtf3
  39.150 +P9Lhq+GCgS9Fi171RUwtlLpjriu+GPOltwTPKx4G4l30YrrmouNVzJlBOozp+jB4
  39.151 +OsygcNTxJqPywkGlI9F+O8zuBE15imjavSINV63y9Ypib+LnpPIOs34t4iq/jCdK
  39.152 +pVbMvNzyzgqBHOymyKh1CIq6UCpeWdbokJsBhknwhtWG/ZuY1aH6JwmZXBSfGsqh
  39.153 +241a3n46tIYWRbF4TCpbAJiWM/Yg5Es4tvT1tZMzIg2Z6TCQkZhbv9yv4vPyBICl
  39.154 +OPSH79J24hmbWF6hDdi8DVi0STDmi/bxA8kKROdhgc9ZKz5bHaVlyewYdNNPGH3I
  39.155 +/euATdTUBPs4g7n/i0P43XuyLvtOBG9m2KfkJmODOiwqlf1/RSDYOWn1uepAxOQ6
  39.156 +vfUm7ELwPx3DLE2J7PPa8fxg4Iph69UP9aF7aOXt61t0fn1Olttc5ANjZuTHYyvq
  39.157 +aPeRPoAmJY1RM26BAzhSdLYwZViEbUhPdmGmTBAJ98PnsvXV4UHI4oyDiZOtg5B0
  39.158 +CRc1jcdabl7YvnBauWJBGs0saHxvFOHXdBftC5cx19kO8vFfoUS6wdM6Ots8hZee
  39.159 +MIOIJZ+xwZSdVA1CMq4v5PrEzbfrHh6oSZ4AkJnFpvne6zX/7TAnlIkCQgQTAQgA
  39.160 +LAIbAwUJAeEzgAcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheABQJZLp7LAhkBAAoJ
  39.161 +EDQ0ZzBHNBnrGgQQAJRnVH0L6X3aNkmLwZrvtWlrfSNG56g+WNRH9KN3NsQ6l4dC
  39.162 +t0IHq9wXZiydTvM+knRnzhpkKNA4bE+mFpSngiC51huE9kvXa4K0s0/oJqfZGfrY
  39.163 +JeaeEWDOxZQ+c0cxAquRL8gB0L+nbEx0KwyKeXexi29Wrxq53Jc3DBJPeeC1zDkd
  39.164 +z1+K0GcnmSBnH1BxJwXqgXg+8wo3CmQD4yn8GiY3L7pRYG+XHgnNLLsm+n6fAyFV
  39.165 +H1Xsk/BRWEu1kWKI1PHaVL8l+/xd5c7Sa3duL41z0W86VHkD0uDdKwyaH8fcV58J
  39.166 +gUEAS0E6VdMO4GnA20hbcX+IqIK/Qpp7FtT0CdcPktJhMUu6e2BXgtL75Z+pmnk3
  39.167 +LpFVSd6pCUavRQCoXO3EiDgKRypqkr8MVKE5IDdNhxo5EHq+7oHyU2lPRLkAieUf
  39.168 +9ZEun+vFiYEaV+T7hqfX4pcFw6dTDvOfl/4lxzxErvrRf+F5KHIdsMtso2clS4FW
  39.169 +GzcnuG3EQqDQe4RFRyo9smCR7KfyYJmM00c+NSrb/SJ/YOfcqUErKpVsKvlS+wY+
  39.170 +M4UkFqOshspv+v6P9b5sDVWY1dwGHAgq+bwIlrkT1BuYKsNa8Il2J2h5caoc7k+V
  39.171 +221dFV8OQa3TQX92ftuLo8ayxX5XvlKRkI5lV2ExlWNPblMjsO83/5cXGm+oiQIc
  39.172 +BBMBCAAGBQJbDAZaAAoJEAVxr7ylSTVTL6EP/0PoDMuttnJMIK76lE5/JXM/H2+Z
  39.173 +dgPUN0t8YgkaKEjvTTcBsiJlt9cnxsTxGHuTi1fdkLQYO5c8LRIVV57aY5ocntl7
  39.174 +kIEoMiUUhiVlHMSaB9PE9HQYMalrtYqhtJ/c0YfIYt0yw1CFYYaNZjKqI7O1zbM8
  39.175 +yHCfauSYOtUgX8oTs+i0/MFUed1qP4EC5W9nRzLhSkzt8jqIn3O9+jksZLAGUUm5
  39.176 +X/4F9DIesdinnsZgYIBXWVVR/04WkLnBwz/f5EhXIq/lhvpde6fNNx009mXtUwez
  39.177 +NG01j+mqm36szmj0Q8+QGhNxuL9i6EGXpoT5HKYM+f+HqO6TCYIiZIBvL1N9J87p
  39.178 +NA49TldwwHDGxNJjUPGT6t+/UcWZ7oKylr/6GyWT9si4JwlUSNMRX2l/kELit3r4
  39.179 ++QcLyxCHcyS8x4pTmnf0jP6xFjqiCJShOo6FuR/BR3bTSwx4G1H1WRpEdeammKFA
  39.180 +GjMFoskoNY8N81eST6AIR/OSZ8RoBUoSb2XTgzwr20G0xz8UefGcViA2NwNYALPh
  39.181 +FY315+zUqyfRuqu7wFLjy3rwX8LZveXIWcRW8mH2ZWk+HkEsmWs6LFqu3OHqeyO6
  39.182 +afLSylzT4U/SoG5VHA6xTNeKMWPkLkQLdvsqU4CUF/RMdq6YFJqV3NGTaZ99yHxa
  39.183 +D6L1FnATnV+nbJOuiQEzBBMBCAAdFiEECumqPjIFlc+TKWvfoVWsSRzM/EEFAlsa
  39.184 +PZ4ACgkQoVWsSRzM/EElPwf/VxjzbUg/AMLIRjmLVScLKiHcwFfH+uCcFK3aw0FJ
  39.185 +J8abKS3FrTru3HwYBF7A6NmUX+/rgPBkKFDbQfz6rhLw6i72y9lkPYUd7MYsl3rl
  39.186 +kO/LIylYYdk347MJ8EQCkxSTwWYSK5SYvVecPtdLLiCJD76QOr0SmaFsCq0ad8bI
  39.187 +2iu7leQrGSfV6JITIoeQBhSLWDSfennZ7MJLg4yKskghpSwjLzZ3oidebIwxvmTi
  39.188 +nUomgTtP2pTnfSgO7wdU7ApgfQ5lTQIhfGr3LC/7F2qoeR8nJcbiE/sw0ZDvegJu
  39.189 +MJgu7Z9j26UzqakdZtCPABTJamzx6CwywTEZ24Viaf97i7Q5S3Jpc3RhIEdyb3Ro
  39.190 +b2ZmIChw4omhcCkgPGtyaXN0YS5ncm90aG9mZkBwZXAtcHJvamVjdC5vcmc+iQI/
  39.191 +BBMBCAApBQJYRUWcAhsDBQkB4TOABwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AA
  39.192 +CgkQNDRnMEc0Ges1ZxAAqJwTf/BK530mkJwU1gF/+7JbIE/PD3aed5pTQV4mTvEJ
  39.193 +fn6m+CcXCG4EpvHeetw1qLmmliGQP21VcgSgmI+fjTq/y9o+m24XUT45txsDGb6r
  39.194 +HHESh9IKhrPJtaSK7IyicUTbWo4Guvt0hEC5sFU0aKZkZEc0SS6ouPc2O8df5bwH
  39.195 +sDLNZ1ZIS9Er3VcQbEwelmFYBUowXxlabftQqFAM77Bkmio5ekMP9jK/6Zfqnw9+
  39.196 +wwb2vVW6XQ/W2mtVhNNgR+PJ71OuX1FeeKD4EGVQ8yE6HNSKB5bzDaW2+6beZqkd
  39.197 +7yvZ/c2hiz5DnY459BYEIAjkFDCNQk5/sAo9ApGENQYm6yScM08W81yiBq3BPG/l
  39.198 +Z4lhonIsG9FnL/FqqpUHKdNZSBmW6EdyjIZxg8liS9iha3JKDFanMcSOVGEquCbH
  39.199 +xV1WxVT/DSLHRgWiiqauqxZ3BHAcrnsKJySYEZzQ3i2Vtp1o1rlWSCRvn0Fh7883
  39.200 +e8j0iVyh6W8uLHq8VkgcMw/M2Y3gfdsRckWOrNkpmBeg+usZostPaeIj2AsYu1JH
  39.201 +hvLjNfQpwCwWngopdpJWexs/DClsAj6WcJYVwkl++pKqRfEKbFCPEriqxzZ4xQo5
  39.202 +eaVZcEcOxIt6kcC6XZNLorPAARd063ShcQMvugXGy5OMDO+mCvRBfjtx88jCQ4uJ
  39.203 +AhwEEwEIAAYFAlhFReMACgkQBXGvvKVJNVMKQhAAn5dYlKDWUp7c8BpYg2WQzNPZ
  39.204 +G835CbxkQ1rNWZbsxr6cjYpX3UNjhnFY7hlIWXdKB+qpURAQD1lgj3hpx0p97e+K
  39.205 +qqUroF/Y+hoLJ0j48G475TEKiL2HLSx4Gp1497BzH7yw66NDvAby0ujW8mj9AgfS
  39.206 +oo17qRukZgVkwYnz2zQ/cgXrnATi9TejimjgxucP3j5KQMbyIL5gvXk8bU4GWJ38
  39.207 +Y3HFWFXauUms+XZpP+J1B9Ucw6WylsblPGJ8ra6h9K4bVMAHP//PjK0jQsGt15Tb
  39.208 +sv4IFQ177/lJ2QAO1AlYAuuRginDQy7T9nXfpEXewbHbTWash0j3Yj0+paYLp7x/
  39.209 +5xEbLr2eG+gZ4Et2a1qeJJWjVhP1WNTtySGIAtJVAub1XcTApoq47KTxxLpBGOJM
  39.210 +eOzs728QWe2DAGXCu3Mevnjokzmesvx9nwhAq+bPaguheyt/PMWDkMxI9GgwlsDa
  39.211 +9FuAMZ6Ia3MM6CNkTxcg3PyD8/iRx0dUb5JXvXlwgw4QTUA/2UGf9qLqHTTxTV6F
  39.212 +vGRrrCvKx9jqYYpY1+hlmBEpPFOc4eiwH7yLugh8M2aAzvIHGtrSMHWe8sCEaure
  39.213 +jWWx7znH4KBe6JjaEIVHGVz14FBxvkUGO2ET+VybsTILhVECnxTM1LonEVJkCpTz
  39.214 +lB5XZxhPT/i7uGofUz2JAh8EMAEIAAkFAlkuntQCHQAACgkQNDRnMEc0GetR1A/+
  39.215 +J2phQTJYEqeKgWOzRV206dK1m+pGYWzM1Es8wtJS45hbV8xXrnWlo14JBUVC/mmh
  39.216 +j67/jrmPCnKMMnRfVtEMoB9MULR2s1M4wVzl6TJkemDNtAdgpBLyC+dBQQZyH0v6
  39.217 +TTJVhiUKsWxDR24C2Hkr54Z4KcruQv4QhHd0zUgSjyihTYdOjMpO//VaOmODCCoX
  39.218 +p48BWN2CMDeGCVDs9nvFuMDrQ1omFZCL+qZcAJbqOg5LJ/FEl+bf8noGIZ8BZphF
  39.219 +pVB+yW1sNRo/yFYboW9LiDdqENhc3Wjx/Qy9qZsThNaUuWNqLR+CdTpPZdhm5PnR
  39.220 +yBBuxb+hIfI4P1Vk1vlwcNkyu5z6gyeMOkVwEv69+olKvpwX8UhYsrE/t4NwVQCm
  39.221 +z5g/DYrGbJfz/x8cLl8h/DvO4lPAKkB0VgxDSUd3kIPQEgYgJQ1xarN3DKOyn+pL
  39.222 +/EEuWcYsiI7tA6NLS4vIxgojN5+G9EuCew6WALJKKfEgKXz6ExIgRMaTYbp01YxI
  39.223 +zXn7N3dQ22Orz14/hESncImQyretdKAtb5HuoN8fJKubvw8nJHihp7EqM64hYhUz
  39.224 +KyJa61/hXKhRK8Dyimwj8k2tTJqIG3bcax0XhhOHvurAFxV4YlQOdKeTk5m0tJ/4
  39.225 +kpVY3f9JWRY/Ug1zzPa8CeKNb/78v3Ul58S1fPnMpcy0MEtyaXN0YSBHcm90aG9m
  39.226 +ZiAocOKJoXApIDxrcmlzdGFAcGVwLXByb2plY3Qub3JnPokCPwQTAQgAKQUCWEVE
  39.227 +cwIbAwUJAeEzgAcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEDQ0ZzBHNBnr
  39.228 +Q/wP/07yFuVEWLuSDmsqKuCXhwH8NxG5eQoS/0bOGp1PQLe9Pi0PW3ivXBznFh7N
  39.229 +lgVLcFbWJ18hfbXh72+zX7EsZK7z4w11ELViGvVT+9BFpMmtXVbnfEAigEqMs4F9
  39.230 +yDZVnR+d8SKS2XsKEvOyRMjybGNezPB/of4dJr/ZDRaisz1nEoEBwx+oOyzokeDb
  39.231 +AnD/0hffxqjvkMuDIPDFn/u3W2l3As9vABqF88Wwu/anPja3+d9Xv6MsBxXMz77D
  39.232 +nAghUsJ7446VEWVW3u+PZRSqN6F+LFChoMUHqHyXUkOMoYZzqTRckGyAzUQtu8sA
  39.233 +Ep0GjWezp/8Hj3ChqgLfjVurJudJd16ez0Jk1PqKemxgwzNc5McBIp3nWC1PuJwk
  39.234 +UXwBcyypfjjEckUfgtRsPRhUwabnUwK59K9ieHlyk2VJdVkhnAIBvnxoAjz4tE2J
  39.235 +o7R7dzRffbKQD/ob4kkNjCZYFGI+MkFFdAqP7iWgNxljQ9CzDWH1P9SdIAwSfMWu
  39.236 +4LFdSV9MhDt6CveCX8l9hQI79HK7HdhszCTqDON1zRK3KPtmvcl29LCtL0L2CIUX
  39.237 +uxhQ+laV/6lALQBqg/wCmA3DQt9tDmhj7gwtAuo2RPAQB90LBFrGvdN1bX4qGx2q
  39.238 +xIvGXlLSYWfuFA0mxwla90MHAHEGpMNDBqlrI7Z+zs7kKNXxiQIcBBMBCAAGBQJY
  39.239 +RUXzAAoJEAVxr7ylSTVToxYP/0ug4SViM4P8PrhjT8zuwI2yuYkY7PTSyhJi6OLW
  39.240 +/ngkXdpVmDy5TjSX/GE0QYbARa7MHmjzKM73PA72o0de9EFqNxU0rOMRj7Hxh50F
  39.241 +17fw5iwvYepKdku3JeZUB8xZkqQxFOj8Xar05Y3TfdWgCpneEwMqhtOG40DMHUtp
  39.242 +m29t8q/hEHUG5zI8j/wgNnxQFS3Z5vfsQvbGoDiPMb8qEfEzYlO/CEQhPGOQFgVh
  39.243 +ooYUJWNu3ZWoroyvGys2ANeibH8yLhnOPMVWMBMoI35ypmLLaier5n0bF9LQmPV0
  39.244 +ZRifzltfWhITIh+MDjAnQM81QiGSG+a8AaWB9mjH27C6VIoCtjrvBj3WfeHbeDwh
  39.245 +I6jmTXj2QCbiyHhb7Dym1Is11j5pL1m6rK6H6kF446hmaOielUXazASrUxmRsMLO
  39.246 +s7QiP+KC01KATEOtmRNXbu8rSbaePM3Y2Y5Hvg5d2GFloWraRQnSRj+gRcDFJtEe
  39.247 +ZAz7rCrEw5K6FxDBuO0IVY5WhJ9m1oXkepNqfsNRQxxrqYobP7IxlojVnF2guCuy
  39.248 +9xEO9Hv8b+1htoT7ERm7UlGvu8p4OqYp89gAYUVXVWiiesxMItCxWX75lPVLVnKy
  39.249 +k77jHz6N41aPYBwnzt4fQx0iT+/Ss6+zEZA0Swboz2p9dfws+uPIrUwTYZoxVLx5
  39.250 +GdPHiQIfBDABCAAJBQJZLp6fAh0AAAoJEDQ0ZzBHNBnrXnIQAIA2U6ct4eFyhDhG
  39.251 +mVmARMaddXWpaPS5xNFgWCvbZqWfVMUxEe1/BeHiA4Gkd3ew0Hudz9GXkt43LFi8
  39.252 +2uZBUV20lL1cxneacQt8o4XUGP5+oiWmuTjpSJmG16uqoEhHIpKnZIoZPDgaEtZD
  39.253 +P5TT8ioKOoM49OUT9nWmRu8dSGdCRqny4cn3Ygxnkvw645ZLL+BV49d46jLRIg/E
  39.254 +uGsDviM9lnF/rPaHgDqaZ7LyLQ/ZIHt8sJNXYl4JHWhspw9o0rlVosir2Kw23g85
  39.255 +a3wl1945bDod79PuVUHknAGdEAxhLz5TLFlGZAn354QCQdhAAU/LjjWEhz7lfXoL
  39.256 +TEWwZfu28zziPrFKuGjo6+Uhrvn87Gznb9crNpYyao+hUxWRVY+eORqIT4mnt3no
  39.257 +u+sZXFQqbrJPsWFpAU8NUtrz06psLLuAAbH6fU6xp8L7aEwvKYzaDCfz2nqMSTKt
  39.258 +yxFG4omAcfKG4ygilDYq7PdRJn+AI3jt32s3tKZwfS7VlF2yo63lSqq5AVpzUm3c
  39.259 +iYmKdMsuJaugsmOnMUTuMOQipkIt5QJ78DM/LmNy0dta38I24DTT1O4/jF96yqx0
  39.260 +S/2+AjK/2mvEDCpR/C6NPrhk6o0QfzCQLas0XbIwxI3z5GVM2D2kZ3+fW6NHi5V7
  39.261 +OW8EVGlsfArj2fr83jqfo86NrZgMtDFLcmlzdGEgR3JvdGhvZmYgKHDiiaFwKSA8
  39.262 +a3Jpc3RhQHBlcC1zZWN1cml0eS5uZXQ+iQI/BBMBCAApBQJYRUUcAhsDBQkB4TOA
  39.263 +BwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQNDRnMEc0GeuAxBAAhKxzf5kj
  39.264 +W+YA+pRA2r+e0R9sK3T4MvJm3tGlVxTr2yT3xLYyKm0KZ+2XeVpMf8WxJ7yZy0aR
  39.265 +R6z9QPBaXO5QUcbk+BvT4kSQEfMYgHZtzBp7tgsyzGV5HogLG3S9Z12V08tYVcD3
  39.266 +TSE0462gZfxrvYfvb/yP4J/0PFz17XwC7ATrEbeSllx9D3m9xi8BhGfkCgR45V2r
  39.267 +7A/oTNhZSaHtxkHb8a9+nzMNd8mgtOCdhOng+pzn2YRSdP6iBA+qabunCY3op3VB
  39.268 +RXoOPpz8CIMkBK5nB/+45Fi56stnCzblXlD95ec+DahW6AYsqXfQCIF3ff9f2KAR
  39.269 +JB+9tdp/8ppxpy0RxOz2uKSDSDaRVVfsG7qj0SJvqSH2auN7awgGpOXC3x2hfA7L
  39.270 +eCb0lISbWgNPlpguY572LpZwGFKz1xvwMSRARVsPrYaH8TDnTDWZcnQEasyxpsHX
  39.271 +TZrnsEZcE6nOaOWDjQp8jsOrD/4gUrIAdgXd2blZGxnD0vuhBVS5MQwn6XpvWEMV
  39.272 +gMMDpACi8eUZ15cRlGawmkw4zjCrX5tyRCaId5EMvYhBW3Vnw8PnQc/S+4P1XRwO
  39.273 +vFC9ijE6zEGYLGl6NoZdBhhUCJnNtP3hCO5WnMifkz2SfAhPxxslRhtdPhAo0d0v
  39.274 +3An8JzB/E9nnHUCbBeyzRw9TWpfSLImvRrSJAhwEEwEIAAYFAlhFRfMACgkQBXGv
  39.275 +vKVJNVMVvA//YfKpjSmjs9agqWzJVhyP5yES4pAPKP/FRC9Mm2gUHw0eTCwN5pqY
  39.276 +DcRkyhfEq0yOdfKTWrS4g8Z1fCkaQS576oTv8L4msrb43skhQVl1QUWGNAcNQxZD
  39.277 +4p396YnqPDGkkftr4ac4v+SNZFJntNs61Rlp6WwKcF7rKH2qIE4kmirrQisNiuDZ
  39.278 +5Y87bujhgtHRc+PN+5uu9t2gymH8ydf3R7x1lGYbF6AmRvEg1cW8UBZAF41b5TJo
  39.279 +hOoXqmuUZaHmeMBaELiFDbCJ5h012xT2wbjQeok5+DRVRDqPASBRN/Y+xvjMPB+r
  39.280 +U7LHCLRdQa2Jdd6X22QiQafQbY8TIuJ8wZcfSdSCtpKnxEPQcPMQ+NbTrmLZk3fb
  39.281 +nO8qJ7TYZ+YO7dUlT17dO8Et+vHWvF+0WFsFFcw/u/gUzztrkcpNaTRV59GSOsta
  39.282 +KCVs10NXiPmMKBRm2yEAX3lxUnxvLTPfCkwI1aHuz5IiaLPQpSjtTbP6LVtrK7z7
  39.283 +x/N/R8if+XofbZ3DoyMykD8mY71vMz5h3iOk4JjyfBo0W+SLAPhxCCfAV96OVKUx
  39.284 +oRjViYUAevnXBG8KtRNVA6p1SUzAx3XhI6tbm2DWFQIFNpxqVX9fPdBLewx9IXup
  39.285 +sHENq1BiOsdasn+Rn+jjbNAle3NUoHSP3rnJDUkJL07kE/Dv6bbo3amJAh8EMAEI
  39.286 +AAkFAlkunrUCHQAACgkQNDRnMEc0GesyVQ//RwC6CO8a8Qk4OL4DGeOMIVAYS+Pu
  39.287 +nqOSL9U6bk7HggYVgbK1vJS7hbrtuXp2RMBl16Dr1HQXNwflTBB81GkXJF2EIp5K
  39.288 +oG+zfXFElOrjyU7/GJbSlI13RPSWvqlZxdGDiK6gqPx/jVYKjeOwhBf4AZ5NZOc3
  39.289 +3kHEFZeRJmt+0PAQa0mNtAPw+Zrfg4yuS/V6c33Q5GV0J7Hrmow7QTrLZK0QLF2F
  39.290 +6Axv96aF4G3E3qlFWWMtyDWB4asOl40XLyWLdHseV+dj/k37fZOeeC1wJat/rySC
  39.291 +kpC27vT2NS3TLT8M1wy8/Vf4QWlPKjCTxbV36H733pVT/uIr6fEckBrujSh9PTt/
  39.292 +UqzNE+NC2HMrmR6SgTtSxQe/pVfB/iNwjhi7ZGoXQLvv7ZFRtZlrhYjMOZNvCQHf
  39.293 +JV5jx89p9B5eUuVlEBs0LTPeGhMkXemd5awnPoDenmbQUiquqqurfqFJY7xICVrB
  39.294 +V6yIcbyQIhy+XtZwMBMCZgBiJ7kcprIwNIBIZwqmuoh/51qADEpjSQzu+NgS6/DG
  39.295 +Qv9wJva+Kj177EN4WrzgvUynhivn7XhQT5OpqtgA5FPTdqKZFvzODsMvBuyzwyek
  39.296 +F0QWNIhdqvcp3i+fRvXMfDtX5YYX0rrgr1S/5Umw9e7sMDoVAdwtciO25ZvbGNrE
  39.297 ++kgsSGxu/ItTkcS0MEtyaXN0YSBCZW5uZXR0IChw4omhcCkgPGtyaXN0YUBwZXAt
  39.298 +c2VjdXJpdHkubmV0PokCPwQTAQgAKQIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4B
  39.299 +AheABQJaHStIBQkDuRpVAAoJEDQ0ZzBHNBnr6acQAJgaFd2ISl6tK9tPx51zh3vV
  39.300 +YUYv99a82sGU25geOc3TKVfssnpLkMzHcXbEEckVyn2lvs1Q9TaymC2j8BDs5xwD
  39.301 +esqu2uw6b0R01mlYhy1+Cuz4XNo434LUyT1/YIOYzduhrlBmZ5B2Kp6tSBF49H7g
  39.302 +MmCZ1BokjwI7JO9ogyzFdx8zPJ1S8jbV5ADf4QoS4p/GkywpPzCEgOkzMAkZ0B5I
  39.303 +epnmQPNtfPzAHEUnUGZk0Dnvw3BoxH0PeacpKNrByJDMWhyQa71f51ooM9vVm+1D
  39.304 +kjptImQ24/K3k+MCKO9aMeE/2aOkSsT8btvhLga5iXBGHygYfhwRduXJTLcCuMjq
  39.305 +S2E9kogaLm5eQktwXswTivhZgBIgKetFot0hfdTnZpc/AANqajZeE7TzDs2J8TxM
  39.306 +yKL0YpyEhZM7Qa7BIAP94STZfKoRN84CCz5pfxp0e85NN7Aka5wnYdsetNqK5Arn
  39.307 +tYqDuChNKurjRmvj/EJPiQpOTDevQJIUBXYMlPj/l6WW6imSzyhMqu0dhYV/KDvO
  39.308 +mqC50mTSypL7GI4VL1bO5OxAq86xwwrWlnLF0K2yUfS9bAVT49ENL+n45Z2k811x
  39.309 +5gPADqp+thfT+JvQQGQU/KnnOc//AqEA4lryvd+IPNSYKdiPCcMjfr06ZTSFxl+W
  39.310 +Z32r1lgcD0ItVnnpIVtGiQI/BBMBCAApAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwEC
  39.311 +HgECF4AFAlsMA6AFCQaJJi0ACgkQNDRnMEc0Get38g//QbNpYEHXttxg+4FKRnnJ
  39.312 +LPasl+Vgn7S9b4ivDLtcUwYbd2lk4l7KXBPGBPz8G7k+xoPdooMyojIkj3mjyAVZ
  39.313 +BSMZ+rJJVzC/u8YYmuY7GEuMEHxWPLJGLVFwGAjvEewtPCQlS91w5IrIlkLgrVoP
  39.314 +HC9yhtGfcaavKZ2+UHf2ISyZ4eTJpEQ8w2WiOHXS/JN/o32r3aLvsIvbfyEAPh13
  39.315 +U24lYtEL2z5n7HMtuh3mthd6uI9V5+WAq9vRKubhyPj6eF7SQKa/2ry1yspHo/LV
  39.316 +a8pvUEL7uihZxAwg0p2+z7fEYyau5ce2x6lGHI3IimRN+kozLXpFHRZqtmTnfkIm
  39.317 +w2k/e7YfzGBql5AKpn8WSs1P+2LQbXA0qkOlIhgLcfjGUfRUoLyRF4DTm6MEjGZW
  39.318 +N7awVmuIxsmLlVc5i6CUcaxWTE8hT93ssfrL7hVEzb+wH/9ckF6FH+gba+pCvaUq
  39.319 +Ssf0NWW8nNga95qBW1Ii3XYH8SF8XI0qVGC5MDqHbUrzCLHH/V9U4lyFde8Luvog
  39.320 +3cpiPt51IwmLPoo1v/bu7g6696HPRiPaoAKjZsPOejinmsFVmCVcEkylMLx3ycoB
  39.321 +KzxdVKNGlD4gJA20tysfTv25ZOaj6/WXI5rGhTu905w5UoWgB5keZ/npRKhDH7+M
  39.322 +nzMmuOhpIOUAbJY9TGCQaL2JAj8EEwEIACkFAlkunsYCGwMFCQHhM4AHCwkIBwMC
  39.323 +AQYVCAIJCgsEFgIDAQIeAQIXgAAKCRA0NGcwRzQZ62qQD/wKX5cKoICueycy8MMR
  39.324 +0YlSgji8cu017P9EsAVThyTeWAgjd9GQJ2dsWxDrPynU7uKEJ7a0GZXi5xyrGFiM
  39.325 +tKhgwVegbWt6OPknUoAKZGzjGyghoIfRNxQJLJ5Hq085A+Gyh+6jIP1ahhL7OTAA
  39.326 +4fZnC4SqLCdoOdcx9+Vucr3wUHBCayrU5HR8GiHdlj5J0eZij5FuGGHIx+sbXAiE
  39.327 +NBPM5B4eXvKhTvCKUs8h9/upcrPfk0ZRxeoh/BxQUOnTsz3J5QXaJHc0xwg3cfXO
  39.328 +0vE0/+6fpCCpniMliDBOfTsX7PbD8UYbCV693+rjFVkOnipyBY3Zz4aXR8Bojpt0
  39.329 +jSRuzFmVf6cqcCJ4knz/ekPmebNayG/NYkAEkAkmGIh1VbQCngufDrFius+sBzkt
  39.330 +Hrmi0VVZRqF0r5zSMVM8VAowzlmnmO4QR9fJGtJ6DjLBImLPJAH0CiNthDChtAU4
  39.331 +XPegZmbZIY4Ox3K95yrKzmhbgE0RhshSERm1D74WTfcohWZurLQ2/bJw3OFWOUaG
  39.332 +GYylV/f6Gzz7iMx7s22PE1xBlwjD55eTnszQ4HiQYGV+2TaQIfRVm3vB/+NQ4LZB
  39.333 +q5l5idrNnE/MOut4XGbes78Q4pRtXQ1yJ65ciPeiifkBd5eE0hL8trRRoObj1JPo
  39.334 +Cl03ggiT2+mEj3/lTB4mgcJKzYkCHAQTAQgABgUCWwwGWgAKCRAFca+8pUk1U9wM
  39.335 +D/9c4liSGCPFbBqg2bppnxPucZU5vc9fyY2u1D7l9RNlXAok2InABdswoy7iUEn4
  39.336 +8TlxuTU0+0PK/fSNnkCAVfYPYAp/Okmn5B8g9gkBqMgTd8freN9VWTp2lSlxaFf7
  39.337 +0u02rpYx7nMCawTRmWhDOtl3hTEpEvtKuNjdjtW0Mz8zx+FnT9L2+e33+ykOEfYK
  39.338 +mIO01tirfyPdKwWAsUSa7C9WGKR2UwVvTcZVd1HOfCktMh4ELAnHaV3jMERbySsO
  39.339 +XEuCmMJU642yvVAKOFt1bRQcvpl0xVtvBph5kNuSksugY6YRUDSBq/bKyegAcjz7
  39.340 +OtdWNzU8jVUbBELe/w2U4D1C18fSJahkikEnemIBZAdTQqBPKtlvFbmCnEB2pQO7
  39.341 +7SpIJrKQzD2LV13vlqfY8FsqIBJ4kQ+PHDWVLrMx7kGF/Sjl0Y5lN+kXz3UNlJ4x
  39.342 +R1yV56gmI8ZM+tqcCxE3cr8brmP+xxkEC0KgmDO11vYwrGdrSC0PnIRrqpCu85qx
  39.343 +KmkVuE5rgNVfNJ7qygPcoQvgum91OQePIfHNusw1Ms1D+D/k6Hab5cC/oOCB8QEp
  39.344 +s4vH51MN6+z32W5vXGWTCA38AvkeDc7AqrPCfZfln94HoUP1VtDcSRjyw6vXnzRe
  39.345 +/ndTSemOjQaVOCYA22S6wpDs5GzjN+0t2GcQk4bSwRLWwYkBMwQTAQgAHRYhBArp
  39.346 +qj4yBZXPkylr36FVrEkczPxBBQJbGj2eAAoJEKFVrEkczPxBZPkH/i1MI+W8srfk
  39.347 +pO9WMyo3bTwRM2LEEN1LCVfXhXxqUbzbjERy50fpFHpqhBGcUssCZrmwwpDrtisG
  39.348 +eNVX/SqHRj05qJW9sF4psuoh+jO3h5lkvQA0Ub/iIaQ4wKgqs9oVwKrMTwxbgqZa
  39.349 +DH4PbZdpMILISeokXIvJ2+cKSpNHXLDFQZGQaFiuFIrDKRG1mnmZrfpYekEXHp1e
  39.350 +FZXXx2znmYOL9UF47TaEvUl572f7rWkNcXVaY8xSvOqOo8vdsv3Spjkjtjn7+UJw
  39.351 +l1rTLAa7geepzFYv2T2PNFYByBGUe/XCe83TxFgp3EKzrqu5GOvkQhYlmltkxKSt
  39.352 +YZZLGCA6iPu0OEtyaXN0YSBCZW5uZXR0IChw4omhcCkgPGtyaXN0YS5ncm90aG9m
  39.353 +ZkBwZXAtcHJvamVjdC5vcmc+iQI/BBMBCAApAhsDBwsJCAcDAgEGFQgCCQoLBBYC
  39.354 +AwECHgECF4AFAlodK0gFCQO5GlUACgkQNDRnMEc0GetWoRAAmr2v4Fe2vUn/kv7t
  39.355 +dPRvQK5fCvuOpAvaJLOjwePobuJa+ItCxM5rGTkCKoCX6hRGc/wpKdZB0Yd2dv9O
  39.356 +SiAdiyoOQOnAtt0+pFvcJ7w5bOjWURi8sWxj9nYvXyGBiVACUvq6ApU0pEifziE1
  39.357 +GmwfCiftyK2nKq9my8vEnPr4pkVzF8CkJdxmO8Ufu1ETKJC+4LW0R7pwWtvTnsmZ
  39.358 +xHd7A1r93mpygMDV7qzDDz6RRy1bz+HrwUGuNlyCqbsHEjgOE1EiyhblocGFI8yk
  39.359 +YG+vzSdWF48Emz15CBVKRTfnkN/QWsxEJZAhTHvHPb8McDpQ0C94cNuRGL1P6+gV
  39.360 +aRDHq4fWJc8V+kKSjB2HammVyZmk0LYWUaWMBoNlCOVrnloDrOjWyoyeh4zPfbWU
  39.361 +k1H2Tr2VIsYjXTa/ne8LorDGWFKDrbl5Y2VzOMl2FYUF8WXwuC1XEud3YZ6SLPs/
  39.362 +c9/FBhWHg6ZXnFshgJkiIPZty76o0mGBWsImt6SvRcef8fBmEBmjFAt6QyP0djWL
  39.363 +qUGQ2Df7cfFLMt6wjesEcyjQGaAJgXAAlN727F7bOA0lyaCRKx5W4leQhboj3khy
  39.364 +gL9P7HG70iF6kDE5gw64YPe5AhV8nPO/D7wHo+dqrl1TvJGF7Bmbw25cMbHwBwdV
  39.365 +Ep6Xf0M3fBrrf/dzEZ2D+pGkVhSJAj8EEwEIACkCGwMHCwkIBwMCAQYVCAIJCgsE
  39.366 +FgIDAQIeAQIXgAUCWwwDoQUJBokmLQAKCRA0NGcwRzQZ617DD/sGjFOBPWitPl1X
  39.367 +ufY3xkkrAEAnVXSzQsLT4y6HF0SodmPNgn7lOMT67GmDDRRUCKhzG9+vRcjzswTf
  39.368 +wo031/ciXYxG1FrdA75NtvDRNio9yiyRurLJTt6nbZgX4TqV0ug2ucysxGZYVNt1
  39.369 +d9H1v8FwzvJvsE2mDw108mv8dVTjLsLL/BXh3Qsb0kJ9PSamY1WRtabz+BQtv5gj
  39.370 +NRNzOaGFLiw7iWdIPeq7dFjdzyg6I8dLlazolFsidtZQIlnfqNTrBwBVLRwe9IkK
  39.371 +VkmsTW8jBCZ8je4GSop8r6V/Uysq3w17/ecsH5VPwuNVRtQIEEV+ojXCFTXCCwKk
  39.372 +xCUYLsrZQG+3Cr5ZtIBH+xxplx7dbC55DWcC2Rb/+iBR3Z5pyDrzVlD5lTZ1Qxru
  39.373 +2340WVLWcE4EUhHkgKL51+1wUh8SPJph8WiyOTHY4Ncs4ZzHwrwsT82zBhpMIyD6
  39.374 +gpz0697HFV6gtQN5tpAHPfvWDgZdsquu6xnHAPWwDWVKjQqssOlkSOayN3ibTULq
  39.375 +VW+FHXiot6no99vY3C7MwBMG8H+DiiAuwMZvjwu7QF/K9e/GtcVMIjixa3JkMcK1
  39.376 ++KeBoLhC9K7Re3M+usBMVl661js21w0US3AFtwhi8JAD6CV+f1EnGZ89pbPgSDYl
  39.377 +EI1oh+J54bj6Jt1wWXB69Q20BeFpj4kCPwQTAQgAKQUCWS6e8QIbAwUJAeEzgAcL
  39.378 +CQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEDQ0ZzBHNBnrVZUP/RAOy8P2I0ad
  39.379 +eV1tGLLd/n9M7f6ntl9vRQOQ9f23xFk3F2iK5JgYX7sCute2lPwqjBewUgxt0PC/
  39.380 +NnTWLhkb5DsJgEfD0RVqWu/KslWRI/kKvcWE7+s4M1Iv65eLyuMWMGmCLcEpRnPE
  39.381 +XOs9qu83W0N1Mw359yc7Z1LUOZdvp2uVXCYSJu52NHV66Lc8tkPcua5VjpD6NrcA
  39.382 +QGuHBtvzu/XpsJZ6AAWskD/gUCCYvFvgIzJ9IFFB3SQXC/ZTKveginNAcKifkJzq
  39.383 +ju8d5nJo8N0D22sYsP7EbaqZbHl4YzwmiELz0uDg5KJSVj2sC4IzWXm1aHnZDV8m
  39.384 +FdflUTSeG1NR7uoey+yf5xRht5AL5AmbOdlL9aWQzje5bqj1oXb9HqAWfOAshsrx
  39.385 +Ygz4PT7u9FGCpZ9alho028yEpZZkWZejLi07M1fQc4kaWMHHfi0aMlYdELsQ43o7
  39.386 +5aspJ9i39aVA1JRXAAB77b/FDNEPX4RbkcX6dyjDdU9GqhE7CQcjJyabxUGwR5DJ
  39.387 +NB/XjFubVe5CCczliqAFY0FHjXEaBoZvsrE6mkc3mGhdyU/016Mpx+lbQgTi8rNa
  39.388 +WmOrnQmdoHhKAuC4KFhrwlalez1fiLdl3tdFXqHuDehB4zLj+cZcdq/5VriKGzI6
  39.389 +5Qrq6HidIvFfJsK67aC1l9dGbfqgvgSUiQIcBBMBCAAGBQJbDAZaAAoJEAVxr7yl
  39.390 +STVTFUYQAMUyyDQO9gMbS549V4qpl7mVzzfqtyWmfYApsKuqrvcYVZZMO1Xl2ICy
  39.391 +LypNsZ4+Z+8HWpPc0gxWpWcdwi5uShS38OEoQN9Oj89EJzZE/guZmqfTK8W4prcp
  39.392 +hoPYOdKWNeF/pHqef9b19TEQfiQqktNsD5YRuvuvUObAWm9JQdDB2C4iJRy12zhG
  39.393 +2Y8NNnq8eZbQa1MgK1EJPvQo4oIOh+e6sJ/G1swFZevsc1DzZX7WWd07g60HVXTo
  39.394 +ous9yHeqrm3xEsay1c9tSvuWWIyEDqTiwp/smjpPMcwt4vAp2cEZDNylB0TeNifq
  39.395 +4PWYAQkSib+B0VEYSPxtjiA76T8kQn8+m6m89fcQWBm9ldgxVO5IY7P6WTTZsnRW
  39.396 +TOXx6tFXVC2c1XktUGxUtqHwOGh4E99Nlysl9f4N7DLEd9wAdwmTcEYpFQp5k73w
  39.397 +briLCmkn88kN1Vu3pVovmRIaImP9nTbIe1jYQcQrIzkdqIYdYENXvlfPHLT2+2z1
  39.398 +z73CxDTsOScwS2m8MJPGrMB9YzzwoCv6kf79j19BzXcjpteddR8z4o2e+J9X+Hlo
  39.399 +plwOKIlwwHM5bYRwq0A96sHyLzP3KkTZbruZbE5wyG2e/hcftQ5pYZ9HfnwuqN8b
  39.400 +Z7bB7p3rvBOy5p0eR1a20RQidw8S3gkSzKuDMsdcZZN2zamHkCmTiQEzBBMBCAAd
  39.401 +FiEECumqPjIFlc+TKWvfoVWsSRzM/EEFAlsaPZ4ACgkQoVWsSRzM/EFtlAf6AkR6
  39.402 +FJ7GSwq/vaSSuZWkHylgSxCLpzXePFmmvJLSuLr1GNATwlxNpdaoN5wGxvFBRlD3
  39.403 +tAZ8y2JpOx4vFcBKoRkGLpn2E+S9TS00JDXVQVE1wB74sG8REm9UwXv2jeAA/VI9
  39.404 +xlADtSbKB1qM1QMCeysBY0pJNilwe1lgSatLB9DXxpsth1hs/o+Eo9pR/3aW6U6i
  39.405 +jOBl54q7Y3oqcXUrwlc+jWgXl/HJWP5OPllikxdG3jFbT0ChrmQAekICk9WOmXa+
  39.406 +vO131CWUgXhzQtHKa3fuPfledIKopH8vDa402q2I7GsRXqkBV8ETa4lSRvoMHEd3
  39.407 +YyGCRl+r4SngBAiE1rQuS3Jpc3RhIEJlbm5ldHQgPGtyaXN0YS5iZW5uZXR0QHBl
  39.408 +cC5mb3VuZGF0aW9uPokCPQQTAQgAJwIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIX
  39.409 +gAUCWwwDoQUJBokmLQAKCRA0NGcwRzQZ691lD/9ySDQYaodPF9pyRDEIjJyjtC+9
  39.410 +62a37kQAg5Z2/8HxbpKdlaIKJ0NQxbaP3v75Yr0uvHCokdqTi7QLCntRk7enIi4c
  39.411 +OLAfzSlYplJouFULWT1AHf++e7Ydvl//TsmSyO1m/cwrE+5BkQYwpNwwHK50UQ/P
  39.412 +qU5USrc4vJ98iUg9wDvKqTrHA3ql09qeYC7vvzecZyb4OVPsw3mP+LX19Jz+13A0
  39.413 +4mNd9+7g5ohe9v+4+SkSi0ZTgT2HCHP2gusHdd/QCnr3PacHmmNBYrJOkebYt5Wz
  39.414 +mOKIXYpa0s0sHn3iJfDeEGi3Yfua2ZwDaiDvdzCPERliv+oFk0vYC5t9BrbvgJTD
  39.415 +Anr9JJmyevZ+QXKjyhUqguSZ6lzhwWLKPi1W2eGg4Pzg7I3yZPqOlux1xF4t6t4n
  39.416 +gczdQEqPIqy/7ZqumjhDN4BGlOYJEeQzdgi2tMl4U5WVsp5cZ2RlJHXpQlcKcuD2
  39.417 +W3QKzLXLEZr9o00igtTlWXCh8jzA2Bry7qtwnS7JjELLVmge3/tOYSZvFe9xXNcK
  39.418 +wdPLkA22OA4dm488pwlmTFKdE+DE+Inft2QSsmzK6L184pMFcqGGPqfEEPNlxqPC
  39.419 +L2fuNyca5oKSWR5m5LPidT4wJ+F4ddhq9AIVn5WSHNZRfHJg2QbIEWct7T6/tq2u
  39.420 +vsdUwaMvR3/ibzehi4kCHAQTAQgABgUCWwwGWgAKCRAFca+8pUk1U9n0D/9axwQ7
  39.421 +QSAYUVglXYt92EAE6jgqk/cWf5uX9av9GzzrzIPTB86KLrOL+yUqIY75mzseMncJ
  39.422 +aEf4mfULdcM11M07YOdcoHT56WkIyFHqN6kgxApu5LQHJQmjpjPe38+3tbCMQbDU
  39.423 +lnFdxmVxvhfVp5yz/luvJzXiwFZ6f8lmrBOJcOw8JNIMldo/LZ4oHHowDwgIB90x
  39.424 +e+CLfw0FQRsuEAjmsyCwO10ur0O07wLrh17/RhgTPZGT1Q8886THN0BOtWImRphc
  39.425 +sRp38MjqV+UrWCd6oUDO/tbucctjtohj75D55CU9bqJfByX5mNG6hQwsKPK9hc10
  39.426 +vAStvk1/Z8WQ+a6nHcL13pi1trZOch+XH1R67w9WMbfw9DyVgup+AumkPsRqsqF5
  39.427 +WKtrXOUb4kc13aWFMsIm/nWn3AHR4NL7BZk+YUNsA1tSRygSwgOAVNXQ9W2xH3VI
  39.428 +hiAuP1CnUJr9YsLfteF2tbVJTBSFlpcpZudBtrKVC4odPD52ThITMj58SXZ67THS
  39.429 +YAtOHzzIKeGnDGhb0tXj2Ca3WZVttIRKkH24w926mVh8HcaF0V52ETv6xPRUEH5d
  39.430 +jI+y3Wi6yUQIwo3+LXXuhjAGhV1owhpwo4J85zR04eAKet8XpEX3S0dxHkD8JRB7
  39.431 +hZeVZJfdkorYeK8pmLeBtpyOo/Z6Gc34GjsocIkBMwQTAQgAHRYhBArpqj4yBZXP
  39.432 +kylr36FVrEkczPxBBQJbGj2eAAoJEKFVrEkczPxBuyYH+waLTZgUlfaAd+JeLrsn
  39.433 +uS9kYvG7RtBZNpVLtG7XJ3td+xiCLS7APwXmUmG2si9UxYrj1bNHJd6CNgt9tkWj
  39.434 +n/V1tCsLcTpwUUnEnq1doYxkzFnJACItKBPUEOaHZuH7heFw+vdjBsdne1wlq0EU
  39.435 +ECgfF8BoAMI0ohfoOf6j9VZat1Vh5GrZa525mVwTgw7exvTjlo8K3lIfIXag4ylp
  39.436 +4hxw+tqTAhV7s3+Ju/f/GyIYgJ4gCgvXIosFWSWc8Ar65R4NrF/y9wsETBNmrpYN
  39.437 +LvfpAEqAiiPtTJFuMl8DffsbLLN9VkeKDMh1aZbn58QOVrTy+Y2BFiwn6z/LT7nD
  39.438 +uKK0KUtyaXN0YSBCZW5uZXR0IDxkYXJ0aG1hbWFAcGVwLmZvdW5kYXRpb24+iQI9
  39.439 +BBMBCAAnAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheABQJbDAOhBQkGiSYtAAoJ
  39.440 +EDQ0ZzBHNBnrbjgP/RDgsbGW0HHfRzqRICYk6sD86aylqXh+PSG+DFd1BV6kupxH
  39.441 +EHZUgma7q5bmYAnCyhePKVjwfbN0KGITX8WDWHdx0be92iVPTFg16kwemGllqewJ
  39.442 +DZD2a71MsmOYop0Hwifdzn+eOtAk9Bs61WYklhbDNxMJ9PUR4iujCnUby2VlX/zF
  39.443 +Lv8Sb2p4kPEikesHMG8doiaxRi5e9rSa5N29y8bBkTVYf177Gc7bWcDZ1F/aBm0W
  39.444 +CklFR3W7Oe9ugkeW8A5yIFOhiXG1bXbjBss6/PbdcOD+/DGtVHRv2jHEQgmID66s
  39.445 +a5vanHrKNw6W6h1OaCpRsD/3eLB8YPkm6dOUAaYZNaCHAbzOwyHRZsLDL43M2lYi
  39.446 +yyyyJFN5bjWvuj4QFa0PKKZUwO30uy96u6IMQlm4m0FX9uCiEy/Vt25NdeTi3FC0
  39.447 +B4iVQd8xMPP5PoMqC0F/6qDc1aySzYnvVgd/a21IpCIc9qqg+ABVKBsvBVM0fIen
  39.448 +HYlDjIUFPGpkgGO2WABmr15PEgFS6dGZy7m1MsfZBOJ46Hsvpvkd8FzLX9/qTYS6
  39.449 +0fbSF/5B9wTYIQgYoe7uWs3AAzzInciv/kNvAxdgwcahoQhPyo8+thOiKt1dLuTL
  39.450 +EhpmV8XcPxETPRu2M8tAcbGTV1QolOWhzbMDA+7m65zv0wQPA+a7lROBqtdciQIc
  39.451 +BBMBCAAGBQJbDAZbAAoJEAVxr7ylSTVTtP4P/0VAO7cH5J435IdkHwZXzwMtW+mt
  39.452 +roIQf36GD7eOjZe02aQvGBAy6VkqE+vUwpHlBImPLmpsRbKqF9BrnaoQFsBW7x0L
  39.453 +DRg1loL8izxABNZdo7pXx25J9u5IS4B69dxEiVakJj8Rw6ZEaWKyILNskNXGoV3g
  39.454 +F0x1uLujOLRFx77sl/BoKQVdnmsk1bgPcLpoPbC/7zASKKak2C+vW3eg9ruQzaWK
  39.455 +ODPflyboT5p9hHpH5kUd/5mYhgpAdyfTOyb3h0WIhKcCRsMHTVwIC9SmnOpoNkie
  39.456 +BDpUkiqHjjUxWjbWY8JhJP5eXHMAtX2ffKy5vWPRlLphg3MV8j3y/p6lUOXRnISm
  39.457 +ELV5zOuqIUP4OalNSSi8HV/6wmWmvRZeNGJveWwagI1d9jLkyCUUF2kHYirXgMK4
  39.458 +MXoK1jNtwEHE/hr+pj1qYPEIl8ggdUHqkKxme3TZov7SH3J/k/uGjkBxYmP4SCq6
  39.459 +D4RKDsgwwcuAt2MlCRMO/6nhWaa5wY1BcD4R4sFGJw5ondM64SoupldfuneVeQ5q
  39.460 +HpjvQSl8TEv9W4Dt4sJ3lnnaBfKXo1DCVsAPDNOASl79/RDdlxn/+tDaboxQoILh
  39.461 +bwjqL/zD9o6SYmjBo8czaRMVKz6FGfjGUl7MBQN6JOmIIiB+f6GRsX1aJ3pBJpys
  39.462 +I4mPZrpvw9PBwXcxiQEzBBMBCAAdFiEECumqPjIFlc+TKWvfoVWsSRzM/EEFAlsa
  39.463 +PZ4ACgkQoVWsSRzM/EHlmQf9GYMMUtbi2b3vXLXKCYjmvG9aoAigVPOzxGVBeTBR
  39.464 +Rwj/TTcsWdNgKxXKPQ4R3/uI5NYCnt/sAa5rNpUWfgkAW9++ZmhtWCw06dd1hWs8
  39.465 +7ziaF2pytaJVZoYauNhKkz9wVKWlWvQglCPK2x68RytmbNxrDK2/bQKAZ7o/b0KO
  39.466 +rCXF5lhHXtTZV9X6/wKmKlDxtGOYybDr9VvfliyH7Y7HPL02FuaqOHB2IQKkttlK
  39.467 +86UcbQRFgC0DGUAb6x+NpoZfwIhrIoTSfw49P4Doqr6WNUfAFQC1Fa8CXIg4a1Ru
  39.468 +aAPCZDa0yf0lh7FaGpdugLe918QINlSdsjwn2PHJQm+lMbkCDQRYRURzARAAwm6P
  39.469 +rA3k0gpy7jcd4LPKebL3xIN+oOp6E4jQMcbBWtYQigfMa4gOjVNi4eeL/FaTky/N
  39.470 +IEFYleyHWp0bxET+9W9L/BNjDt6R/LWBDLKtQVmqrC0p8rNTqCo1LI0CsCEu/Zzy
  39.471 +bVd24x+w/VUj1Y2dkPEP3R7FpcpSDMzllM+kLYGXa3+R0PAMniAzDamfMTgicv9Z
  39.472 +LIODKjDTBXCzFFTTKwev/nirD18k4vBqTFsssLnV9MMxanSW/yFTQcGm0A6PiiKS
  39.473 +Y4Bsk3T4OAHr/CR33ebeWvmcCTgF0u72zUG76XXwRHHjxEG9n5BwDxVfiq/2niXA
  39.474 +2Zua8nDx6wmYLvzugFBrmS2cA3epuNLDbnhQ5oHR217SZY/pVTKLmEXEanY85ISF
  39.475 +yuKCmZx1H7Rhcnr/SJGcmcTyXoZUQHimhWnXvMOpGUZ7+dIqTaSgBC6D4D3KWFVl
  39.476 +FywjpwU10PVJQZRSHwWsO6z4UCOrEHq1F13EUe7RJnguhaCoPdFfZNM4i6MxRSCo
  39.477 +xV4bv1+WxT1trY3bodnK//p6/7OXPrhIj0dmtdFELHeWKes9w6E26pWLpzk9TaAK
  39.478 +Jp4jSGh5awjgFCsz3GT09HDy5pjesXa7TOMbsc9dbUUX3Z+JiyZC47F+hmwrOOek
  39.479 +4G34/GXz2RxJdV46lr4nfuU8y1P649202BbKxQ0AEQEAAYkCJQQYAQgADwIbDAUC
  39.480 +WwwDoQUJBokmLgAKCRA0NGcwRzQZ611iD/48dFaRj61CvBuYsed+Kk3uo9pCs04W
  39.481 +SWiUarnd9zKlx3ChN+YtYMTDRpQcH7JEP0N3OifA3nOSgLgd7/HrPdt6Aim5k7v4
  39.482 +Fw7AwEuCbP3w92hzot4OetOyya6IHy8xpiqRj2etPzNAbB0kBEvwmNKSOZMPVRZ8
  39.483 +0Pegz00OI5OMGopuYgZcyAd/R5ZhqJf+8EmHsNXwT3g3ifX7QtXOXlfK8cCExxTa
  39.484 +4xreoP7UWIAUHmWz0wFnPFNQlTt42oA9mF3PjGgCmJ7j4XF7cvEyO0GDRZ1ZGWbE
  39.485 +xrk/EdGKrBQBwlCdxc/1Q87B6Kl2igXAi6rvOeUSWD5TAJSoi5M0gZYB7/6Ve+1Q
  39.486 +04sTmRt3ev6mLLb2Fu/glT7LpVUcMbpLrOB+Pm2d0eOZxVeElO7RV5nJQ8LNwtrl
  39.487 +uBlk644rn9mWiVhfdhfmP/eluXvCyps8BUFwZQu/LZB7lAFiIF0cr+7dKiLRpgMi
  39.488 +RLhTCQht6SEO1rreSb1gF7Em+aJzv1hpvbzQp46vUOqeUGZr1iF840W0b7n/s4Bp
  39.489 +xED67TQi25vFfEYYBtEzYqTCgI2v1h5ixtBkovFbXv28RYZPg5bWfAOQIwb3AnYv
  39.490 +FGBN2XdeO0ytL8rT7qKhvcS63E6ap605r5IvpgpJFap2KhWh2mwHYvNTWPnf1uTO
  39.491 +KgBhWHuSC0CEbA==
  39.492 +=oYD/
  39.493 +-----END PGP PUBLIC KEY BLOCK-----
  39.494 +
  39.495 +--------------D703284A94612CBD63CC1F3B--
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/test/test_files/432_no_from_encrypted_and_signed.eml	Fri Sep 28 10:36:44 2018 +0200
    40.3 @@ -0,0 +1,92 @@
    40.4 +Subject: Fake removed header
    40.5 +Reply-To: krista@pep-project.org
    40.6 +To: pEp Test Bob <pep.test.bob@pep-project.org>
    40.7 +Openpgp: preference=signencrypt
    40.8 +Organization: pEp
    40.9 +Message-ID: <738942f0-8558-dab9-5f60-33267708110e@pep-project.org>
   40.10 +Date: Tue, 28 Aug 2018 17:00:59 +0200
   40.11 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
   40.12 + Thunderbird/52.9.1
   40.13 +MIME-Version: 1.0
   40.14 +Content-Type: multipart/encrypted;
   40.15 + protocol="application/pgp-encrypted";
   40.16 + boundary="9URwsx7u29XUW6rbMgCxFfvSekUGqtOLi"
   40.17 +
   40.18 +This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)
   40.19 +--9URwsx7u29XUW6rbMgCxFfvSekUGqtOLi
   40.20 +Content-Type: application/pgp-encrypted
   40.21 +Content-Description: PGP/MIME version identification
   40.22 +
   40.23 +Version: 1
   40.24 +
   40.25 +--9URwsx7u29XUW6rbMgCxFfvSekUGqtOLi
   40.26 +Content-Type: application/octet-stream; name="encrypted.asc"
   40.27 +Content-Description: OpenPGP encrypted message
   40.28 +Content-Disposition: inline; filename="encrypted.asc"
   40.29 +
   40.30 +-----BEGIN PGP MESSAGE-----
   40.31 +
   40.32 +hQEMA4rbkTfsG51OAQf9FNb7XSpEj9pZ2+FBeIvjRP052dw7D/r4du1cnYVIT1lO
   40.33 +vFQ8KDH6TgWBNATXo3zUetPSu8ijysjf3BkjB8oXM6WVGW0x0YG7VjrBUSllNTG4
   40.34 +7lq7zHMBxvPMsoVq9l6AruJotFdCpscNPiKwFW8ippx6I6dfC6nkNsSX7VMLrfQ7
   40.35 +ijgwN6jaOTlhfohFDRVxdGce38/4bdpB6ywZCeTdzFQF8G4sPDwcqwEE9CdTgSLj
   40.36 +zyi4OOVwbbFV4zWDHM4X5Gw8OHoedsmbUwDrDtImxjhjBjhbXSUG/1uVivcguZAB
   40.37 +0oAk1YPlAOpJXVFXEv9UMv+NsaYsRerukeO1LIPFDIUBDANaAgXZcwg/TQEH/jRn
   40.38 +KnJa0rp1H1r8BJVZwk20P+kDZhUF4PQ/3bt5d8+DILS284AQ+FkulQu+Qf4MymYh
   40.39 +puPPZwsgRSvbgPuMNwTsvDsoQOWd3qa31ujL7ocbTJXqwt6/CZEuW6j9vIfbFmpG
   40.40 +g30u0e1MZHuU7kcBMptcnpUEE4PoKTTSOK8kcGY6UZwWwJzfMUTi2eR2CawJHJl1
   40.41 +VUCfPp5QU0Lh990cXCEM5RRSddx5juSwIjkozpuP0joaEgwCjh8PLVXvH3r3MKiG
   40.42 +Mp5SAJzfGvvcA+n1A1GSXs7RWw8YwgtblqwJtyCGg749SfKAEVbKQnZiBGgXasfN
   40.43 +fuzEo/kJupFBUwseZp3S6wHXYvz1Fo2eK2pcw9ZnN7+gVawXj27pe+gSTheSt+Pj
   40.44 +iVap9q2mBiZ63ywwvDhs6ON7lDmu6mnmN0ANt9fUW1bwF7vmRBDqzgQuaTKKzgag
   40.45 +gASTYKQqY1s1DQNlXsRx1hPDkvxZyjbbGg6BK0qsGGdT4UWVbe05+N63xK4/RLlK
   40.46 +HNU9wRGy++qwNlv5rL4GNlOGV2ypVLGRWdS2ER211qzEUxm1iIuF0Zcdn4Sozx3M
   40.47 +rItVn0Moyx5ddANOANQlHtJCBAPsabP67+PV8UbIn/GEONdWsyrAgVAUpvqsmEGf
   40.48 +2FluwpxnNyy3qR7LzHzejNuXcCOwAylvbPXqJ/1wtAXjaHYJVcJekeDGKLIgj80K
   40.49 +CiuCM9V2cf95luQr+3u+x0+lAAChFlRoWG8Uk+QlgmYEu0YKSZ0+r435aoo/N1kC
   40.50 +7dMb0ZrWqaHiBA85PGa6j2dCz5YwXWPRmmKIx+RlfCbGlczAspQIdnrwCVD9FWT9
   40.51 +7rh+Kkjoc1bpyzwvnzjPPDBje6ntjLc+0TGP6rMvKQlUIoFX9FKYuvZk1Jm0QDFR
   40.52 +U3MpxHsYZefJFIhzgPreQno+sBK4MRPqQkrybzHk6StdfXrl1tDERZXRqayDmPQJ
   40.53 +xYqD8s3SE3KVyQtJpJdFQyRSHL4JEBpHwb0wokk9Hk5MHH2cwCIigBhYr/blRbBe
   40.54 +uh0y9GTfLioCmiSn5LpyRpIw5941g/2gFwfkhHdJh8SYTI+FS3m0lfP5UCCH7N3Z
   40.55 +QEgSqpT0wdSwiMFoaD4Lu9SFlAVIEl8DgLVxDdsfRwoKnt1gn+e4fSCZJLPIQd4b
   40.56 +BVjc7DLmnKLGr405S6VOMGxiigsxP/WNQfEUsLNE7SQwxCRMdA38wwz9ZqKMGZGs
   40.57 +jzES6rC0qbxkbu/ZjgUg4SL2OsIQqXfxZ6IPcRtA2zfC/hVp862ZeWx8KZ5bS/Ge
   40.58 +cTuTb5oajq09zcIqsTijvyVLrPQ1QhK0zNq921Q7NoCHhckX1iMEN/eFTuDo8yRU
   40.59 +h0cQVtHFxTXf4Ho0/0L55wVnME8VkxUF6BKk9dgGBTUgj2Yf8XA9XraYAq4OSoS3
   40.60 +inNSDShHWbP0fm5xW5kgGGJhwDU82OS2Uni5UkeAN7UyZ98wL6toUiPfoioVq2/6
   40.61 +N6zIYQmH1cBYdtgpMEUEILWhjLTfdYGpbPe08sHOC7wMA564S2DhzQZT4M51JHQ1
   40.62 +rIJwBoW0MqRd5YG1Chnafgbft7ZDFk8BVAAvCGOkNffOGO1yl8OPX2CE4ANw2veI
   40.63 +4kmnlyGY/WEMhzA51t4kCqXIeLP9wU967lBW+dAyl7+FhI8KnltOKNdZr4/72dlc
   40.64 +hPr6Vro0luImdO/KsqjFrnBbG21+HkVnwmJ2dUZ+msoGwWecoMzACv/S/HuoIg/0
   40.65 +QTn0wbzHXYavIt7CSTdUOQMTBsjaWZcfWYBmeuGni4iy3E3Mki/hby2LGvwdYVf1
   40.66 +NW0yyzpaiAzc+ZrGr1Dgrtx9Tgrc/SecWjyZEGztLPJxB8hn3EoVK0tVGW6CgeoG
   40.67 +BWBqBIZyFSaAc9kh6oIs6EJr7+cAMjFp4ljgNoOMRizbPyfYjw/JkE9ookogxS+6
   40.68 +61qeh5qCzW5gGNmkJXKf6oYhST2KvM310sjXvmVKPFsfk9OYnrtHUyTOVENba335
   40.69 +c7wthNkWvnkh0khSOXFyRY/eGvdx7tBWGRXzdwom8HB6Z0QeZlb15inJZAiD8ciQ
   40.70 +JPz5irO3UCA9TQCQU95Tw4hsgewC95xW5yCmi8oFE6EDA2ht6/bxCwaHfdnHMlDu
   40.71 +ALdX8PEC+dKeU5mwYZjk+hU/aoLs6o+ZizoLq3NqWELyVhc9E0t3IgT6SwumFuKJ
   40.72 +/BOhhYfruSb98bCTwSmALBke8KrgafAoqGmb9l1kcYY8y6cbCrn0wwF4B0C74kL8
   40.73 +wrlfAouvRXXN9ZBsXz5ZjD0B1cf+p1sER34+eX6n+6codEaPvHHqGSe3HNAYf1bE
   40.74 +K4nqQ9784cMw3z/fzBQ21i4M2dMdhnpcRIShxJNc9PcC2Hveg676dhgbXkPPp0Rn
   40.75 +QZfghkX8VvIHrD+eaMdmZYUTYv/B4W6RJf1j9Gtf0+ksdMBT3ovtSVryclMKXkYv
   40.76 +lOYLOC+AFd8OqMg+XctaRp8g+FKo8w647mpXbhTE6Lx5g9hP8T+uoznWHQGDRZ1S
   40.77 +buE2d9kM2gcyT83WOCtnhH7wtJNDdP5gup5kMcBJnEL3MDiPLj0RQjUbAztsbGfV
   40.78 +hDxI/aQ+AF/GxGmIObCdASr7uB24zNhX2+a7fbEZ7jjUWf12MFyPpmyLy+sz0tSe
   40.79 +nmNB1MexlPis9bKqlxTuw7hxQULklNsKFvfeo2nhmLirbaaSQHXg6IfWGVZQ7I3b
   40.80 ++3QGtaw8YaJHuw+2r+DHpyBsKOOCnVkTf69t4URpRSsu3Q5ClH4HD+tlyhKGtKGc
   40.81 +KoP6AiWmI/EscnXke3FOwhEMEaO+Cy/iDb6Plvd/MjQg4bQDVADfK6e9Jk4NvbQq
   40.82 +uAtW5qq5ng+osr1yClxpdfKyhAVc5xUF5//v04u2N/K/aY6J0IjUmReaWKZsyisq
   40.83 +B9peITPxqJtLQFshoTs+BmgQqsGhxMGH8qXNYPWDFYh2KT5v2LvTfwPP9JFw7/YV
   40.84 +/Lhv9RqccyXXWP2hozcMUdNztM0SmLTXjr4V8s90ipokk/q2MmiwSADYMpjPvgzw
   40.85 +MOEAHlIjlS4IzoNPT3fDQaHVBpiPZxCEgP/cej4cOW+HTv7zILSk9WKWlX2cYlMA
   40.86 +wElpxXLIsOPlraq+2vpYJUBqikgoctXWNwdSXNLBhAeGoOMIR0INdPejDVpR9ALf
   40.87 +GwwhtFirHIsVCRKiWAXZabCQuZK2R7NEofd+SSWij4m0Ma/zWd0DKDsHMP+QWPqL
   40.88 +dLs7uhHqtyOQS7/9f6sdIh7GtFsm99HWkfEptnX8RAesVovSv89SScU5NsFztHSd
   40.89 +dk09U4eM792Pxd8eBylg6A0ClNevPCwkXdLkPSp0WrQ7dqf4KsWpa7tQCWDVWfWY
   40.90 +sqA3ztNY4pZ+aUMMxgnmNLmPSV03wqgwWWz3qZenkyPrwU6G6X4FIoBN5vHZuekH
   40.91 +96e4DjtXsuDTophREz3iv100G3FlPaoTr/ra
   40.92 +=52Ta
   40.93 +-----END PGP MESSAGE-----
   40.94 +
   40.95 +--9URwsx7u29XUW6rbMgCxFfvSekUGqtOLi--
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/test/test_files/432_no_from_encrypted_not_signed.eml	Fri Sep 28 10:36:44 2018 +0200
    41.3 @@ -0,0 +1,83 @@
    41.4 +Reply-To: krista@pep-project.org
    41.5 +To: pEp Test Bob <pep.test.bob@pep-project.org>
    41.6 +Subject: Fake removed header
    41.7 +Openpgp: preference=signencrypt
    41.8 +Organization: pEp
    41.9 +Message-ID: <5827095a-5284-7511-5a93-09863043378a@pep-project.org>
   41.10 +Date: Tue, 28 Aug 2018 17:00:18 +0200
   41.11 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
   41.12 + Thunderbird/52.9.1
   41.13 +MIME-Version: 1.0
   41.14 +Content-Type: multipart/encrypted;
   41.15 + protocol="application/pgp-encrypted";
   41.16 + boundary="NSkgAD9jvONNSWxuU6NbZsLr3E5X4TCOO"
   41.17 +
   41.18 +This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)
   41.19 +--NSkgAD9jvONNSWxuU6NbZsLr3E5X4TCOO
   41.20 +Content-Type: application/pgp-encrypted
   41.21 +Content-Description: PGP/MIME version identification
   41.22 +
   41.23 +Version: 1
   41.24 +
   41.25 +--NSkgAD9jvONNSWxuU6NbZsLr3E5X4TCOO
   41.26 +Content-Type: application/octet-stream; name="encrypted.asc"
   41.27 +Content-Description: OpenPGP encrypted message
   41.28 +Content-Disposition: inline; filename="encrypted.asc"
   41.29 +
   41.30 +-----BEGIN PGP MESSAGE-----
   41.31 +
   41.32 +hQEMA4rbkTfsG51OAQf/YsSAXKEEOOIdyYtTTE37kvW7/YD1WffK8yBZSo2gJdkD
   41.33 +ypcQWx8hDfK+h+K4AQMQsOaSHelijGyPnhy6sGsbhCbubee0xxjuu44PMK5XVuWs
   41.34 +NrDjTRDGDdm521Hw4jSZFQaqvgnK+p1HEuVG0aErVdaJKOPAIQdIK1jPaV5UAtmV
   41.35 +5PSw9n7Cuf/YFYBspNh7dg4s9b7eQcLYmCxvlY9DNrfqsFEs0hjzVLw3jK6m2HP9
   41.36 +v5kKznmF/IeLDLFon8puAn9rnCc5fSui9khIqrZ8c7llJh4bxOdsnwWeHMktamP2
   41.37 +KR/hsp62atwnMLpBtkVT7rVbmFeaM8YXLYao459KOYUBDANaAgXZcwg/TQEH/1bd
   41.38 +yKgvu7WT0W2nkxQQ6pe/w+TBgiE98MGTZe1zJnkDat/rO2Zn1Ee0anNOPM/B/itv
   41.39 +OPVy1UXo/+2J8TxsaYtqytiYR+fb5hg0BNRHIjQ0tWoqr89uPX574iBajH4Vg04r
   41.40 +IOTim3cm+wh0+8QMUGfscsjl58l87xS7sTICGsMJgn3jh3D/nht1n6paY+vHQFwP
   41.41 +0Jbtoj5KNknD/JleLkrIEZqbxpi7lgDYcIc/94HtbephkT9ATlJxFOKOV2dC/i5W
   41.42 +aCXEMZkYur3gy1IXn/5DjW42k/ZAsIO1NjTIMdsGwuX1n+Jsa++lPej7NKMp1wMx
   41.43 +2BDjGU3hztz3VfQNVaPS6gHIwy5zGLI4MvE61IrBD6zC1x5M6oy8UAjPP7vyae5d
   41.44 +O31ayAcKQq7WlIUc0PM3OB0qiFFxAozYc8b67o0XMy0zBzCm6c6Koxo00I8UA6V5
   41.45 +HSPhLQ2icjgN7R5XoOZ/Wh2ZiaGOZvDiquRZqqL2EMuu1JFPQJVTDbUgCsLbDNIz
   41.46 +kC3baypXYAcE5ipGe9AS/1kNtVcj5xHQBgIl3Brc7CHOFPV1SaXKTeJATsXVwP07
   41.47 +r6dR/Uikl493VX7RWypAFx7ebFBwavpH1z0FBNBNrjgN5zo54op1U7dyRw/KUv95
   41.48 +lxM/6UNVK0lnQ0kKboVDlP98JxpBIieT7TYFgADWBK/2Fk21ZUATjWzvjBkpNyBq
   41.49 +KiLZzwFhikz8dPQKw2rcAZXMfrOt5Ubcy3uqn9t5FzqLuNr8rsna028a3V8gyEpy
   41.50 +YMcw/3eOJaiGFjEh65zuYPIisf4M1PWC9Fqas7Z/kBiqSh4M0z8XWGHantGn7hea
   41.51 +zUXKFa3lTTbZSk5xkQhxgt4p+OX7g3XJLhL0nAl89geoQxei1gAu1W67eampcoMI
   41.52 +Z2cErd7W60XWxtkC6a5hn8p+r8EKbP0Gqn8rHb9R/xqzhi7GgfDU+t4rTIB04Em0
   41.53 +u8WvPUi9OlRjbT6Coj3QaTWBL+Fi+stKgPQlaEE0NpH/27YW6XwESwA8AL6Gae0s
   41.54 +ZgrtNOnypwjhKP0/vRMapLDwXOvBUbZoVue9ZXaVgo2wdlEmSPVjZgl1Lxs/F+eh
   41.55 +7g8ayDrpSCzw9lTtFi15UCerD+3R4eiVvopL8hv7WEJSSKrmLU+nyq0bI6hUClow
   41.56 +TtDY7MfkOLJ0+bm7n7jCNG7mb9jNn9E+vsMpUmCgNmHCmBpRGPQQlxuvcdZQRlqw
   41.57 +/ULY7Hxvy5KZXHJULD6simunWuNGoIfDoAz8gzGpLM66rxkvN1hsR5esuNctNTOX
   41.58 +F/v7ifFAcNcXVQDNAtTAAZj6ta1TOWovePWERynTnCLjD3BDz8xgQMkA9ajGqVSw
   41.59 +kRSuvq+nDpef2tK3qApvAdUVkOODW074waXo6dXBfLjYlwPkDn1SihbO+K2BI2I9
   41.60 +map08Kc4fvXGDbUBDfS5QmHlOPZjjE1R/5JSp9LHN5++hSVJ5lBbYsbvRJ2Q5LoS
   41.61 +Iw2VPVp62iStwpkz1s1Ah+X5ls+t25LAmciIc1LSAiQFZeLPbLG5V8+jONdXtQCv
   41.62 +vIdOBrNUuRKo6vKLV4AuOIK6aztDxq54g5Hi+I3x8CMIGPJnJQbCQqV5eXrORoPW
   41.63 +BWNQ9d/qX7egMUXqGlyIbxY7DA5H6z2TkclQxUGSEnkTnuLZzTPqEhEXYrx4CcDC
   41.64 +caAVwzUNlAXTcOrnO/dvcfzF1IxiBsN7/TxF326REmnp48ah9o11gQ04eOoOyVsf
   41.65 +aG68+yldxR+M24oRqLL20yhsrEe0THBeJsjaUhgK+Yz4jZBVl8W8zP72/TQxo22R
   41.66 +pAvIfKoqjKnqIwSD6QP2WUn0OkfvDTqEUZCHUNH7qvh/cIi/cZWHgCVoUHA4FX0G
   41.67 +iIn4r9MgA02512u4OE85P5S4FcYPh79dvkX7gRvTIAjtuN95e3ozQqgUntwwx+dc
   41.68 +da+xdSCIGuuoGmSwEad1OQGSm70eK4Hek+8CMXS0KfpARdw1PzYbl0vWx9JDace1
   41.69 +uSU67kXCBClBcB9XumkK5MC/X5bwPy4RHQvujvvQtnv4pwokjRCiO7Z+ibFEDaiq
   41.70 +jh5lz6u3jgfxKVJRuGRHPoj3YKngv4IUtMjRPsg+VEIcPmoLHQzsX0cd59ksPzVT
   41.71 +9hQRfvVB+AG++iYpYuCNsXUShtyCO/2RQoJaho3hW4tW2yXeaSwx5AteRVcz7cLV
   41.72 +1ytq2eiyAEyk0LKH8MVDe9MSTAsallyWDikE/vvgSnPi17MpLkmXfhs4iykNUQk7
   41.73 +qSEdwxcySlWyCg7Vd06GQB1Jp/0NbKdI7DQ5SnQeL14ZjcT6FtDtOgcDl9PIw0zc
   41.74 +QsFhvE0azlD0Bx1C0Kk27RYfDgnKYYQMNCd4y4MF/mb+06SfJVhApVydL8FzlT/T
   41.75 +SQIhD2tQCNdQX8qaOm1fQaXAonyL6na0eSY9uSNG2PI2+rIaVQoIoewA8MPiRe9K
   41.76 +roDDXBL64MfCMmJPytrAVYgcRtj1r2pnF/j8a2D5ocIAKtv+1ZVD514J1ZLJhYsu
   41.77 +BymbDwCJ3ZdLZpe7xhzZPNq9xR/QfD4gDn2dFmU5QDOZir5W5ZfPNotX9NkwL9SE
   41.78 +shrnHKPK0shMXrqtWOFjAAZRYFyt+8yop+fiM4zWzIt6AFWO521HILw3d7yolltg
   41.79 +1n09/U0u8I43msxSUCn8YH16WECrxRSWYp4zlaC3SL6MY5KNwRUZQ2ewH5YMD07B
   41.80 +I6Cv5VR2MyEJCbbDuuV1rN+Yl/wGhIQ43qO3IaUY/ex4l9WQoS4QVycfS62ryuuF
   41.81 +x01DwQOOAlq5BtzkVdCnAnVokNJAzq66wmtmBkv5oCrujsYHR2hcgEMApVYqh+LX
   41.82 +OZeRaNbLTiNbildSJBv4nI9+FVkZBAxSc3VMxnKPgnTRWW1wuw==
   41.83 +=TGci
   41.84 +-----END PGP MESSAGE-----
   41.85 +
   41.86 +--NSkgAD9jvONNSWxuU6NbZsLr3E5X4TCOO--
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/test/test_keys/priv/pep-test-bob-0xC9C2EE39_priv.asc	Fri Sep 28 10:36:44 2018 +0200
    42.3 @@ -0,0 +1,57 @@
    42.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    42.5 +
    42.6 +lQOYBFV4Pl8BCACuukQLwsHftH5jkVsSL7COFhamNsEE8lZ8MG1f1Rx5ztPuZTna
    42.7 +YXyWODgpj2Bxz0TcP+Q17GbLKse7TWD1k9i1RzLWz8ZSCLYq2TtjLWPleVuGGWeq
    42.8 +Y3tTWHC/nFbivolNPA0mL2038TGdBolPaZiPZ4P8wuQVYNfDqi4utcezGDNS8OHh
    42.9 +EPhfyKKoSM79HLoUPc6xsfimxPMrylI/i8bFvfDYz5vmydefvAxNhqjLH3Gmhj1p
   42.10 +nInsraEiyh7Y2zAxCfr6hD9nky7WixBinKFFhQpcUu1o+Ie6UGwLVbTyRMOcRsob
   42.11 +yahqA/m2HfDRj1Y+n8HHqsQkB2BtmMYXla3jABEBAAEAB/wKqiU2GVr1zJ5iqGZ7
   42.12 +hS9zDk3imXjAuwpK7GlfAVk9snSRpycK7IrxeX8s3J30qsOxGv5sYvOUcGK35kCs
   42.13 +eV78RyfthmM8WMcs28ATgE7WtkhyUAGmTwnuq9+Ldz9MYEUHUrEaXnTkBocFmd0I
   42.14 +Qx5qZLvHHtDtRx4HfAJZz0/5kj8KyKYB5cYsvRoLYdCWuxeIbJu5FYtHHBywNFnZ
   42.15 +Qt8STaQqZPD0gPh3ahzY8KYJFZbSFpGfaH0AX5dkFpUJdyad4R2c9ZOmnaK3W0Ba
   42.16 +cdQSdi66iiT0UG7f6ECR9HfI+nVfshOVLZA90p+LqLW51S7iBeFAoZyYfKuNrE9b
   42.17 +pV3VBADNf9Ec2CJ3jo2LrTrkN1HkcjmwdosFQWaDaXtRmV/GidWAyTS+JzaxnS1A
   42.18 +Y9klOqJktVNegrrkk+Xo6jHxkneGucDSsxpIVIcqTa2LGrt1E1eHNYwuEPIyHvl3
   42.19 +gPmfLCuetu+qp97+EOJBklSJi4ljPcAo7i+WI4Nsni6Q6eF7XQQA2aqRpIBmDdFY
   42.20 +9x3uAMDO3mSqIiEJWPiFZHs/qKGezJUgl4hrsjuiUWiD1gcPSS0zJRcZZ7GLYb9r
   42.21 +1uJOnzOtTLexEnAa0VJ9Svci+jtRX6HVETAnYqn9AQ/0sYvmTmWKge7q7BJHGnyv
   42.22 +YbyXmCwGyV8/cvSS8Mmh8iMYWg6mej8D/jN0ymPP9jGeuFav6Va/T8j+Fdl0zTVT
   42.23 +MkFPizlxJEev6PA9QKvAWo4iqRA3SIdqjrZpPcpwhalV5cK4KfHlh8/GagjU9kFS
   42.24 +JvUarmLZqoDqKT6cHb2OzcNBeCsuKGthraT1G+8NpXIgNr6a+5upo83pbL4RarPn
   42.25 +3u2JgSX0RPKDP8y0QXBFcCBUZXN0IEJvYiAodGVzdCBrZXksIGRvbid0IHVzZSkg
   42.26 +PHBlcC50ZXN0LmJvYkBwZXAtcHJvamVjdC5vcmc+iQE4BBMBAgAiBQJVeD5fAhsD
   42.27 +BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRBZv/SIycLuOaR5CACj3E6ykNqj
   42.28 +GS5PzghYfLJso6j954QzLwOozTzU/3/HWH4lC3Jmfr0pGI51KZ6Xevrp3N9SxRqr
   42.29 +uJCFRtwNeH3ujIgDh/UHCUEsP/+d74SOenIBYGUKE1OJmh8/LQdkNSc6JNdzJjDW
   42.30 +dKeh6cAMFvWju/Nqtl/l0FGspQU9dmCMtzkKgmwoKZW56aEVZ2lTxqNEo1aQ+lLr
   42.31 +NueBq0/Q5kAVEzUG7Ufm19wXjWenEMeeElX3UAGudLJuckx7uD8W/yBwqrRAbaCS
   42.32 +eZf6RVBLz96ekjWrVfMnmjkPuQPPt5cs98RxQTpxk7b6xLaWXymhA6cYU+FAW4Dp
   42.33 +bjfJjMWIFDcKnQOYBFV4Pl8BCADKQ2SV6gjR5N69xVdiCaefjwobrXR1niuBHBNT
   42.34 +XMJwPk2xv+e7fY28RK1BzODYCzBhpltvRoCcJi9S7Rqyz81nbxnw/1TaKtn6dDDh
   42.35 +ZPVHjN3vasDueM6xTEfEihNc0Owf4wz9SBjuredUVkdTxU7FxSgVP10dOxhdtkjW
   42.36 +jGW1DF6WlYA8BAIEdbpoheJHz3NFkhPQ8Dlzo7Ioe2t7vrTztcBX11o2e+FPOq1S
   42.37 +mhEr78wbROAyCVAXK+8qDh4zDq8iAMZK/KnZrm6pP00+iBRcb+JQgn3Gn+hU0lgE
   42.38 +3YB9kBJLeWaHxEPNnnNNvW/BMl53ctf8Ip+pzpA1K/S23KU7ABEBAAEAB/0UO5/y
   42.39 +aSoUXl8zv5ZpWGA8E1x7qU3MPZQfgwtMhwEXplEyVelHSvIkjQAsjridPqf1KhAy
   42.40 +dkHY8kRAo4xMqoHjIMIzu+76hgKDzcoH+gfumOD97qwPDub/kGBg1j5v8KGg4knD
   42.41 +L8pNXKMWlNeSFzDf6BmFipmfb3EVYBiIMceIz97c4BGvs29TC2wIKmJBRbWu9eS7
   42.42 +vqkBj8rEGi+pEnzTFvcZTMkoU6Uj/HifpvQ7BcOzUQ/1tiGQMEPv8oPMWmKudqBw
   42.43 +53e7RoYCZmTzuzI5fNvNcNT1EcUQmAfkgT6zvQuY63DAdECVx2f0p7MlgGA9ncQb
   42.44 +IVVdBtJXfwsAFmthBADXmavPPgiC8nU1q8e2pB0pmS3/uflPdmh+xKs0MxylDgSO
   42.45 +H9Ar7g9duxsrjxxHzlkTb0Am2XeWww3fBO762VH9VCAPH3FRoHGNCnY6Ix0MyikW
   42.46 +g4Gs66QXHMTNweOa9zk+cZS6N0H6dDis6x+9M1FCeJzy3gXaq+vfV5LfGeXMYQQA
   42.47 +8CnyHE7rjoqGNPnTWetuYgo6yhYJudbhO0uDewR5MdP1gwpTUmYl5RD41LSwTSGp
   42.48 +VSbjtct5dQg2ZhjUWxXcx1OC+aMafmDPi6S32mwbgfNtfTCIygM8CPDjdWbFu1ba
   42.49 +KbPA9Lc/SHgpg0vbdiZ4PWOqsqnig834r+3VfLX/dxsEANAWGGJRNTHmIwoC4HsV
   42.50 ++KiyApbBRw2TCHxJjlzFY2OFpe8RuGKE7HpKiSYjarGxP0RlESrbie0nbJ8FooIH
   42.51 +gY2ipO3khgK4MK1Xua405mNVzge9oNJPgWEtLabubimVnTwjU6O7m79Xl+R9BYb1
   42.52 +GVZm7f/WMDL7BsNVvhMVjdgiOOOJAR8EGAECAAkFAlV4Pl8CGwwACgkQWb/0iMnC
   42.53 +7jlqbwf/dP4sXDRiR5uVMh5WhOn1S8MnHZhLWAQ6fI9/KxggCPhgY6zAgszPMutz
   42.54 +BsQlV4P6QX30d99IMJrzGYYxjN7Z6fF7us9u103+GTzGQH7/47JG0eSTSaKQvqEa
   42.55 +N1+6M/OBZKcwNW6xHa+lhIS5nJGV3Oey/RFQwucBujQbtyjDN3aGshwqzhJXFBlF
   42.56 +3RqFzLxuAJmeOVedaKvdPjRhgFuxhkicUhVp27qXQCpDpkUkj9hb75yCE6pAzopO
   42.57 +6s65yHsnFyehwgyMrfpTPlPM86B1LH4IEwSaOrEJSdHnnFD8nnSIjRyfra3dsI/R
   42.58 +VNmYX8EkMGICzoR4lWcYFShJQM6QQg==
   42.59 +=rBox
   42.60 +-----END PGP PRIVATE KEY BLOCK-----