diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index d34a7bdbb..547eb8755 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -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() { diff --git a/examples/repl/main.rs b/examples/repl/main.rs index a9156b066..e36972e58 100644 --- a/examples/repl/main.rs +++ b/examples/repl/main.rs @@ -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; diff --git a/src/dc_apeerstate.rs b/src/dc_apeerstate.rs deleted file mode 100644 index 47d1a33d4..000000000 --- a/src/dc_apeerstate.rs +++ /dev/null @@ -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, - pub public_key_fingerprint: *mut libc::c_char, - pub gossip_key: Option, - 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, - 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 -} diff --git a/src/dc_contact.rs b/src/dc_contact.rs index 9e5b0d25a..55bf4cee7 100644 --- a/src/dc_contact.rs +++ b/src/dc_contact.rs @@ -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 } diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index dd9e412da..c3cc3d26c 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -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 = 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::()) 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::()) as *mut dc_hash_t; diff --git a/src/dc_imap.rs b/src/dc_imap.rs index 640bf8182..fd429de2c 100644 --- a/src/dc_imap.rs +++ b/src/dc_imap.rs @@ -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, diff --git a/src/dc_qr.rs b/src/dc_qr.rs index e9611e560..027fd3b01 100644 --- a/src/dc_qr.rs +++ b/src/dc_qr.rs @@ -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 } diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index d4e203e13..82e1a4ca4 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -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 = diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index 2d10e708b..5063f46b8 100644 --- a/src/dc_securejoin.rs +++ b/src/dc_securejoin.rs @@ -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)( diff --git a/src/dc_sqlite3.rs b/src/dc_sqlite3.rs index c3d7bd153..a21fa5b52 100644 --- a/src/dc_sqlite3.rs +++ b/src/dc_sqlite3.rs @@ -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); } diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 439b9a444..d19220b39 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -1952,3 +1952,19 @@ mod tests { } } } + +pub fn to_cstring>(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() } +} diff --git a/src/lib.rs b/src/lib.rs index b5386f084..c3e25dad8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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::*; diff --git a/src/peerstate.rs b/src/peerstate.rs new file mode 100644 index 000000000..f38979086 --- /dev/null +++ b/src/peerstate.rs @@ -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, + pub last_seen: u64, + pub last_seen_autocrypt: u64, + pub prefer_encrypt: EncryptPreference, + pub public_key: Option, + pub public_key_fingerprint: Option, + pub gossip_key: Option, + pub gossip_timestamp: u64, + pub gossip_key_fingerprint: Option, + verified_key: VerifiedKey, + pub verified_key_fingerprint: Option, + pub to_save: Option, + pub degrade_event: Option, +} + +#[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 { + 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 { + 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 { + 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 + } +}