refactor(peerstate): safe implementation of peerstate

This commit is contained in:
Friedel Ziegelmayer
2019-05-26 22:33:39 +02:00
committed by GitHub
parent d926b3536d
commit 94aa314f30
13 changed files with 794 additions and 772 deletions

View File

@@ -3,7 +3,6 @@ use std::sync::{Arc, RwLock};
use deltachat::constants::*;
use deltachat::dc_aheader::*;
use deltachat::dc_apeerstate::*;
use deltachat::dc_array::*;
use deltachat::dc_chat::*;
use deltachat::dc_chatlist::*;
@@ -44,6 +43,7 @@ use deltachat::dc_strbuilder::*;
use deltachat::dc_strencode::*;
use deltachat::dc_token::*;
use deltachat::dc_tools::*;
use deltachat::peerstate::*;
use deltachat::types::*;
use deltachat::x::*;
use num_traits::FromPrimitive;
@@ -407,7 +407,6 @@ unsafe fn log_msglist(context: &dc_context_t, msglist: *mut dc_array_t) {
}
unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
let mut contact: *mut dc_contact_t;
let mut peerstate = dc_apeerstate_new(context);
if !dc_array_search_id(contacts, 1i32 as uint32_t, 0 as *mut size_t) {
dc_array_add_id(contacts, 1i32 as uint32_t);
}
@@ -444,29 +443,14 @@ unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
b"addr unset\x00" as *const u8 as *const libc::c_char
},
);
let peerstate_ok: libc::c_int = dc_apeerstate_load_by_addr(
&mut peerstate,
&context.sql.clone().read().unwrap(),
addr,
);
if 0 != peerstate_ok && contact_id != 1i32 as libc::c_uint {
let pe: *mut libc::c_char;
match peerstate.prefer_encrypt {
1 => pe = dc_strdup(b"mutual\x00" as *const u8 as *const libc::c_char),
0 => pe = dc_strdup(b"no-preference\x00" as *const u8 as *const libc::c_char),
20 => pe = dc_strdup(b"reset\x00" as *const u8 as *const libc::c_char),
_ => {
pe = dc_mprintf(
b"unknown-value (%i)\x00" as *const u8 as *const libc::c_char,
peerstate.prefer_encrypt,
)
}
}
let peerstate =
Peerstate::from_addr(context, &context.sql.clone().read().unwrap(), to_str(addr));
if peerstate.is_some() && contact_id != 1i32 as libc::c_uint {
let pe = to_cstring(format!("{}", peerstate.as_ref().unwrap().prefer_encrypt));
line2 = dc_mprintf(
b", prefer-encrypt=%s\x00" as *const u8 as *const libc::c_char,
pe,
pe.as_ptr(),
);
free(pe as *mut libc::c_void);
}
dc_contact_unref(contact);
free(name as *mut libc::c_void);
@@ -488,8 +472,8 @@ unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
}
i += 1
}
dc_apeerstate_unref(&mut peerstate);
}
static mut s_is_auth: libc::c_int = 0i32;
pub unsafe fn dc_cmdline_skip_auth() {

View File

@@ -22,7 +22,6 @@ use std::sync::{Arc, RwLock};
use deltachat::constants::*;
use deltachat::dc_aheader::*;
use deltachat::dc_apeerstate::*;
use deltachat::dc_array::*;
use deltachat::dc_chat::*;
use deltachat::dc_chatlist::*;
@@ -63,6 +62,7 @@ use deltachat::dc_strbuilder::*;
use deltachat::dc_strencode::*;
use deltachat::dc_token::*;
use deltachat::dc_tools::*;
use deltachat::peerstate::*;
use deltachat::types::*;
use deltachat::x::*;
mod cmdline;

View File

@@ -1,542 +0,0 @@
use std::ffi::{CStr, CString};
use num_traits::ToPrimitive;
use crate::constants::*;
use crate::dc_aheader::*;
use crate::dc_chat::*;
use crate::dc_context::dc_context_t;
use crate::dc_hash::*;
use crate::dc_key::*;
use crate::dc_sqlite3::*;
use crate::dc_tools::*;
use crate::types::*;
use crate::x::*;
/* prefer-encrypt states */
/**
* @class dc_apeerstate_t
* Library-internal.
*/
pub struct dc_apeerstate_t<'a> {
pub context: &'a dc_context_t,
pub addr: *mut libc::c_char,
pub last_seen: time_t,
pub last_seen_autocrypt: time_t,
pub prefer_encrypt: libc::c_int,
pub public_key: Option<Key>,
pub public_key_fingerprint: *mut libc::c_char,
pub gossip_key: Option<Key>,
pub gossip_timestamp: time_t,
pub gossip_key_fingerprint: *mut libc::c_char,
// TODO: this should be a reference to either the public_key or verified_key
pub verified_key: Option<Key>,
pub verified_key_fingerprint: *mut libc::c_char,
pub to_save: libc::c_int,
pub degrade_event: libc::c_int,
}
/* the returned pointer is ref'd and must be unref'd after usage */
pub fn dc_apeerstate_new<'a>(context: &'a dc_context_t) -> dc_apeerstate_t<'a> {
dc_apeerstate_t {
context,
addr: std::ptr::null_mut(),
last_seen: 0,
last_seen_autocrypt: 0,
prefer_encrypt: 0,
public_key: None,
public_key_fingerprint: std::ptr::null_mut(),
gossip_key: None,
gossip_key_fingerprint: std::ptr::null_mut(),
gossip_timestamp: 0,
verified_key: None,
verified_key_fingerprint: std::ptr::null_mut(),
to_save: 0,
degrade_event: 0,
}
}
pub unsafe fn dc_apeerstate_unref(peerstate: &mut dc_apeerstate_t) {
dc_apeerstate_empty(peerstate);
}
/*******************************************************************************
* dc_apeerstate_t represents the state of an Autocrypt peer - Load/save
******************************************************************************/
unsafe fn dc_apeerstate_empty(peerstate: &mut dc_apeerstate_t) {
peerstate.last_seen = 0i32 as time_t;
peerstate.last_seen_autocrypt = 0i32 as time_t;
peerstate.prefer_encrypt = 0i32;
peerstate.to_save = 0i32;
free(peerstate.addr as *mut libc::c_void);
peerstate.addr = 0 as *mut libc::c_char;
free(peerstate.public_key_fingerprint as *mut libc::c_void);
peerstate.public_key_fingerprint = 0 as *mut libc::c_char;
free(peerstate.gossip_key_fingerprint as *mut libc::c_void);
peerstate.gossip_key_fingerprint = 0 as *mut libc::c_char;
free(peerstate.verified_key_fingerprint as *mut libc::c_void);
peerstate.verified_key_fingerprint = 0 as *mut libc::c_char;
peerstate.public_key = None;
peerstate.gossip_timestamp = 0i32 as time_t;
peerstate.gossip_key = None;
peerstate.verified_key = None;
peerstate.degrade_event = 0i32;
}
// TODO should return bool /rtn
pub unsafe fn dc_apeerstate_init_from_header(
peerstate: &mut dc_apeerstate_t,
header: &Aheader,
message_time: time_t,
) -> libc::c_int {
dc_apeerstate_empty(peerstate);
peerstate.addr = dc_strdup(CString::new(header.addr.clone()).unwrap().as_ptr());
peerstate.last_seen = message_time;
peerstate.last_seen_autocrypt = message_time;
peerstate.to_save |= 0x2i32;
peerstate.prefer_encrypt = header.prefer_encrypt.to_i32().unwrap();
peerstate.public_key = Some(header.public_key.clone());
dc_apeerstate_recalc_fingerprint(peerstate);
1
}
// TODO should return bool /rtn
pub unsafe fn dc_apeerstate_recalc_fingerprint(peerstate: &mut dc_apeerstate_t) -> libc::c_int {
let mut old_public_fingerprint: *mut libc::c_char = 0 as *mut libc::c_char;
let mut old_gossip_fingerprint: *mut libc::c_char = 0 as *mut libc::c_char;
if let Some(ref public_key) = peerstate.public_key {
old_public_fingerprint = peerstate.public_key_fingerprint;
peerstate.public_key_fingerprint = public_key.fingerprint_c();
if old_public_fingerprint.is_null()
|| *old_public_fingerprint.offset(0isize) as libc::c_int == 0i32
|| peerstate.public_key_fingerprint.is_null()
|| *peerstate.public_key_fingerprint.offset(0isize) as libc::c_int == 0i32
|| strcasecmp(old_public_fingerprint, peerstate.public_key_fingerprint) != 0i32
{
peerstate.to_save |= 0x2i32;
if !old_public_fingerprint.is_null()
&& 0 != *old_public_fingerprint.offset(0isize) as libc::c_int
{
peerstate.degrade_event |= 0x2i32;
}
}
}
if let Some(ref gossip_key) = peerstate.gossip_key {
old_gossip_fingerprint = peerstate.gossip_key_fingerprint;
peerstate.gossip_key_fingerprint = gossip_key.fingerprint_c();
if old_gossip_fingerprint.is_null()
|| *old_gossip_fingerprint.offset(0isize) as libc::c_int == 0i32
|| peerstate.gossip_key_fingerprint.is_null()
|| *peerstate.gossip_key_fingerprint.offset(0isize) as libc::c_int == 0i32
|| strcasecmp(old_gossip_fingerprint, peerstate.gossip_key_fingerprint) != 0i32
{
peerstate.to_save |= 0x2i32;
if !old_gossip_fingerprint.is_null()
&& 0 != *old_gossip_fingerprint.offset(0isize) as libc::c_int
{
peerstate.degrade_event |= 0x2i32
}
}
}
free(old_public_fingerprint as *mut libc::c_void);
free(old_gossip_fingerprint as *mut libc::c_void);
1
}
// TODO should return bool /rtn
pub unsafe fn dc_apeerstate_init_from_gossip(
peerstate: &mut dc_apeerstate_t,
gossip_header: &Aheader,
message_time: time_t,
) -> libc::c_int {
dc_apeerstate_empty(peerstate);
peerstate.addr = dc_strdup(CString::new(gossip_header.addr.clone()).unwrap().as_ptr());
peerstate.gossip_timestamp = message_time;
peerstate.to_save |= 0x2i32;
peerstate.gossip_key = Some(gossip_header.public_key.clone());
dc_apeerstate_recalc_fingerprint(peerstate);
1
}
// TODO should return bool /rtn
pub unsafe fn dc_apeerstate_degrade_encryption(
peerstate: &mut dc_apeerstate_t,
message_time: time_t,
) -> libc::c_int {
if peerstate.prefer_encrypt == 1i32 {
peerstate.degrade_event |= 0x1i32
}
peerstate.prefer_encrypt = 20i32;
peerstate.last_seen = message_time;
peerstate.to_save |= 0x2i32;
1
}
pub unsafe fn dc_apeerstate_apply_header(
peerstate: &mut dc_apeerstate_t,
header: &Aheader,
message_time: time_t,
) {
if peerstate.addr.is_null()
|| CStr::from_ptr(peerstate.addr)
.to_str()
.unwrap()
.to_lowercase()
!= header.addr.to_lowercase()
{
return;
}
if message_time > peerstate.last_seen_autocrypt {
peerstate.last_seen = message_time;
peerstate.last_seen_autocrypt = message_time;
peerstate.to_save |= 0x1i32;
if (header.prefer_encrypt == EncryptPreference::Mutual
|| header.prefer_encrypt == EncryptPreference::NoPreference)
&& header.prefer_encrypt.to_i32().unwrap() != peerstate.prefer_encrypt
{
if peerstate.prefer_encrypt == 1i32
&& header.prefer_encrypt != EncryptPreference::Mutual
{
peerstate.degrade_event |= 0x1i32
}
peerstate.prefer_encrypt = header.prefer_encrypt.to_i32().unwrap();
peerstate.to_save |= 0x2i32
}
if peerstate.public_key.as_ref() != Some(&header.public_key) {
peerstate.public_key = Some(header.public_key.clone());
dc_apeerstate_recalc_fingerprint(peerstate);
peerstate.to_save |= 0x2i32;
}
}
}
pub unsafe fn dc_apeerstate_apply_gossip(
peerstate: &mut dc_apeerstate_t,
gossip_header: &Aheader,
message_time: time_t,
) {
if peerstate.addr.is_null()
|| CStr::from_ptr(peerstate.addr)
.to_str()
.unwrap()
.to_lowercase()
!= gossip_header.addr.to_lowercase()
{
return;
}
if message_time > peerstate.gossip_timestamp {
peerstate.gossip_timestamp = message_time;
peerstate.to_save |= 0x1i32;
if peerstate.gossip_key.as_ref() != Some(&gossip_header.public_key) {
peerstate.gossip_key = Some(gossip_header.public_key.clone());
dc_apeerstate_recalc_fingerprint(peerstate);
peerstate.to_save |= 0x2i32
}
};
}
pub unsafe fn dc_apeerstate_render_gossip_header(
peerstate: &dc_apeerstate_t,
min_verified: libc::c_int,
) -> *mut libc::c_char {
if peerstate.addr.is_null() {
return std::ptr::null_mut();
}
let addr = CStr::from_ptr(peerstate.addr).to_str().unwrap().into();
if let Some(key) = dc_apeerstate_peek_key(peerstate, min_verified) {
// TODO: avoid cloning
let header = Aheader::new(addr, key.clone(), EncryptPreference::NoPreference);
let rendered = header.to_string();
let rendered_c = CString::new(rendered).unwrap();
return strdup(rendered_c.as_ptr());
}
std::ptr::null_mut()
}
pub unsafe fn dc_apeerstate_peek_key<'a>(
peerstate: &'a dc_apeerstate_t<'a>,
min_verified: libc::c_int,
) -> Option<&'a Key> {
if peerstate.public_key.is_none()
&& peerstate.gossip_key.is_none()
&& peerstate.verified_key.is_none()
{
return None;
}
if 0 != min_verified {
return peerstate.verified_key.as_ref();
}
if peerstate.public_key.is_some() {
return peerstate.public_key.as_ref();
}
peerstate.gossip_key.as_ref()
}
// TODO should return bool /rtn
pub unsafe fn dc_apeerstate_set_verified(
peerstate: &mut dc_apeerstate_t,
which_key: libc::c_int,
fingerprint: *const libc::c_char,
verified: libc::c_int,
) -> libc::c_int {
let mut success: libc::c_int = 0;
if !(which_key != 0 && which_key != 1 || verified != 2) {
if which_key == 1
&& !peerstate.public_key_fingerprint.is_null()
&& *peerstate.public_key_fingerprint.offset(0isize) as libc::c_int != 0
&& *fingerprint.offset(0isize) as libc::c_int != 0
&& strcasecmp(peerstate.public_key_fingerprint, fingerprint) == 0
{
peerstate.to_save |= 0x2;
peerstate.verified_key = peerstate.public_key.clone();
peerstate.verified_key_fingerprint = dc_strdup(peerstate.public_key_fingerprint);
success = 1
}
if which_key == 0
&& !peerstate.gossip_key_fingerprint.is_null()
&& *peerstate.gossip_key_fingerprint.offset(0isize) as libc::c_int != 0
&& *fingerprint.offset(0isize) as libc::c_int != 0
&& strcasecmp(peerstate.gossip_key_fingerprint, fingerprint) == 0
{
peerstate.to_save |= 0x2;
peerstate.verified_key = peerstate.gossip_key.clone();
peerstate.verified_key_fingerprint = dc_strdup(peerstate.gossip_key_fingerprint);
success = 1
}
}
success
}
// TODO should return bool /rtn
pub unsafe fn dc_apeerstate_load_by_addr(
peerstate: &mut dc_apeerstate_t,
sql: &dc_sqlite3_t,
addr: *const libc::c_char,
) -> libc::c_int {
let mut success: libc::c_int = 0;
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
if !addr.is_null() {
dc_apeerstate_empty(peerstate);
stmt =
dc_sqlite3_prepare(
peerstate.context,
sql,
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;\x00"
as *const u8 as *const libc::c_char);
sqlite3_bind_text(stmt, 1, addr, -1, None);
if !(sqlite3_step(stmt) != 100) {
dc_apeerstate_set_from_stmt(peerstate, stmt);
success = 1
}
}
sqlite3_finalize(stmt);
success
}
unsafe fn dc_apeerstate_set_from_stmt(
mut peerstate: &mut dc_apeerstate_t,
stmt: *mut sqlite3_stmt,
) {
peerstate.addr = dc_strdup(sqlite3_column_text(stmt, 0) as *mut libc::c_char);
peerstate.last_seen = sqlite3_column_int64(stmt, 1) as time_t;
peerstate.last_seen_autocrypt = sqlite3_column_int64(stmt, 2) as time_t;
peerstate.prefer_encrypt = sqlite3_column_int(stmt, 3);
peerstate.gossip_timestamp = sqlite3_column_int(stmt, 5) as time_t;
peerstate.public_key_fingerprint = dc_strdup(sqlite3_column_text(stmt, 7) as *mut libc::c_char);
peerstate.gossip_key_fingerprint = dc_strdup(sqlite3_column_text(stmt, 8) as *mut libc::c_char);
peerstate.verified_key_fingerprint =
dc_strdup(sqlite3_column_text(stmt, 10) as *mut libc::c_char);
if sqlite3_column_type(stmt, 4) != 5 {
peerstate.public_key = Key::from_stmt(stmt, 4, KeyType::Public);
}
if sqlite3_column_type(stmt, 6) != 5 {
peerstate.gossip_key = Key::from_stmt(stmt, 6, KeyType::Public);
}
if sqlite3_column_type(stmt, 9) != 5 {
peerstate.verified_key = Key::from_stmt(stmt, 9, KeyType::Public);
}
}
// TODO should return bool /rtn
pub unsafe fn dc_apeerstate_load_by_fingerprint(
peerstate: &mut dc_apeerstate_t,
sql: &dc_sqlite3_t,
fingerprint: *const libc::c_char,
) -> libc::c_int {
let mut success: libc::c_int = 0;
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
if !fingerprint.is_null() {
dc_apeerstate_empty(peerstate);
stmt =
dc_sqlite3_prepare(
peerstate.context,
sql,
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE public_key_fingerprint=? COLLATE NOCASE OR gossip_key_fingerprint=? COLLATE NOCASE ORDER BY public_key_fingerprint=? DESC;\x00"
as *const u8 as *const libc::c_char);
sqlite3_bind_text(stmt, 1, fingerprint, -1, None);
sqlite3_bind_text(stmt, 2, fingerprint, -1, None);
sqlite3_bind_text(stmt, 3, fingerprint, -1, None);
if sqlite3_step(stmt) == 100 {
dc_apeerstate_set_from_stmt(peerstate, stmt);
success = 1
}
}
sqlite3_finalize(stmt);
success
}
// TODO should return bool /rtn
pub unsafe fn dc_apeerstate_save_to_db(
peerstate: &dc_apeerstate_t,
sql: &dc_sqlite3_t,
create: libc::c_int,
) -> libc::c_int {
let current_block: u64;
let mut success: libc::c_int = 0;
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
if peerstate.addr.is_null() {
return 0;
}
if 0 != create {
stmt = dc_sqlite3_prepare(
peerstate.context,
sql,
b"INSERT INTO acpeerstates (addr) VALUES(?);\x00" as *const u8 as *const libc::c_char,
);
sqlite3_bind_text(stmt, 1, peerstate.addr, -1, None);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
stmt = 0 as *mut sqlite3_stmt
}
if 0 != peerstate.to_save & 0x2 || 0 != create {
stmt =
dc_sqlite3_prepare(
peerstate.context,sql,
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, prefer_encrypted=?, public_key=?, gossip_timestamp=?, gossip_key=?, public_key_fingerprint=?, gossip_key_fingerprint=?, verified_key=?, verified_key_fingerprint=? WHERE addr=?;\x00"
as *const u8 as *const libc::c_char);
sqlite3_bind_int64(stmt, 1, peerstate.last_seen as sqlite3_int64);
sqlite3_bind_int64(stmt, 2, peerstate.last_seen_autocrypt as sqlite3_int64);
sqlite3_bind_int64(stmt, 3, peerstate.prefer_encrypt as sqlite3_int64);
let pub_bytes = peerstate.public_key.as_ref().map(|k| k.to_bytes());
let gossip_bytes = peerstate.gossip_key.as_ref().map(|k| k.to_bytes());
let ver_bytes = peerstate.verified_key.as_ref().map(|k| k.to_bytes());
sqlite3_bind_blob(
stmt,
4,
pub_bytes
.as_ref()
.map(|b| b.as_ptr())
.unwrap_or_else(|| std::ptr::null()) as *const _,
pub_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
None,
);
sqlite3_bind_int64(stmt, 5, peerstate.gossip_timestamp as sqlite3_int64);
sqlite3_bind_blob(
stmt,
6,
gossip_bytes
.as_ref()
.map(|b| b.as_ptr())
.unwrap_or_else(|| std::ptr::null()) as *const _,
gossip_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
None,
);
sqlite3_bind_text(stmt, 7, peerstate.public_key_fingerprint, -1, None);
sqlite3_bind_text(stmt, 8, peerstate.gossip_key_fingerprint, -1, None);
sqlite3_bind_blob(
stmt,
9,
ver_bytes
.as_ref()
.map(|b| b.as_ptr())
.unwrap_or_else(|| std::ptr::null()) as *const _,
ver_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
None,
);
sqlite3_bind_text(stmt, 10, peerstate.verified_key_fingerprint, -1, None);
sqlite3_bind_text(stmt, 11, peerstate.addr, -1, None);
if sqlite3_step(stmt) != 101 {
current_block = 7258450500457619456;
} else {
sqlite3_finalize(stmt);
stmt = 0 as *mut sqlite3_stmt;
current_block = 11913429853522160501;
}
} else if 0 != peerstate.to_save & 0x1 {
stmt =
dc_sqlite3_prepare(
peerstate.context,sql,
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? WHERE addr=?;\x00"
as *const u8 as *const libc::c_char);
sqlite3_bind_int64(stmt, 1, peerstate.last_seen as sqlite3_int64);
sqlite3_bind_int64(stmt, 2, peerstate.last_seen_autocrypt as sqlite3_int64);
sqlite3_bind_int64(stmt, 3, peerstate.gossip_timestamp as sqlite3_int64);
sqlite3_bind_text(stmt, 4, peerstate.addr, -1, None);
if sqlite3_step(stmt) != 101 {
current_block = 7258450500457619456;
} else {
sqlite3_finalize(stmt);
stmt = 0 as *mut sqlite3_stmt;
current_block = 11913429853522160501;
}
} else {
current_block = 11913429853522160501;
}
match current_block {
11913429853522160501 => {
if 0 != peerstate.to_save & 0x2 || 0 != create {
dc_reset_gossiped_timestamp(peerstate.context, 0 as uint32_t);
}
success = 1
}
_ => {}
}
sqlite3_finalize(stmt);
success
}
pub unsafe fn dc_apeerstate_has_verified_key(
peerstate: &dc_apeerstate_t,
fingerprints: *const dc_hash_t,
) -> bool {
if fingerprints.is_null() {
return false;
}
if peerstate.verified_key.is_some()
&& !peerstate.verified_key_fingerprint.is_null()
&& !dc_hash_find(
fingerprints,
peerstate.verified_key_fingerprint as *const libc::c_void,
strlen(peerstate.verified_key_fingerprint) as libc::c_int,
)
.is_null()
{
return true;
}
false
}

