ENGINE-398: reset notification (outgoing) ENGINE-398
authorKrista Bennett <krista@pep-project.org>
Fri, 03 Aug 2018 12:20:08 +0200
branchENGINE-398
changeset 28002c40068e30a0
parent 2799 913e407519e2
child 2804 f58a31635b13
ENGINE-398: reset notification (outgoing)
src/message_api.c
src/pEpEngine.c
src/pEpEngine.h
src/pEp_internal.h
     1.1 --- a/src/message_api.c	Thu Aug 02 12:20:11 2018 +0200
     1.2 +++ b/src/message_api.c	Fri Aug 03 12:20:08 2018 +0200
     1.3 @@ -899,7 +899,7 @@
     1.4  }
     1.5  
     1.6  static message* wrap_message_as_attachment(message* envelope, 
     1.7 -    message* attachment, bool keep_orig_subject) {
     1.8 +    message* attachment, message_wrap_type wrap_type, bool keep_orig_subject) {
     1.9      
    1.10      if (!attachment)
    1.11          return NULL;
    1.12 @@ -910,14 +910,22 @@
    1.13  
    1.14      replace_opt_field(attachment, "X-pEp-Version", PEP_VERSION, true);
    1.15          
    1.16 -    if (!_envelope) {
    1.17 +    if (!_envelope && (wrap_type != PEP_message_transport)) {
    1.18          _envelope = extract_minimal_envelope(attachment, PEP_dir_outgoing);
    1.19          status = generate_message_id(_envelope);
    1.20          
    1.21          if (status != PEP_STATUS_OK)
    1.22              goto enomem;
    1.23          
    1.24 -        attachment->longmsg = encapsulate_message_wrap_info("INNER", attachment->longmsg);
    1.25 +        const char* inner_type_string = "";
    1.26 +        switch (wrap_type) {
    1.27 +            case PEP_message_key_reset:
    1.28 +                inner_type_string = "KEY_RESET";
    1.29 +                break;
    1.30 +            default:
    1.31 +                inner_type_string = "INNER";
    1.32 +        }
    1.33 +        attachment->longmsg = encapsulate_message_wrap_info(inner_type_string, attachment->longmsg);
    1.34          _envelope->longmsg = encapsulate_message_wrap_info("OUTER", _envelope->longmsg);
    1.35      }
    1.36      else {
    1.37 @@ -1500,6 +1508,129 @@
    1.38      free(revoked_fpr);
    1.39  }
    1.40  
    1.41 +PEP_STATUS send_key_reset_to_recents(PEP_SESSION session,
    1.42 +                                     const char* revoke_fpr, 
    1.43 +                                     const char* new_fpr) {
    1.44 +    assert(revoke_fpr);
    1.45 +    assert(new_fpr);
    1.46 +    assert(session);
    1.47 +    assert(session->sync_session);
    1.48 +    assert(session->sync_session->inject_sync_message);
    1.49 +    assert(session->sync_session->management);
    1.50 +    
    1.51 +    if (!session || !revoke_fpr || !new_fpr)
    1.52 +        return PEP_ILLEGAL_VALUE;
    1.53 +        
    1.54 +    if (!session->sync_session->inject_sync_msg || session->sync_session->sync_management)
    1.55 +        return PEP_SYNC_NO_INJECT_CALLBACK;
    1.56 +        
    1.57 +    identity_list* recent_contacts = NULL;
    1.58 +    message* reset_msg = NULL;
    1.59 +
    1.60 +    PEP_STATUS status = get_last_contacted(session, &recent_contacts);
    1.61 +    
    1.62 +    if (status != PEP_STATUS_OK)
    1.63 +        goto pep_free;
    1.64 +                    
    1.65 +    identity_list* curr_id_ptr = recent_contacts;
    1.66 +
    1.67 +    
    1.68 +    while (curr_id_ptr) {
    1.69 +        pEp_identity* curr_id = curr_id_ptr->ident;
    1.70 +        
    1.71 +        if (!curr_id)
    1.72 +            break;
    1.73 +    
    1.74 +        const char* user_id = curr_id->user_id;
    1.75 +        
    1.76 +        // Should be impossible, but?
    1.77 +        if (user_id)
    1.78 +            continue;
    1.79 +            
    1.80 +        // Check if they've already been told - this shouldn't be the case, but...
    1.81 +        bool contacted = false;
    1.82 +        status = has_key_reset_been_sent(session, user_id, revoke_fpr, &contacted);
    1.83 +        if (status != PEP_STATUS_OK)
    1.84 +            goto pep_free;
    1.85 +    
    1.86 +        if (contacted)
    1.87 +            continue;
    1.88 +            
    1.89 +        // if not, make em a message    
    1.90 +        reset_msg = NULL;
    1.91 +        
    1.92 +        status = create_standalone_key_reset_message(&reset_msg,
    1.93 +                                                     curr_id,
    1.94 +                                                     revoke_fpr,
    1.95 +                                                     new_fpr);
    1.96 +
    1.97 +        if (status != PEP_STATUS_OK)
    1.98 +            goto pep_free;
    1.99 +        
   1.100 +        // insert into queue
   1.101 +        int result = session->sync_session->inject_sync_msg(reset_msg, session->sync_session->sync_management);
   1.102 +
   1.103 +        if (result != 0) {
   1.104 +            status = PEP_SYNC_INJECT_FAILED;
   1.105 +            goto pep_free;
   1.106 +        }    
   1.107 +            
   1.108 +        // Put into notified DB
   1.109 +        status = set_reset_contact_notified(session, revoke_fpr, user_id);
   1.110 +        if (status != PEP_STATUS_OK)
   1.111 +            goto pep_free;
   1.112 +            
   1.113 +        curr_id_ptr = curr_id_ptr->next;
   1.114 +    }
   1.115 +    
   1.116 +pep_free:
   1.117 +    free_identity_list(recent_contacts);
   1.118 +    free_message(reset_msg);
   1.119 +    return status;
   1.120 +}
   1.121 +
   1.122 +PEP_STATUS create_standalone_key_reset_message(message** dst, 
   1.123 +                                               pEp_identity* recip,
   1.124 +                                               const char* revoke_fpr,
   1.125 +                                               const char* new_fpr) {
   1.126 +                                                   
   1.127 +    if (!dst || !recip->user_id || !recip->address)
   1.128 +        return PEP_ILLEGAL_VALUE;
   1.129 +
   1.130 +    *dst = NULL;
   1.131 +    // Get own identity user has corresponded with
   1.132 +    pEp_identity* own_identity = NULL;
   1.133 +    PEP_STATUS status = get_own_address_for_contact_id(PEP_SESSION session,
   1.134 +                                                       recip,
   1.135 +                                                       &own_identity);                                                       
   1.136 +    if (status != PEP_STATUS_OK)
   1.137 +        return status;
   1.138 +        
   1.139 +    message* reset_message = new_message(PEP_dir_outgoing);
   1.140 +    reset_message->from = own_identity;
   1.141 +    reset_message->to = new_identity_list(identity_dup(recip)); // ?
   1.142 +    
   1.143 +    status = _attach_key(session, revoke_fpr, reset_message);
   1.144 +    if (status != PEP_STATUS_OK)
   1.145 +        goto pep_free;
   1.146 +    status = _attach_key(session, new_fpr, reset_message);
   1.147 +    if (status != PEP_STATUS_OK)
   1.148 +        goto pep_free;
   1.149 +    
   1.150 +    message* output_msg = NULL;
   1.151 +    
   1.152 +    status = encrypt_message(session, reset_message, NULL,
   1.153 +                             output_msg, PEP_enc_PGP_MIME,
   1.154 +                             PEP_encrypt_flag_key_reset_only);
   1.155 +
   1.156 +    if (status == PEP_STATUS_OK)
   1.157 +        *dst = output_msg;
   1.158 +        
   1.159 +pep_free:
   1.160 +    free_message(reset_message);
   1.161 +    return status;
   1.162 +}
   1.163 +
   1.164  PEP_cryptotech determine_encryption_format(message *msg)
   1.165  {
   1.166      assert(msg);
   1.167 @@ -1625,7 +1756,6 @@
   1.168  
   1.169      identity_list * _il;
   1.170  
   1.171 -
   1.172      if (enc_format != PEP_enc_none && (_il = src->bcc) && _il->ident)
   1.173      {
   1.174          // BCC limited support:
   1.175 @@ -1809,7 +1939,8 @@
   1.176      else {
   1.177          // FIXME - we need to deal with transport types (via flag)
   1.178          if ((!force_v_1) && ((max_comm_type | PEP_ct_confirmed) == PEP_ct_pEp)) {
   1.179 -            _src = wrap_message_as_attachment(NULL, src, false);
   1.180 +            message_wrap_type = ((flags & PEP_encrypt_flag_key_reset_only) ? PEP_message_key_reset : PEP_message_default);
   1.181 +            _src = wrap_message_as_attachment(NULL, src, message_wrap_type, false);
   1.182              if (!_src)
   1.183                  goto pep_error;
   1.184          }
   1.185 @@ -2106,8 +2237,8 @@
   1.186      determine_encryption_format(src);
   1.187      if (src->enc_format != PEP_enc_none)
   1.188          return PEP_ILLEGAL_VALUE;
   1.189 -
   1.190      if (target_id && (!target_id->user_id || target_id->user_id[0] == '\0')) {
   1.191 +        
   1.192          char* own_id = NULL;
   1.193          status = get_default_own_userid(session, &own_id);
   1.194          if (own_id) {
   1.195 @@ -2150,7 +2281,7 @@
   1.196      // if (!(flags & PEP_encrypt_flag_force_no_attached_key))
   1.197      //     _attach_key(session, target_fpr, src);
   1.198  
   1.199 -    _src = wrap_message_as_attachment(NULL, src, false);
   1.200 +    _src = wrap_message_as_attachment(NULL, src, PEP_message_default, false);
   1.201      if (!_src)
   1.202          goto pep_error;
   1.203  
   1.204 @@ -3022,6 +3153,22 @@
   1.205      return NULL;
   1.206  }
   1.207  
   1.208 +PEP_STATUS check_for_own_revoked_key(
   1.209 +        PEP_SESSION session, 
   1.210 +        stringlist_t* keylist,
   1.211 +        char** bad_fpr,
   1.212 +        char** replacement_fpr
   1.213 +    ) 
   1.214 +{
   1.215 +    if (!session || !bad_fpr || !replacement_fpr)
   1.216 +        return PEP_ILLEGAL_VALUE;
   1.217 +    stringlist_t* _k = keylist;
   1.218 +    while (_k) {
   1.219 +        
   1.220 +    }
   1.221 +}
   1.222 +
   1.223 +
   1.224  DYNAMIC_API PEP_STATUS _decrypt_message(
   1.225          PEP_SESSION session,
   1.226          message *src,
   1.227 @@ -3412,6 +3559,10 @@
   1.228          }
   1.229      } // End prepare output message for return
   1.230  
   1.231 +    // 3. Check to see if the sender used a bad key
   1.232 +    char* bad_fpr = NULL;
   1.233 +    status = check_for_own_revoked_key(session, _keylist, &bad_fpr);
   1.234 +    
   1.235      *dst = msg;
   1.236      *keylist = _keylist;
   1.237  
     2.1 --- a/src/pEpEngine.c	Thu Aug 02 12:20:11 2018 +0200
     2.2 +++ b/src/pEpEngine.c	Fri Aug 03 12:20:08 2018 +0200
     2.3 @@ -446,6 +446,11 @@
     2.4  
     2.5  static const char *sql_was_id_for_revoke_contacted = 
     2.6      "select count(*) from revocation_contact_list where fpr = ?1 and contact_id = ?2 ;";
     2.7 +
     2.8 +// We only need user_id and address, since in the main usage, we'll call update_identity
     2.9 +// on this anyway when sending out messages.
    2.10 +static const char *sql_get_last_contacted =
    2.11 +    "select userid, address from identity where datetime('now') < datetime(timestamp, '+14 days') ; ";
    2.12      
    2.13  static int user_version(void *_version, int count, char **text, char **name)
    2.14  {
    2.15 @@ -1221,6 +1226,27 @@
    2.16      assert(int_result == SQLITE_OK);
    2.17  
    2.18      int_result = sqlite3_prepare_v2(_session->db, 
    2.19 +            sql_was_id_for_revoke_contacted,
    2.20 +            (int)strlen(sql_was_id_for_revoke_contacted), 
    2.21 +            &_session->was_id_for_revoke_contacted, NULL);
    2.22 +    assert(int_result == SQLITE_OK);
    2.23 +
    2.24 +    int_result = sqlite3_prepare_v2(_session->db, 
    2.25 +            sql_get_last_contacted,
    2.26 +            (int)strlen(sql_get_last_contacted), 
    2.27 +            &_session->get_last_contacted, NULL);
    2.28 +    assert(int_result == SQLITE_OK);
    2.29 +
    2.30 +static const char *sql_was_id_for_revoke_contacted = 
    2.31 +    "select count(*) from revocation_contact_list where fpr = ?1 and contact_id = ?2 ;";
    2.32 +
    2.33 +// We only need user_id and address, since in the main usage, we'll call update_identity
    2.34 +// on this anyway when sending out messages.
    2.35 +static const char *sql_get_last_contacted =
    2.36 +    "select userid, address from identity where datetime('now') < datetime(timestamp, '+14 days') ; ";
    2.37 +
    2.38 +
    2.39 +    int_result = sqlite3_prepare_v2(_session->db, 
    2.40              sql_get_own_address_binding_from_contact,
    2.41              (int)strlen(sql_get_own_address_binding_from_contact), 
    2.42              &_session->get_own_address_binding_from_contact, NULL);
    2.43 @@ -1505,7 +1531,9 @@
    2.44              if (session->get_contacted_ids_from_revoke_fpr)
    2.45                  sqlite3_finalize(session->get_contacted_ids_from_revoke_fpr);  
    2.46              if (session->was_id_for_revoke_contacted)
    2.47 -                sqlite3_finalize(session->was_id_for_revoke_contacted);                                        
    2.48 +                sqlite3_finalize(session->was_id_for_revoke_contacted);   
    2.49 +            if (session->get_last_contacted)
    2.50 +                sqlite3_finalize(session->get_last_contacted);                                       
    2.51              if (session->set_device_group)
    2.52                  sqlite3_finalize(session->set_device_group);
    2.53              if (session->get_device_group)
    2.54 @@ -2155,6 +2183,7 @@
    2.55      return status;
    2.56  }
    2.57  
    2.58 +
    2.59  PEP_STATUS get_identities_by_address(
    2.60          PEP_SESSION session,
    2.61          const char *address,
    2.62 @@ -2253,7 +2282,7 @@
    2.63              break;
    2.64          }
    2.65          default: 
    2.66 -            status = PEP_UNKNOWN_ERROR;
    2.67 +            status = PEP_UNKNOWN_DB_ERROR;
    2.68      }
    2.69  
    2.70      sqlite3_reset(session->exists_identity_entry);
    2.71 @@ -2287,7 +2316,7 @@
    2.72              break;
    2.73          }
    2.74          default:
    2.75 -            status = PEP_UNKNOWN_ERROR;
    2.76 +            status = PEP_UNKNOWN_DB_ERROR;
    2.77      }
    2.78      
    2.79      sqlite3_reset(session->exists_trust_entry);
    2.80 @@ -2641,7 +2670,7 @@
    2.81              }
    2.82              default:
    2.83                  sqlite3_reset(session->exists_person);
    2.84 -                return PEP_UNKNOWN_ERROR;
    2.85 +                return PEP_UNKNOWN_DB_ERROR;
    2.86          }
    2.87          sqlite3_reset(session->exists_person);
    2.88      }
    2.89 @@ -2670,10 +2699,7 @@
    2.90      *is_pep = false;
    2.91              
    2.92      const char* user_id = identity->user_id;
    2.93 -    
    2.94 -    if (!session || EMPTYSTR(user_id))
    2.95 -        return PEP_ILLEGAL_VALUE;
    2.96 -        
    2.97 +            
    2.98      char* alias_default = NULL;
    2.99      
   2.100      PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
   2.101 @@ -3703,7 +3729,7 @@
   2.102              break;
   2.103  
   2.104          default:
   2.105 -            status = PEP_UNKNOWN_ERROR;
   2.106 +            status = PEP_UNKNOWN_DB_ERROR;
   2.107              result = SQLITE_DONE;
   2.108          }
   2.109      } while (result != SQLITE_DONE);
   2.110 @@ -3754,7 +3780,7 @@
   2.111          break;
   2.112  
   2.113      default:
   2.114 -        status = PEP_UNKNOWN_ERROR;
   2.115 +        status = PEP_UNKNOWN_DB_ERROR;
   2.116      }
   2.117  
   2.118      if (status == PEP_STATUS_OK) {
   2.119 @@ -3801,7 +3827,7 @@
   2.120              status = PEP_RECORD_NOT_FOUND;
   2.121              break;
   2.122          default:
   2.123 -            status = PEP_UNKNOWN_ERROR;
   2.124 +            status = PEP_UNKNOWN_DB_ERROR;
   2.125      }
   2.126      sqlite3_reset(session->sequence_value2);
   2.127  
   2.128 @@ -3963,7 +3989,7 @@
   2.129              break;
   2.130              
   2.131          default:
   2.132 -            status = PEP_UNKNOWN_ERROR;
   2.133 +            status = PEP_UNKNOWN_DB_ERROR;
   2.134      }
   2.135      
   2.136      sqlite3_reset(session->set_revoked);
   2.137 @@ -4070,6 +4096,140 @@
   2.138      return status;
   2.139  }
   2.140  
   2.141 +PEP_STATUS get_last_contacted(
   2.142 +        PEP_SESSION session,
   2.143 +        identity_list** id_list
   2.144 +    )
   2.145 +{
   2.146 +    pEp_identity* ident;
   2.147 +
   2.148 +    assert(session);
   2.149 +    assert(address);
   2.150 +    assert(address[0]);
   2.151 +    assert(id_list);
   2.152 +
   2.153 +    if (!(session && address && address[0] && id_list))
   2.154 +        return PEP_ILLEGAL_VALUE;
   2.155 +
   2.156 +    *id_list = NULL;
   2.157 +    identity_list* ident_list = NULL;
   2.158 +
   2.159 +    sqlite3_reset(session->get_last_contacted);
   2.160 +    int result;
   2.161 +
   2.162 +    while ((result = sqlite3_step(session->get_last_contacted)) == SQLITE_ROW) {
   2.163 +        ident = new_identity(
   2.164 +                (const char *) sqlite3_column_text(session->get_last_contacted, 1),
   2.165 +                NULL,
   2.166 +                (const char *) sqlite3_column_text(session->get_last_contacted, 0),
   2.167 +                );
   2.168 +        assert(ident);
   2.169 +        if (ident == NULL) {
   2.170 +            sqlite3_reset(session->get_last_contacted);
   2.171 +            return PEP_OUT_OF_MEMORY;
   2.172 +        }
   2.173 +    
   2.174 +        if (ident_list)
   2.175 +            identity_list_add(ident_list, ident);
   2.176 +        else
   2.177 +            ident_list = new_identity_list(ident);
   2.178 +    }
   2.179 +
   2.180 +    sqlite3_reset(session->get_last_contacted);
   2.181 +    
   2.182 +    *id_list = ident_list;
   2.183 +    
   2.184 +    if (!ident_list)
   2.185 +        return PEP_CANNOT_FIND_IDENTITY;
   2.186 +    
   2.187 +    return PEP_STATUS_OK;    
   2.188 +}
   2.189 +
   2.190 +
   2.191 +PEP_STATUS has_key_reset_been_sent(
   2.192 +        PEP_SESSION session, 
   2.193 +        const char* user_id, 
   2.194 +        const char* revoked_fpr,
   2.195 +        bool* contacted)
   2.196 +{
   2.197 +    assert(session);
   2.198 +    assert(contacted);
   2.199 +    assert(identity);
   2.200 +    assert(!EMPTYSTR(user_id));
   2.201 +
   2.202 +    if (!session || !contacted || !identity || EMPTYSTR(user_id))
   2.203 +        return PEP_ILLEGAL_VALUE;
   2.204 +    
   2.205 +    *contacted = false;
   2.206 +                    
   2.207 +    char* alias_default = NULL;
   2.208 +    
   2.209 +    PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
   2.210 +    
   2.211 +    if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
   2.212 +        free(alias_default);
   2.213 +        alias_default = strdup(user_id);
   2.214 +    }
   2.215 +    
   2.216 +    sqlite3_reset(session->was_id_for_revoke_contacted);
   2.217 +    sqlite3_bind_text(session->was_id_for_revoke_contacted, 1, revoked_fpr, -1,
   2.218 +            SQLITE_STATIC);
   2.219 +    sqlite3_bind_text(session->was_id_for_revoke_contacted, 2, user_id, -1,
   2.220 +            SQLITE_STATIC);        
   2.221 +    int result = sqlite3_step(session->was_id_for_revoke_contacted);
   2.222 +    switch (result) {
   2.223 +        case SQLITE_ROW: {
   2.224 +            *contacted = (sqlite3_column_int(session->was_id_for_revoke_contacted, 0) != 0);
   2.225 +            break;
   2.226 +        }
   2.227 +        default:
   2.228 +            sqlite3_reset(session->was_id_for_revoke_contacted);
   2.229 +            free(alias_default);
   2.230 +            return PEP_UNKNOWN_DB_ERROR;
   2.231 +    }
   2.232 +
   2.233 +    sqlite3_reset(session->was_id_for_revoke_contacted);
   2.234 +    return PEP_STATUS_OK;
   2.235 +}
   2.236 +
   2.237 +//static const char *sql_set_revoke_contact_as_notified =
   2.238 +//    "insert or replace into revocation_contact_list(fpr, contact_id) values (?1, ?2) ;";
   2.239 +
   2.240 +PEP_STATUS set_reset_contact_notified(
   2.241 +        PEP_SESSION session,
   2.242 +        const char* revoke_fpr,
   2.243 +        const char* contact_id
   2.244 +    )
   2.245 +{
   2.246 +    PEP_STATUS status = PEP_STATUS_OK;
   2.247 +    
   2.248 +    assert(session && !EMPTY_STR(revoke_fpr) && !EMPTY_STR(contact_id));
   2.249 +    
   2.250 +    if (!session || EMPTY_STR(revoke_fpr) || EMPTY_STR(contact_id))
   2.251 +        return PEP_ILLEGAL_VALUE;
   2.252 +    
   2.253 +    sqlite3_reset(session->set_revoke_contact_as_notified);
   2.254 +    sqlite3_bind_text(session->set_revoke_contact_as_notified, 1, revoke_fpr, -1, 
   2.255 +            SQLITE_STATIC);
   2.256 +    sqlite3_bind_text(session->set_revoke_contact_as_notified, 2, contact_id, -1,
   2.257 +            SQLITE_STATIC);
   2.258 +
   2.259 +    int result;
   2.260 +    
   2.261 +    result = sqlite3_step(session->set_revoke_contact_as_notified);
   2.262 +    switch (result) {
   2.263 +        case SQLITE_DONE:
   2.264 +            status = PEP_STATUS_OK;
   2.265 +            break;
   2.266 +            
   2.267 +        default:
   2.268 +            status = PEP_UNKNOWN_DB_ERROR;
   2.269 +    }
   2.270 +    
   2.271 +    sqlite3_reset(session->set_revoke_contact_as_notified);
   2.272 +    return status;    
   2.273 +}
   2.274 +
   2.275  
   2.276  PEP_STATUS key_created(
   2.277          PEP_SESSION session,
   2.278 @@ -4118,7 +4278,7 @@
   2.279      assert(int_result == SQLITE_OK);
   2.280  
   2.281      if (int_result != SQLITE_OK)
   2.282 -        return PEP_UNKNOWN_ERROR;
   2.283 +        return PEP_UNKNOWN_DB_ERROR;
   2.284  
   2.285      return PEP_STATUS_OK;
   2.286  }
     3.1 --- a/src/pEpEngine.h	Thu Aug 02 12:20:11 2018 +0200
     3.2 +++ b/src/pEpEngine.h	Fri Aug 03 12:20:08 2018 +0200
     3.3 @@ -44,6 +44,7 @@
     3.4      PEP_INIT_SQLITE3_WITHOUT_MUTEX                  = 0x0120,
     3.5      PEP_INIT_CANNOT_OPEN_DB                         = 0x0121,
     3.6      PEP_INIT_CANNOT_OPEN_SYSTEM_DB                  = 0x0122,
     3.7 +    PEP_UNKNOWN_DB_ERROR                            = 0x01ff,
     3.8      
     3.9      PEP_KEY_NOT_FOUND                               = 0x0201,
    3.10      PEP_KEY_HAS_AMBIG_NAME                          = 0x0202,
    3.11 @@ -91,6 +92,7 @@
    3.12      PEP_SYNC_NO_NOTIFY_CALLBACK                     = 0x0901,
    3.13      PEP_SYNC_ILLEGAL_MESSAGE                        = 0x0902,
    3.14      PEP_SYNC_NO_INJECT_CALLBACK                     = 0x0903,
    3.15 +    PEP_SYNC_INJECT_FAILED                          = 0x0904,
    3.16  
    3.17      PEP_SEQUENCE_VIOLATED                           = 0x0970,
    3.18      PEP_CANNOT_INCREASE_SEQUENCE                    = 0x0971,
     4.1 --- a/src/pEp_internal.h	Thu Aug 02 12:20:11 2018 +0200
     4.2 +++ b/src/pEp_internal.h	Fri Aug 03 12:20:08 2018 +0200
     4.3 @@ -146,6 +146,7 @@
     4.4      sqlite3_stmt *set_revoke_contact_as_notified;
     4.5      sqlite3_stmt *get_contacted_ids_from_revoke_fpr;
     4.6      sqlite3_stmt *was_id_for_revoke_contacted;
     4.7 +    sqlite3_stmt *get_last_contacted;
     4.8      sqlite3_stmt *set_device_group;
     4.9      sqlite3_stmt *get_device_group;
    4.10      sqlite3_stmt *set_pgp_keypair;