View File

@@ -1,5 +1,5 @@
use crate::constants::Event;
use crate::dc_apeerstate::*;
use crate::dc_aheader::EncryptPreference;
use crate::dc_array::*;
use crate::dc_context::dc_context_t;
use crate::dc_context::*;
@@ -11,6 +11,7 @@ use crate::dc_sqlite3::*;
use crate::dc_stock::*;
use crate::dc_strbuilder::*;
use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*;
use crate::x::*;
@@ -769,7 +770,6 @@ pub unsafe fn dc_get_contact_encrinfo(
let mut ret: dc_strbuilder_t;
let loginparam: *mut dc_loginparam_t = dc_loginparam_new();
let contact: *mut dc_contact_t = dc_contact_new(context);
let mut peerstate = dc_apeerstate_new(context);
let mut fingerprint_self: *mut libc::c_char = 0 as *mut libc::c_char;
let mut fingerprint_other_verified: *mut libc::c_char = 0 as *mut libc::c_char;
@@ -784,10 +784,10 @@ pub unsafe fn dc_get_contact_encrinfo(
};
dc_strbuilder_init(&mut ret, 0i32);
if !(!dc_contact_load_from_db(contact, &context.sql.clone().read().unwrap(), contact_id)) {
dc_apeerstate_load_by_addr(
&mut peerstate,
let peerstate = Peerstate::from_addr(
context,
&context.sql.clone().read().unwrap(),
(*contact).addr,
to_str((*contact).addr),
);
dc_loginparam_read(
context,
@@ -800,10 +800,12 @@ pub unsafe fn dc_get_contact_encrinfo(
(*loginparam).addr,
&context.sql.clone().read().unwrap(),
);
if dc_apeerstate_peek_key(&peerstate, 0).is_some() {
if peerstate.is_some() && peerstate.as_ref().and_then(|p| p.peek_key(0)).is_some() {
let peerstate = peerstate.as_ref().unwrap();
p = dc_stock_str(
context,
if peerstate.prefer_encrypt == 1i32 {
if peerstate.prefer_encrypt == EncryptPreference::Mutual {
34i32
} else {
25i32
@@ -828,29 +830,38 @@ pub unsafe fn dc_get_contact_encrinfo(
fingerprint_self = self_key
.map(|k| k.formatted_fingerprint_c())
.unwrap_or(std::ptr::null_mut());
fingerprint_other_verified = dc_apeerstate_peek_key(&peerstate, 2)
fingerprint_other_verified = peerstate
.peek_key(2)
.map(|k| k.formatted_fingerprint_c())
.unwrap_or(std::ptr::null_mut());
fingerprint_other_unverified = dc_apeerstate_peek_key(&peerstate, 0)
fingerprint_other_unverified = peerstate
.peek_key(0)
.map(|k| k.formatted_fingerprint_c())
.unwrap_or(std::ptr::null_mut());
if strcmp((*loginparam).addr, peerstate.addr) < 0i32 {
if peerstate.addr.is_some()
&& to_str((*loginparam).addr) < peerstate.addr.as_ref().unwrap()
{
cat_fingerprint(
&mut ret,
(*loginparam).addr,
fingerprint_self,
0 as *const libc::c_char,
);
let c_addr = to_cstring(peerstate.addr.as_ref().unwrap());
cat_fingerprint(
&mut ret,
peerstate.addr,
c_addr.as_ptr(),
fingerprint_other_verified,
fingerprint_other_unverified,
);
} else {
let c_addr = peerstate.addr.as_ref().map(to_cstring);
cat_fingerprint(
&mut ret,
peerstate.addr,
c_addr
.map(|a| a.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
fingerprint_other_verified,
fingerprint_other_unverified,
);
@@ -874,7 +885,6 @@ pub unsafe fn dc_get_contact_encrinfo(
}
}
dc_apeerstate_unref(&mut peerstate);
dc_contact_unref(contact);
dc_loginparam_unref(loginparam);
@@ -1094,7 +1104,7 @@ pub unsafe fn dc_contact_is_verified(contact: *mut dc_contact_t) -> libc::c_int
/// If you do not have the peerstate available, it is loaded automatically.
pub unsafe fn dc_contact_is_verified_ex<'a>(
contact: *mut dc_contact_t<'a>,
peerstate: Option<&dc_apeerstate_t<'a>>,
peerstate: Option<&Peerstate<'a>>,
) -> libc::c_int {
if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint {
return 0;
@@ -1107,21 +1117,20 @@ pub unsafe fn dc_contact_is_verified_ex<'a>(
}
if let Some(peerstate) = peerstate {
if peerstate.verified_key.is_some() {
if peerstate.verified_key().is_some() {
2
} else {
0
}
} else {
let mut peerstate = dc_apeerstate_new((*contact).context);
let peerstate = Peerstate::from_addr(
(*contact).context,
&(*contact).context.sql.clone().read().unwrap(),
to_str((*contact).addr),
);
let res = if 0
!= dc_apeerstate_load_by_addr(
&mut peerstate,
&(*contact).context.sql.clone().read().unwrap(),
(*contact).addr,
) {
if peerstate.verified_key.is_some() {
let res = if let Some(ps) = peerstate {
if ps.verified_key().is_some() {
2
} else {
0
@@ -1129,7 +1138,6 @@ pub unsafe fn dc_contact_is_verified_ex<'a>(
} else {
0
};
dc_apeerstate_unref(&mut peerstate);
res
}

View File

@@ -15,7 +15,6 @@ use mmime::mmapstring::*;
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
use crate::dc_aheader::*;
use crate::dc_apeerstate::*;
use crate::dc_context::dc_context_t;
use crate::dc_hash::*;
use crate::dc_key::*;
@@ -26,6 +25,7 @@ use crate::dc_pgp::*;
use crate::dc_securejoin::*;
use crate::dc_sqlite3::*;
use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*;
use crate::x::*;
@@ -62,7 +62,7 @@ pub unsafe fn dc_e2ee_encrypt(
let imffields_unprotected: *mut mailimf_fields;
let mut keyring = Keyring::default();
let plain: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
let mut peerstates = Vec::new();
let mut peerstates: Vec<Peerstate> = Vec::new();
if !helper.is_null() {
memset(
helper as *mut libc::c_void,
@@ -113,21 +113,23 @@ pub unsafe fn dc_e2ee_encrypt(
0 as *mut libc::c_void
})
as *const libc::c_char;
let mut peerstate = dc_apeerstate_new(context);
if !(strcasecmp(recipient_addr, addr) == 0i32) {
if 0 != dc_apeerstate_load_by_addr(
&mut peerstate,
if strcasecmp(recipient_addr, addr) != 0 {
let peerstate = Peerstate::from_addr(
context,
&context.sql.clone().read().unwrap(),
recipient_addr,
) && (peerstate.prefer_encrypt == 1i32 || 0 != e2ee_guaranteed)
to_str(recipient_addr),
);
if peerstate.is_some()
&& (peerstate.as_ref().unwrap().prefer_encrypt
== EncryptPreference::Mutual
|| 0 != e2ee_guaranteed)
{
if let Some(key) = dc_apeerstate_peek_key(&peerstate, min_verified)
{
let peerstate = peerstate.unwrap();
if let Some(key) = peerstate.peek_key(min_verified as usize) {
keyring.add_owned(key.clone());
peerstates.push(peerstate);
}
} else {
dc_apeerstate_unref(&mut peerstate);
do_encrypt = 0i32;
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
break;
@@ -183,11 +185,11 @@ pub unsafe fn dc_e2ee_encrypt(
if iCnt > 1i32 {
let mut i: libc::c_int = 0i32;
while i < iCnt {
let p: *mut libc::c_char = dc_apeerstate_render_gossip_header(
&peerstates[i as usize],
min_verified,
);
if !p.is_null() {
let p = peerstates[i as usize]
.render_gossip_header(min_verified as usize);
if p.is_some() {
let header = to_cstring(p.unwrap());
mailimf_fields_add(
imffields_encrypted,
mailimf_field_new_custom(
@@ -195,7 +197,7 @@ pub unsafe fn dc_e2ee_encrypt(
b"Autocrypt-Gossip\x00" as *const u8
as *const libc::c_char,
),
p,
strdup(header.as_ptr()),
),
);
}
@@ -385,10 +387,6 @@ pub unsafe fn dc_e2ee_encrypt(
if !plain.is_null() {
mmap_string_free(plain);
}
for peerstate in peerstates.iter_mut() {
dc_apeerstate_unref(peerstate);
}
}
/*******************************************************************************
@@ -583,8 +581,7 @@ pub unsafe fn dc_e2ee_decrypt(
(to detect parts that could not be decrypted, simply look for left "multipart/encrypted" MIME types */
/*just a pointer into mailmime structure, must not be freed*/
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
let mut message_time: time_t = 0i32 as time_t;
let mut peerstate = dc_apeerstate_new(context);
let mut message_time = 0;
let mut from: *mut libc::c_char = 0 as *mut libc::c_char;
let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
let mut private_keyring = Keyring::default();
@@ -615,33 +612,26 @@ pub unsafe fn dc_e2ee_decrypt(
}
}
}
let mut peerstate = None;
let autocryptheader = Aheader::from_imffields(from, imffields);
if message_time > 0 && !from.is_null() {
if 0 != dc_apeerstate_load_by_addr(
&mut peerstate,
&context.sql.clone().read().unwrap(),
from,
) {
peerstate =
Peerstate::from_addr(context, &context.sql.clone().read().unwrap(), to_str(from));
if let Some(ref mut peerstate) = peerstate {
if let Some(ref header) = autocryptheader {
dc_apeerstate_apply_header(&mut peerstate, header, message_time);
dc_apeerstate_save_to_db(
&mut peerstate,
&context.sql.clone().read().unwrap(),
0i32,
);
} else if message_time > peerstate.last_seen_autocrypt
peerstate.apply_header(&header, message_time as u64);
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
} else if message_time as u64 > peerstate.last_seen_autocrypt
&& 0 == contains_report(in_out_message)
{
dc_apeerstate_degrade_encryption(&mut peerstate, message_time);
dc_apeerstate_save_to_db(
&peerstate,
&context.sql.clone().read().unwrap(),
0i32,
);
peerstate.degrade_encryption(message_time as u64);
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
}
} else if let Some(ref header) = autocryptheader {
dc_apeerstate_init_from_header(&mut peerstate, header, message_time);
dc_apeerstate_save_to_db(&peerstate, &context.sql.clone().read().unwrap(), 1i32);
let p = Peerstate::from_header(context, header, message_time as u64);
p.save_to_db(&context.sql.clone().read().unwrap(), true);
peerstate = Some(p);
}
}
/* load private key for decryption */
@@ -657,21 +647,23 @@ pub unsafe fn dc_e2ee_decrypt(
self_addr,
&context.sql.clone().read().unwrap(),
) {
if peerstate.last_seen == 0 {
dc_apeerstate_load_by_addr(
&mut peerstate,
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
peerstate = Peerstate::from_addr(
&context,
&context.sql.clone().read().unwrap(),
from,
to_str(from),
);
}
if 0 != peerstate.degrade_event {
dc_handle_degrade_event(context, &peerstate);
}
if let Some(ref key) = peerstate.gossip_key {
public_keyring_for_validate.add_ref(key);
}
if let Some(ref key) = peerstate.public_key {
public_keyring_for_validate.add_ref(key);
if let Some(ref peerstate) = peerstate {
if peerstate.degrade_event.is_some() {
dc_handle_degrade_event(context, &peerstate);
}
if let Some(ref key) = peerstate.gossip_key {
public_keyring_for_validate.add_ref(key);
}
if let Some(ref key) = peerstate.public_key {
public_keyring_for_validate.add_ref(key);
}
}
(*helper).signatures = malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
dc_hash_init((*helper).signatures, 3i32, 1i32);
@@ -706,7 +698,6 @@ pub unsafe fn dc_e2ee_decrypt(
mailimf_fields_free(gossip_headers);
}
dc_apeerstate_unref(&mut peerstate);
free(from as *mut libc::c_void);
free(self_addr as *mut libc::c_void);
}
@@ -752,30 +743,25 @@ unsafe fn update_gossip_peerstates(
)
.is_null()
{
let mut peerstate = dc_apeerstate_new(context);
if 0 == dc_apeerstate_load_by_addr(
&mut peerstate,
let mut peerstate = Peerstate::from_addr(
context,
&context.sql.clone().read().unwrap(),
CString::new(header.addr.clone()).unwrap().as_ptr(),
) {
dc_apeerstate_init_from_gossip(&mut peerstate, header, message_time);
dc_apeerstate_save_to_db(
&mut peerstate,
&context.sql.clone().read().unwrap(),
1i32,
);
&header.addr,
);
if let Some(ref mut peerstate) = peerstate {
peerstate.apply_gossip(header, message_time as u64);
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
} else {
dc_apeerstate_apply_gossip(&mut peerstate, header, message_time);
dc_apeerstate_save_to_db(
&mut peerstate,
&context.sql.clone().read().unwrap(),
0i32,
);
let p = Peerstate::from_gossip(context, header, message_time as u64);
p.save_to_db(&context.sql.clone().read().unwrap(), true);
peerstate = Some(p);
}
if 0 != peerstate.degrade_event {
dc_handle_degrade_event(context, &peerstate);
if let Some(peerstate) = peerstate {
if peerstate.degrade_event.is_some() {
dc_handle_degrade_event(context, &peerstate);
}
}
dc_apeerstate_unref(&mut peerstate);
if gossipped_addr.is_null() {
gossipped_addr =
malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;

View File

@@ -9,6 +9,7 @@ use crate::dc_log::*;
use crate::dc_loginparam::*;
use crate::dc_oauth2::dc_get_oauth2_access_token;
use crate::dc_sqlite3::*;
use crate::dc_tools::{to_str, to_string};
use crate::types::*;
pub const DC_IMAP_SEEN: usize = 0x0001;
@@ -1698,14 +1699,6 @@ impl Imap {
}
}
fn to_string(str: *const libc::c_char) -> String {
unsafe { CStr::from_ptr(str).to_str().unwrap().to_string() }
}
fn to_str<'a>(str: *const libc::c_char) -> &'a str {
unsafe { CStr::from_ptr(str).to_str().unwrap() }
}
/// Try to get the folder meaning by the name of the folder only used if the server does not support XLIST.
// TODO: lots languages missing - maybe there is a list somewhere on other MUAs?
// however, if we fail to find out the sent-folder,

View File

@@ -1,4 +1,3 @@
use crate::dc_apeerstate::*;
use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_context::dc_context_t;
@@ -8,6 +7,7 @@ use crate::dc_lot::*;
use crate::dc_param::*;
use crate::dc_strencode::*;
use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*;
use crate::x::*;
@@ -31,7 +31,6 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
let mut name: *mut libc::c_char = 0 as *mut libc::c_char;
let mut invitenumber: *mut libc::c_char = 0 as *mut libc::c_char;
let mut auth: *mut libc::c_char = 0 as *mut libc::c_char;
let mut peerstate = dc_apeerstate_new(context);
let mut qr_parsed: *mut dc_lot_t = dc_lot_new();
let mut chat_id: uint32_t = 0i32 as uint32_t;
let mut device_msg: *mut libc::c_char = 0 as *mut libc::c_char;
@@ -238,17 +237,21 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
16562876845594826114 => {}
_ => {
if !fingerprint.is_null() {
let peerstate = Peerstate::from_fingerprint(
context,
&context.sql.clone().read().unwrap(),
to_str(fingerprint),
);
if addr.is_null() || invitenumber.is_null() || auth.is_null() {
if 0 != dc_apeerstate_load_by_fingerprint(
&mut peerstate,
&context.sql.clone().read().unwrap(),
fingerprint,
) {
if let Some(peerstate) = peerstate {
(*qr_parsed).state = 210i32;
let c_addr = peerstate.addr.as_ref().map(to_cstring);
(*qr_parsed).id = dc_add_or_lookup_contact(
context,
0 as *const libc::c_char,
peerstate.addr,
c_addr
.map(|a| a.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
0x80i32,
0 as *mut libc::c_int,
);
@@ -324,7 +327,6 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
}
free(addr as *mut libc::c_void);
free(fingerprint as *mut libc::c_void);
dc_apeerstate_unref(&mut peerstate);
free(payload as *mut libc::c_void);
free(name as *mut libc::c_void);
free(invitenumber as *mut libc::c_void);
@@ -332,5 +334,6 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
free(device_msg as *mut libc::c_void);
free(grpname as *mut libc::c_void);
free(grpid as *mut libc::c_void);
return qr_parsed;
qr_parsed
}

View File

@@ -7,7 +7,6 @@ use mmime::mmapstring::*;
use mmime::other::*;
use crate::constants::*;
use crate::dc_apeerstate::*;
use crate::dc_array::*;
use crate::dc_chat::*;
use crate::dc_contact::*;
@@ -27,6 +26,7 @@ use crate::dc_stock::*;
use crate::dc_strbuilder::*;
use crate::dc_strencode::*;
use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*;
use crate::x::*;
@@ -1847,10 +1847,9 @@ unsafe fn check_verified_properties(
to_ids: *const dc_array_t,
failure_reason: *mut *mut libc::c_char,
) -> libc::c_int {
let mut current_block: u64;
let mut current_block: u64 = 0;
let mut everythings_okay: libc::c_int = 0i32;
let contact: *mut dc_contact_t = dc_contact_new(context);
let mut peerstate = dc_apeerstate_new(context);
let mut to_ids_str: *mut libc::c_char = 0 as *mut libc::c_char;
let mut q3: *mut libc::c_char = 0 as *mut libc::c_char;
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
@@ -1872,12 +1871,13 @@ unsafe fn check_verified_properties(
// this check is skipped for SELF as there is no proper SELF-peerstate
// and results in group-splits otherwise.
if from_id != 1i32 as libc::c_uint {
if 0 == dc_apeerstate_load_by_addr(
&mut peerstate,
let peerstate = Peerstate::from_addr(
context,
&context.sql.clone().read().unwrap(),
(*contact).addr,
) || dc_contact_is_verified_ex(contact, Some(&peerstate)) != 2i32
{
to_str((*contact).addr),
);
if peerstate.is_none() || dc_contact_is_verified_ex(contact, peerstate.as_ref()) != 2 {
*failure_reason = dc_mprintf(
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char,
b"The sender of this message is not verified.\x00" as *const u8
@@ -1885,17 +1885,16 @@ unsafe fn check_verified_properties(
);
dc_log_warning(context, 0i32, *failure_reason);
current_block = 14837890932895028253;
} else if !dc_apeerstate_has_verified_key(
&peerstate,
(*(*mimeparser).e2ee_helper).signatures,
) {
*failure_reason = dc_mprintf(
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char,
b"The message was sent with non-verified encryption.\x00" as *const u8
as *const libc::c_char,
);
dc_log_warning(context, 0i32, *failure_reason);
current_block = 14837890932895028253;
} else if let Some(peerstate) = peerstate {
if !peerstate.has_verified_key((*(*mimeparser).e2ee_helper).signatures) {
*failure_reason = dc_mprintf(
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char,
b"The message was sent with non-verified encryption.\x00" as *const u8
as *const libc::c_char,
);
dc_log_warning(context, 0i32, *failure_reason);
current_block = 14837890932895028253;
}
} else {
current_block = 15904375183555213903;
}
@@ -1920,27 +1919,26 @@ unsafe fn check_verified_properties(
let to_addr: *const libc::c_char =
sqlite3_column_text(stmt, 0i32) as *const libc::c_char;
let mut is_verified: libc::c_int = sqlite3_column_int(stmt, 1i32);
let mut peerstate = Peerstate::from_addr(
context,
&context.sql.clone().read().unwrap(),
to_str(to_addr),
);
if !dc_hash_find(
(*(*mimeparser).e2ee_helper).gossipped_addr,
to_addr as *const libc::c_void,
strlen(to_addr) as libc::c_int,
)
.is_null()
&& 0 != dc_apeerstate_load_by_addr(
&mut peerstate,
&context.sql.clone().read().unwrap(),
to_addr,
)
&& peerstate.is_some()
{
let peerstate = peerstate.as_mut().unwrap();
if 0 == is_verified
|| strcmp(
peerstate.verified_key_fingerprint,
peerstate.public_key_fingerprint,
) != 0i32
&& strcmp(
peerstate.verified_key_fingerprint,
peerstate.gossip_key_fingerprint,
) != 0i32
|| peerstate.verified_key_fingerprint
!= peerstate.public_key_fingerprint
&& peerstate.verified_key_fingerprint
!= peerstate.gossip_key_fingerprint
{
dc_log_info(
context,
@@ -1949,14 +1947,12 @@ unsafe fn check_verified_properties(
(*contact).addr,
to_addr,
);
let fp = peerstate.gossip_key_fingerprint;
dc_apeerstate_set_verified(&mut peerstate, 0i32, fp, 2i32);
dc_apeerstate_save_to_db(
&mut peerstate,
&context.sql.clone().read().unwrap(),
0i32,
);
is_verified = 1i32
let fp = peerstate.gossip_key_fingerprint.clone();
if let Some(fp) = fp {
peerstate.set_verified(0, &fp, 2);
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
is_verified = 1i32;
}
}
}
if !(0 == is_verified) {
@@ -1985,11 +1981,11 @@ unsafe fn check_verified_properties(
}
sqlite3_finalize(stmt);
dc_contact_unref(contact);
dc_apeerstate_unref(&mut peerstate);
free(to_ids_str as *mut libc::c_void);
sqlite3_free(q3 as *mut libc::c_void);
return everythings_okay;
everythings_okay
}
unsafe fn set_better_msg(mime_parser: *mut dc_mimeparser_t, better_msg: *mut *mut libc::c_char) {
if !(*better_msg).is_null() && carray_count((*mime_parser).parts) > 0i32 as libc::c_uint {
let mut part: *mut dc_mimepart_t =

View File

@@ -1,7 +1,7 @@
use mmime::mailimf_types::*;
use crate::constants::Event;
use crate::dc_apeerstate::*;
use crate::dc_aheader::EncryptPreference;
use crate::dc_array::*;
use crate::dc_chat::*;
use crate::dc_configure::*;
@@ -21,6 +21,7 @@ use crate::dc_stock::*;
use crate::dc_strencode::*;
use crate::dc_token::*;
use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*;
use crate::x::*;
@@ -353,27 +354,28 @@ unsafe fn fingerprint_equals_sender(
let mut fingerprint_equal: libc::c_int = 0i32;
let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id);
let contact: *mut dc_contact_t = dc_contact_new(context);
let mut peerstate = dc_apeerstate_new(context);
let mut fingerprint_normalized: *mut libc::c_char = 0 as *mut libc::c_char;
if !(dc_array_get_cnt(contacts) != 1) {
let peerstate = Peerstate::from_addr(
context,
&context.sql.clone().read().unwrap(),
to_str((*contact).addr),
);
if !(!dc_contact_load_from_db(
contact,
&context.sql.clone().read().unwrap(),
dc_array_get_id(contacts, 0i32 as size_t),
) || 0
== dc_apeerstate_load_by_addr(
&mut peerstate,
&context.sql.clone().read().unwrap(),
(*contact).addr,
))
) || peerstate.is_some())
{
fingerprint_normalized = dc_normalize_fingerprint_c(fingerprint);
if strcasecmp(fingerprint_normalized, peerstate.public_key_fingerprint) == 0i32 {
fingerprint_equal = 1i32
let peerstate = peerstate.as_ref().unwrap();
let fingerprint_normalized = dc_normalize_fingerprint(to_str(fingerprint));
if peerstate.public_key_fingerprint.is_some()
&& &fingerprint_normalized == peerstate.public_key_fingerprint.as_ref().unwrap()
{
fingerprint_equal = 1;
}
}
}
free(fingerprint_normalized as *mut libc::c_void);
dc_contact_unref(contact);
dc_array_unref(contacts);
@@ -973,23 +975,20 @@ unsafe fn mark_peer_as_verified(
context: &dc_context_t,
fingerprint: *const libc::c_char,
) -> libc::c_int {
let mut success: libc::c_int = 0i32;
let mut peerstate = dc_apeerstate_new(context);
if !(0
== dc_apeerstate_load_by_fingerprint(
&mut peerstate,
&context.sql.clone().read().unwrap(),
fingerprint,
))
{
if !(0 == dc_apeerstate_set_verified(&mut peerstate, 1i32, fingerprint, 2i32)) {
peerstate.prefer_encrypt = 1i32;
peerstate.to_save |= 0x2i32;
dc_apeerstate_save_to_db(&mut peerstate, &context.sql.clone().read().unwrap(), 0i32);
success = 1i32
let mut success = 0;
if let Some(ref mut peerstate) = Peerstate::from_fingerprint(
context,
&context.sql.clone().read().unwrap(),
to_str(fingerprint),
) {
if peerstate.set_verified(1, to_str(fingerprint), 2) {
peerstate.prefer_encrypt = EncryptPreference::Mutual;
peerstate.to_save = Some(ToSave::All);
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
success = 1;
}
}
dc_apeerstate_unref(&mut peerstate);
success
}
@@ -1047,7 +1046,7 @@ unsafe fn encrypted_and_signed(
1
}
pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: &dc_apeerstate_t) {
pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: &Peerstate) {
let stmt;
let contact_id: uint32_t;
let mut contact_chat_id: uint32_t = 0i32 as uint32_t;
@@ -1057,13 +1056,23 @@ pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: &dc_ape
// together with DC_DE_FINGERPRINT_CHANGED which is logged, the idea is not to bother
// with things they cannot fix, so the user is just kicked from the verified group
// (and he will know this and can fix this)
if 0 != peerstate.degrade_event & 0x2i32 {
if Some(DegradeEvent::FingerprintChanged) == peerstate.degrade_event {
stmt = dc_sqlite3_prepare(
context,
&context.sql.clone().read().unwrap(),
b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char,
);
sqlite3_bind_text(stmt, 1i32, peerstate.addr, -1i32, None);
let c_addr = peerstate.addr.as_ref().map(to_cstring);
sqlite3_bind_text(
stmt,
1i32,
c_addr
.as_ref()
.map(|a| a.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
-1i32,
None,
);
sqlite3_step(stmt);
contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t;
sqlite3_finalize(stmt);
@@ -1075,7 +1084,13 @@ pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: &dc_ape
&mut contact_chat_id,
0 as *mut libc::c_int,
);
let msg: *mut libc::c_char = dc_stock_str_repl_string(context, 37i32, peerstate.addr);
let msg = dc_stock_str_repl_string(
context,
37i32,
c_addr
.map(|a| a.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
);
dc_add_device_msg(context, contact_chat_id, msg);
free(msg as *mut libc::c_void);
(context.cb)(

View File

@@ -1,10 +1,10 @@
use crate::constants::*;
use crate::dc_apeerstate::*;
use crate::dc_context::dc_context_t;
use crate::dc_hash::*;
use crate::dc_log::*;
use crate::dc_param::*;
use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*;
use crate::x::*;
@@ -906,16 +906,14 @@ pub unsafe fn dc_sqlite3_open(
as *const libc::c_char,
);
while sqlite3_step(stmt) == 100 {
let mut peerstate = dc_apeerstate_new(context);
if 0 != dc_apeerstate_load_by_addr(
&mut peerstate,
if let Some(ref mut peerstate) = Peerstate::from_addr(
context,
sql,
sqlite3_column_text(stmt, 0) as *const libc::c_char,
) && 0 != dc_apeerstate_recalc_fingerprint(&mut peerstate)
{
dc_apeerstate_save_to_db(&mut peerstate, sql, 0);
to_str(sqlite3_column_text(stmt, 0) as *const libc::c_char),
) {
peerstate.recalc_fingerprint();
peerstate.save_to_db(sql, false);
}
dc_apeerstate_unref(&mut peerstate);
}
sqlite3_finalize(stmt);
}

View File

@@ -1952,3 +1952,19 @@ mod tests {
}
}
}
pub fn to_cstring<S: AsRef<str>>(s: S) -> std::ffi::CString {
std::ffi::CString::new(s.as_ref()).unwrap()
}
pub fn to_string(s: *const libc::c_char) -> String {
if s.is_null() {
return "".into();
}
unsafe { std::ffi::CStr::from_ptr(s).to_str().unwrap().to_string() }
}
pub fn to_str<'a>(s: *const libc::c_char) -> &'a str {
assert!(!s.is_null(), "cannot be used on null pointers");
unsafe { std::ffi::CStr::from_ptr(s).to_str().unwrap() }
}

View File

@@ -22,9 +22,13 @@ extern crate smallvec;
#[macro_use]
pub mod dc_log;
pub mod dc_aheader;
pub mod peerstate;
pub mod types;
pub mod x;
pub mod dc_apeerstate;
pub mod constants;
pub mod dc_aheader;
pub mod dc_array;
pub mod dc_chat;
pub mod dc_chatlist;
@@ -64,8 +68,5 @@ pub mod dc_strbuilder;
pub mod dc_strencode;
pub mod dc_token;
pub mod dc_tools;
pub mod types;
pub mod x;
pub mod constants;
pub use self::constants::*;

564
src/peerstate.rs Normal file
View File

@@ -0,0 +1,564 @@
use std::ffi::CString;
use num_traits::FromPrimitive;
use crate::constants::*;
use crate::dc_aheader::*;
use crate::dc_chat::*;
use crate::dc_context::dc_context_t;
use crate::dc_hash::*;
use crate::dc_key::*;
use crate::dc_sqlite3::*;
use crate::dc_tools::{to_cstring, to_string};
use crate::types::*;
use crate::x::*;
/// Peerstate represents the state of an Autocrypt peer.
pub struct Peerstate<'a> {
pub context: &'a dc_context_t,
pub addr: Option<String>,
pub last_seen: u64,
pub last_seen_autocrypt: u64,
pub prefer_encrypt: EncryptPreference,
pub public_key: Option<Key>,
pub public_key_fingerprint: Option<String>,
pub gossip_key: Option<Key>,
pub gossip_timestamp: u64,
pub gossip_key_fingerprint: Option<String>,
verified_key: VerifiedKey,
pub verified_key_fingerprint: Option<String>,
pub to_save: Option<ToSave>,
pub degrade_event: Option<DegradeEvent>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
#[repr(u8)]
pub enum ToSave {
Timestamps = 0x01,
All = 0x02,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
#[repr(u8)]
pub enum DegradeEvent {
/// Recoverable by an incoming encrypted mail.
EncryptionPaused = 0x01,
/// Recoverable by a new verify.
FingerprintChanged = 0x02,
}
#[derive(Debug, Copy, Clone)]
pub enum VerifiedKey {
Gossip,
Public,
None,
}
impl Default for VerifiedKey {
fn default() -> Self {
VerifiedKey::None
}
}
impl VerifiedKey {
pub fn is_none(&self) -> bool {
match self {
VerifiedKey::None => true,
_ => false,
}
}
pub fn is_some(&self) -> bool {
!self.is_none()
}
}
impl<'a> Peerstate<'a> {
pub fn new(context: &'a dc_context_t) -> Self {
Peerstate {
context,
addr: None,
last_seen: 0,
last_seen_autocrypt: 0,
prefer_encrypt: Default::default(),
public_key: None,
public_key_fingerprint: None,
gossip_key: None,
gossip_key_fingerprint: None,
gossip_timestamp: 0,
verified_key: Default::default(),
verified_key_fingerprint: None,
to_save: None,
degrade_event: None,
}
}
pub fn verified_key(&self) -> Option<&Key> {
match self.verified_key {
VerifiedKey::Public => self.public_key.as_ref(),
VerifiedKey::Gossip => self.gossip_key.as_ref(),
VerifiedKey::None => None,
}
}
pub fn from_header(context: &'a dc_context_t, header: &Aheader, message_time: u64) -> Self {
let mut res = Self::new(context);
res.addr = Some(header.addr.clone());
res.last_seen = message_time;
res.last_seen_autocrypt = message_time;
res.to_save = Some(ToSave::All);
res.prefer_encrypt = header.prefer_encrypt;
res.public_key = Some(header.public_key.clone());
res.recalc_fingerprint();
res
}
pub fn from_gossip(
context: &'a dc_context_t,
gossip_header: &Aheader,
message_time: u64,
) -> Self {
let mut res = Self::new(context);
res.addr = Some(gossip_header.addr.clone());
res.gossip_timestamp = message_time;
res.to_save = Some(ToSave::All);
res.gossip_key = Some(gossip_header.public_key.clone());
res.recalc_fingerprint();
res
}
pub fn from_addr(context: &'a dc_context_t, sql: &dc_sqlite3_t, addr: &str) -> Option<Self> {
let mut res = None;
let stmt = unsafe {
dc_sqlite3_prepare(
context,
sql,
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;\x00"
as *const u8 as *const libc::c_char)
};
let addr_c = CString::new(addr.as_bytes()).unwrap();
unsafe { sqlite3_bind_text(stmt, 1, addr_c.as_ptr(), -1, None) };
if unsafe { sqlite3_step(stmt) } == 100 {
res = Some(Self::from_stmt(context, stmt));
}
unsafe { sqlite3_finalize(stmt) };
res
}
pub fn from_fingerprint(
context: &'a dc_context_t,
sql: &dc_sqlite3_t,
fingerprint: &str,
) -> Option<Self> {
let mut res = None;
let stmt = unsafe {
dc_sqlite3_prepare(
context,
sql,
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE public_key_fingerprint=? COLLATE NOCASE OR gossip_key_fingerprint=? COLLATE NOCASE ORDER BY public_key_fingerprint=? DESC;\x00"
as *const u8 as *const libc::c_char)
};
let fp_c = CString::new(fingerprint.as_bytes()).unwrap();
unsafe {
sqlite3_bind_text(stmt, 1, fp_c.as_ptr(), -1, None);
sqlite3_bind_text(stmt, 2, fp_c.as_ptr(), -1, None);
sqlite3_bind_text(stmt, 3, fp_c.as_ptr(), -1, None);
}
if unsafe { sqlite3_step(stmt) == 100 } {
res = Some(Self::from_stmt(context, stmt));
}
unsafe { sqlite3_finalize(stmt) };
res
}
fn from_stmt(context: &'a dc_context_t, stmt: *mut sqlite3_stmt) -> Self {
let mut res = Self::new(context);
res.addr = Some(to_string(unsafe {
sqlite3_column_text(stmt, 0) as *const _
}));
res.last_seen = unsafe { sqlite3_column_int64(stmt, 1) } as u64;
res.last_seen_autocrypt = unsafe { sqlite3_column_int64(stmt, 2) } as u64;
res.prefer_encrypt =
EncryptPreference::from_i32(unsafe { sqlite3_column_int(stmt, 3) }).unwrap_or_default();
res.gossip_timestamp = unsafe { sqlite3_column_int(stmt, 5) } as u64;
res.public_key_fingerprint = Some(to_string(unsafe {
sqlite3_column_text(stmt, 7) as *const _
}));
res.gossip_key_fingerprint = Some(to_string(unsafe {
sqlite3_column_text(stmt, 8) as *const _
}));
res.verified_key_fingerprint = Some(to_string(unsafe {
sqlite3_column_text(stmt, 10) as *const _
}));
if unsafe { sqlite3_column_type(stmt, 4) } != 5 {
res.public_key = Key::from_stmt(stmt, 4, KeyType::Public);
}
if unsafe { sqlite3_column_type(stmt, 6) } != 5 {
res.gossip_key = Key::from_stmt(stmt, 6, KeyType::Public);
}
if unsafe { sqlite3_column_type(stmt, 9) } != 5 {
let vk = Key::from_stmt(stmt, 9, KeyType::Public);
res.verified_key = if vk == res.gossip_key {
VerifiedKey::Gossip
} else if vk == res.public_key {
VerifiedKey::Public
} else {
VerifiedKey::None
};
}
res
}
pub fn recalc_fingerprint(&mut self) {
if let Some(ref public_key) = self.public_key {
let old_public_fingerprint = self.public_key_fingerprint.take();
self.public_key_fingerprint = Some(public_key.fingerprint());
if old_public_fingerprint.is_none()
|| self.public_key_fingerprint.is_none()
|| old_public_fingerprint != self.public_key_fingerprint
{
self.to_save = Some(ToSave::All);
if old_public_fingerprint.is_some() {
self.degrade_event = Some(DegradeEvent::FingerprintChanged);
}
}
}
if let Some(ref gossip_key) = self.gossip_key {
let old_gossip_fingerprint = self.gossip_key_fingerprint.take();
self.gossip_key_fingerprint = Some(gossip_key.fingerprint());
if old_gossip_fingerprint.is_none()
|| self.gossip_key_fingerprint.is_none()
|| old_gossip_fingerprint != self.gossip_key_fingerprint
{
self.to_save = Some(ToSave::All);
if old_gossip_fingerprint.is_some() {
self.degrade_event = Some(DegradeEvent::FingerprintChanged);
}
}
}
}
pub fn degrade_encryption(&mut self, message_time: u64) {
if self.prefer_encrypt == EncryptPreference::Mutual {
self.degrade_event = Some(DegradeEvent::EncryptionPaused);
}
self.prefer_encrypt = EncryptPreference::Reset;
self.last_seen = message_time;
self.to_save = Some(ToSave::All);
}
pub fn apply_header(&mut self, header: &Aheader, message_time: u64) {
if self.addr.is_none()
|| self.addr.as_ref().unwrap().to_lowercase() != header.addr.to_lowercase()
{
return;
}
if message_time > self.last_seen_autocrypt {
self.last_seen = message_time;
self.last_seen_autocrypt = message_time;
self.to_save = Some(ToSave::Timestamps);
if (header.prefer_encrypt == EncryptPreference::Mutual
|| header.prefer_encrypt == EncryptPreference::NoPreference)
&& header.prefer_encrypt != self.prefer_encrypt
{
if self.prefer_encrypt == EncryptPreference::Mutual
&& header.prefer_encrypt != EncryptPreference::Mutual
{
self.degrade_event = Some(DegradeEvent::EncryptionPaused);
}
self.prefer_encrypt = header.prefer_encrypt;
self.to_save = Some(ToSave::All)
}
if self.public_key.as_ref() != Some(&header.public_key) {
self.public_key = Some(header.public_key.clone());
self.recalc_fingerprint();
self.to_save = Some(ToSave::All);
}
}
}
pub fn apply_gossip(&mut self, gossip_header: &Aheader, message_time: u64) {
if self.addr.is_none()
|| self.addr.as_ref().unwrap().to_lowercase() != gossip_header.addr.to_lowercase()
{
return;
}
if message_time > self.gossip_timestamp {
self.gossip_timestamp = message_time;
self.to_save = Some(ToSave::Timestamps);
if self.gossip_key.as_ref() != Some(&gossip_header.public_key) {
self.gossip_key = Some(gossip_header.public_key.clone());
self.recalc_fingerprint();
self.to_save = Some(ToSave::All)
}
};
}
pub fn render_gossip_header(&self, min_verified: usize) -> Option<String> {
if let Some(ref addr) = self.addr {
if let Some(key) = self.peek_key(min_verified) {
// TODO: avoid cloning
let header = Aheader::new(
addr.to_string(),
key.clone(),
EncryptPreference::NoPreference,
);
return Some(header.to_string());
}
}
None
}
pub fn peek_key(&self, min_verified: usize) -> Option<&Key> {
if self.public_key.is_none() && self.gossip_key.is_none() && self.verified_key.is_none() {
return None;
}
if 0 != min_verified {
return self.verified_key();
}
if self.public_key.is_some() {
return self.public_key.as_ref();
}
self.gossip_key.as_ref()
}
pub fn set_verified(&mut self, which_key: usize, fingerprint: &str, verified: usize) -> bool {
let mut success = false;
if !(which_key != 0 && which_key != 1 || verified != 2) {
if which_key == 1
&& self.public_key_fingerprint.is_some()
&& self.public_key_fingerprint.as_ref().unwrap() == fingerprint
{
self.to_save = Some(ToSave::All);
self.verified_key = VerifiedKey::Public;
self.verified_key_fingerprint = self.public_key_fingerprint.clone();
success = true;
}
if which_key == 0
&& self.gossip_key_fingerprint.is_some()
&& self.gossip_key_fingerprint.as_ref().unwrap() == fingerprint
{
self.to_save = Some(ToSave::All);
self.verified_key = VerifiedKey::Gossip;
self.verified_key_fingerprint = self.gossip_key_fingerprint.clone();
success = true;
}
}
success
}
pub fn save_to_db(&self, sql: &dc_sqlite3_t, create: bool) -> bool {
let mut success = false;
if self.addr.is_none() {
return success;
}
if create {
let stmt = unsafe {
dc_sqlite3_prepare(
self.context,
sql,
b"INSERT INTO acpeerstates (addr) VALUES(?);\x00" as *const u8
as *const libc::c_char,
)
};
let addr_c = CString::new(self.addr.as_ref().unwrap().as_bytes()).unwrap();
unsafe {
sqlite3_bind_text(stmt, 1, addr_c.as_ptr(), -1, None);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
}
if self.to_save == Some(ToSave::All) || create {
let stmt = unsafe {
dc_sqlite3_prepare(
self.context,sql,
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, prefer_encrypted=?, public_key=?, gossip_timestamp=?, gossip_key=?, public_key_fingerprint=?, gossip_key_fingerprint=?, verified_key=?, verified_key_fingerprint=? WHERE addr=?;\x00"
as *const u8 as *const libc::c_char)
};
unsafe {
sqlite3_bind_int64(stmt, 1, self.last_seen as sqlite3_int64);
sqlite3_bind_int64(stmt, 2, self.last_seen_autocrypt as sqlite3_int64);
sqlite3_bind_int64(stmt, 3, self.prefer_encrypt as sqlite3_int64);
}
let addr_c = self.addr.as_ref().map(|addr| to_cstring(addr));
let pub_bytes = self.public_key.as_ref().map(|k| k.to_bytes());
let gossip_bytes = self.gossip_key.as_ref().map(|k| k.to_bytes());
let ver_bytes = self.verified_key().map(|k| k.to_bytes());
unsafe {
sqlite3_bind_blob(
stmt,
4,
pub_bytes
.as_ref()
.map(|b| b.as_ptr())
.unwrap_or_else(|| std::ptr::null()) as *const _,
pub_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
None,
);
sqlite3_bind_int64(stmt, 5, self.gossip_timestamp as sqlite3_int64);
sqlite3_bind_blob(
stmt,
6,
gossip_bytes
.as_ref()
.map(|b| b.as_ptr())
.unwrap_or_else(|| std::ptr::null()) as *const _,
gossip_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
None,
);
let pkc = self
.public_key_fingerprint
.as_ref()
.map(|fp| to_cstring(fp));
let gkc = self
.gossip_key_fingerprint
.as_ref()
.map(|fp| to_cstring(fp));
sqlite3_bind_text(
stmt,
7,
pkc.map(|fp| fp.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
-1,
None,
);
sqlite3_bind_text(
stmt,
8,
gkc.map(|fp| fp.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
-1,
None,
);
sqlite3_bind_blob(
stmt,
9,
ver_bytes
.as_ref()
.map(|b| b.as_ptr())
.unwrap_or_else(|| std::ptr::null()) as *const _,
ver_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
None,
);
let vkc = self
.verified_key_fingerprint
.as_ref()
.map(|fp| to_cstring(fp));
sqlite3_bind_text(
stmt,
10,
vkc.map(|fp| fp.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
-1,
None,
);
sqlite3_bind_text(
stmt,
11,
addr_c
.map(|addr| addr.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
-1,
None,
);
}
if unsafe { sqlite3_step(stmt) } == 101 {
success = true;
}
unsafe { sqlite3_finalize(stmt) };
} else if self.to_save == Some(ToSave::Timestamps) {
let stmt = unsafe {
dc_sqlite3_prepare(
self.context,sql,
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? WHERE addr=?;\x00"
as *const u8 as *const libc::c_char)
};
let addr_c = self.addr.as_ref().map(|fp| to_cstring(fp));
unsafe {
sqlite3_bind_int64(stmt, 1, self.last_seen as sqlite3_int64);
sqlite3_bind_int64(stmt, 2, self.last_seen_autocrypt as sqlite3_int64);
sqlite3_bind_int64(stmt, 3, self.gossip_timestamp as sqlite3_int64);
sqlite3_bind_text(
stmt,
4,
addr_c
.map(|addr| addr.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
-1,
None,
);
}
if unsafe { sqlite3_step(stmt) } == 101 {
success = true;
}
unsafe { sqlite3_finalize(stmt) };
}
if self.to_save == Some(ToSave::All) || create {
unsafe { dc_reset_gossiped_timestamp(self.context, 0 as uint32_t) };
}
success
}
pub fn has_verified_key(&self, fingerprints: *const dc_hash_t) -> bool {
if fingerprints.is_null() {
return false;
}
if self.verified_key.is_some() && self.verified_key_fingerprint.is_some() {
let vkc = to_cstring(self.verified_key_fingerprint.as_ref().unwrap());
if !unsafe {
dc_hash_find(
fingerprints,
vkc.as_ptr() as *const libc::c_void,
strlen(vkc.as_ptr()) as libc::c_int,
)
.is_null()
} {
return true;
}
}
false
}
}