mirror of
https://github.com/chatmail/core.git
synced 2026-05-05 14:26:30 +03:00
refactor(peerstate): safe implementation of peerstate
This commit is contained in:
committed by
GitHub
parent
d926b3536d
commit
94aa314f30
@@ -3,7 +3,6 @@ use std::sync::{Arc, RwLock};
|
|||||||
|
|
||||||
use deltachat::constants::*;
|
use deltachat::constants::*;
|
||||||
use deltachat::dc_aheader::*;
|
use deltachat::dc_aheader::*;
|
||||||
use deltachat::dc_apeerstate::*;
|
|
||||||
use deltachat::dc_array::*;
|
use deltachat::dc_array::*;
|
||||||
use deltachat::dc_chat::*;
|
use deltachat::dc_chat::*;
|
||||||
use deltachat::dc_chatlist::*;
|
use deltachat::dc_chatlist::*;
|
||||||
@@ -44,6 +43,7 @@ use deltachat::dc_strbuilder::*;
|
|||||||
use deltachat::dc_strencode::*;
|
use deltachat::dc_strencode::*;
|
||||||
use deltachat::dc_token::*;
|
use deltachat::dc_token::*;
|
||||||
use deltachat::dc_tools::*;
|
use deltachat::dc_tools::*;
|
||||||
|
use deltachat::peerstate::*;
|
||||||
use deltachat::types::*;
|
use deltachat::types::*;
|
||||||
use deltachat::x::*;
|
use deltachat::x::*;
|
||||||
use num_traits::FromPrimitive;
|
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) {
|
unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
|
||||||
let mut contact: *mut dc_contact_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) {
|
if !dc_array_search_id(contacts, 1i32 as uint32_t, 0 as *mut size_t) {
|
||||||
dc_array_add_id(contacts, 1i32 as uint32_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
|
b"addr unset\x00" as *const u8 as *const libc::c_char
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let peerstate_ok: libc::c_int = dc_apeerstate_load_by_addr(
|
let peerstate =
|
||||||
&mut peerstate,
|
Peerstate::from_addr(context, &context.sql.clone().read().unwrap(), to_str(addr));
|
||||||
&context.sql.clone().read().unwrap(),
|
if peerstate.is_some() && contact_id != 1i32 as libc::c_uint {
|
||||||
addr,
|
let pe = to_cstring(format!("{}", peerstate.as_ref().unwrap().prefer_encrypt));
|
||||||
);
|
|
||||||
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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
line2 = dc_mprintf(
|
line2 = dc_mprintf(
|
||||||
b", prefer-encrypt=%s\x00" as *const u8 as *const libc::c_char,
|
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);
|
dc_contact_unref(contact);
|
||||||
free(name as *mut libc::c_void);
|
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
|
i += 1
|
||||||
}
|
}
|
||||||
dc_apeerstate_unref(&mut peerstate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut s_is_auth: libc::c_int = 0i32;
|
static mut s_is_auth: libc::c_int = 0i32;
|
||||||
|
|
||||||
pub unsafe fn dc_cmdline_skip_auth() {
|
pub unsafe fn dc_cmdline_skip_auth() {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ use std::sync::{Arc, RwLock};
|
|||||||
|
|
||||||
use deltachat::constants::*;
|
use deltachat::constants::*;
|
||||||
use deltachat::dc_aheader::*;
|
use deltachat::dc_aheader::*;
|
||||||
use deltachat::dc_apeerstate::*;
|
|
||||||
use deltachat::dc_array::*;
|
use deltachat::dc_array::*;
|
||||||
use deltachat::dc_chat::*;
|
use deltachat::dc_chat::*;
|
||||||
use deltachat::dc_chatlist::*;
|
use deltachat::dc_chatlist::*;
|
||||||
@@ -63,6 +62,7 @@ use deltachat::dc_strbuilder::*;
|
|||||||
use deltachat::dc_strencode::*;
|
use deltachat::dc_strencode::*;
|
||||||
use deltachat::dc_token::*;
|
use deltachat::dc_token::*;
|
||||||
use deltachat::dc_tools::*;
|
use deltachat::dc_tools::*;
|
||||||
|
use deltachat::peerstate::*;
|
||||||
use deltachat::types::*;
|
use deltachat::types::*;
|
||||||
use deltachat::x::*;
|
use deltachat::x::*;
|
||||||
mod cmdline;
|
mod cmdline;
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::constants::Event;
|
use crate::constants::Event;
|
||||||
use crate::dc_apeerstate::*;
|
use crate::dc_aheader::EncryptPreference;
|
||||||
use crate::dc_array::*;
|
use crate::dc_array::*;
|
||||||
use crate::dc_context::dc_context_t;
|
use crate::dc_context::dc_context_t;
|
||||||
use crate::dc_context::*;
|
use crate::dc_context::*;
|
||||||
@@ -11,6 +11,7 @@ use crate::dc_sqlite3::*;
|
|||||||
use crate::dc_stock::*;
|
use crate::dc_stock::*;
|
||||||
use crate::dc_strbuilder::*;
|
use crate::dc_strbuilder::*;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
|
use crate::peerstate::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use crate::x::*;
|
use crate::x::*;
|
||||||
|
|
||||||
@@ -769,7 +770,6 @@ pub unsafe fn dc_get_contact_encrinfo(
|
|||||||
let mut ret: dc_strbuilder_t;
|
let mut ret: dc_strbuilder_t;
|
||||||
let loginparam: *mut dc_loginparam_t = dc_loginparam_new();
|
let loginparam: *mut dc_loginparam_t = dc_loginparam_new();
|
||||||
let contact: *mut dc_contact_t = dc_contact_new(context);
|
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_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;
|
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);
|
dc_strbuilder_init(&mut ret, 0i32);
|
||||||
if !(!dc_contact_load_from_db(contact, &context.sql.clone().read().unwrap(), contact_id)) {
|
if !(!dc_contact_load_from_db(contact, &context.sql.clone().read().unwrap(), contact_id)) {
|
||||||
dc_apeerstate_load_by_addr(
|
let peerstate = Peerstate::from_addr(
|
||||||
&mut peerstate,
|
context,
|
||||||
&context.sql.clone().read().unwrap(),
|
&context.sql.clone().read().unwrap(),
|
||||||
(*contact).addr,
|
to_str((*contact).addr),
|
||||||
);
|
);
|
||||||
dc_loginparam_read(
|
dc_loginparam_read(
|
||||||
context,
|
context,
|
||||||
@@ -800,10 +800,12 @@ pub unsafe fn dc_get_contact_encrinfo(
|
|||||||
(*loginparam).addr,
|
(*loginparam).addr,
|
||||||
&context.sql.clone().read().unwrap(),
|
&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(
|
p = dc_stock_str(
|
||||||
context,
|
context,
|
||||||
if peerstate.prefer_encrypt == 1i32 {
|
if peerstate.prefer_encrypt == EncryptPreference::Mutual {
|
||||||
34i32
|
34i32
|
||||||
} else {
|
} else {
|
||||||
25i32
|
25i32
|
||||||
@@ -828,29 +830,38 @@ pub unsafe fn dc_get_contact_encrinfo(
|
|||||||
fingerprint_self = self_key
|
fingerprint_self = self_key
|
||||||
.map(|k| k.formatted_fingerprint_c())
|
.map(|k| k.formatted_fingerprint_c())
|
||||||
.unwrap_or(std::ptr::null_mut());
|
.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())
|
.map(|k| k.formatted_fingerprint_c())
|
||||||
.unwrap_or(std::ptr::null_mut());
|
.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())
|
.map(|k| k.formatted_fingerprint_c())
|
||||||
.unwrap_or(std::ptr::null_mut());
|
.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(
|
cat_fingerprint(
|
||||||
&mut ret,
|
&mut ret,
|
||||||
(*loginparam).addr,
|
(*loginparam).addr,
|
||||||
fingerprint_self,
|
fingerprint_self,
|
||||||
0 as *const libc::c_char,
|
0 as *const libc::c_char,
|
||||||
);
|
);
|
||||||
|
let c_addr = to_cstring(peerstate.addr.as_ref().unwrap());
|
||||||
cat_fingerprint(
|
cat_fingerprint(
|
||||||
&mut ret,
|
&mut ret,
|
||||||
peerstate.addr,
|
c_addr.as_ptr(),
|
||||||
fingerprint_other_verified,
|
fingerprint_other_verified,
|
||||||
fingerprint_other_unverified,
|
fingerprint_other_unverified,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
let c_addr = peerstate.addr.as_ref().map(to_cstring);
|
||||||
|
|
||||||
cat_fingerprint(
|
cat_fingerprint(
|
||||||
&mut ret,
|
&mut ret,
|
||||||
peerstate.addr,
|
c_addr
|
||||||
|
.map(|a| a.as_ptr())
|
||||||
|
.unwrap_or_else(|| std::ptr::null()),
|
||||||
fingerprint_other_verified,
|
fingerprint_other_verified,
|
||||||
fingerprint_other_unverified,
|
fingerprint_other_unverified,
|
||||||
);
|
);
|
||||||
@@ -874,7 +885,6 @@ pub unsafe fn dc_get_contact_encrinfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dc_apeerstate_unref(&mut peerstate);
|
|
||||||
dc_contact_unref(contact);
|
dc_contact_unref(contact);
|
||||||
dc_loginparam_unref(loginparam);
|
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.
|
/// If you do not have the peerstate available, it is loaded automatically.
|
||||||
pub unsafe fn dc_contact_is_verified_ex<'a>(
|
pub unsafe fn dc_contact_is_verified_ex<'a>(
|
||||||
contact: *mut dc_contact_t<'a>,
|
contact: *mut dc_contact_t<'a>,
|
||||||
peerstate: Option<&dc_apeerstate_t<'a>>,
|
peerstate: Option<&Peerstate<'a>>,
|
||||||
) -> libc::c_int {
|
) -> libc::c_int {
|
||||||
if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint {
|
if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1107,21 +1117,20 @@ pub unsafe fn dc_contact_is_verified_ex<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(peerstate) = peerstate {
|
if let Some(peerstate) = peerstate {
|
||||||
if peerstate.verified_key.is_some() {
|
if peerstate.verified_key().is_some() {
|
||||||
2
|
2
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut peerstate = dc_apeerstate_new((*contact).context);
|
let peerstate = Peerstate::from_addr(
|
||||||
|
(*contact).context,
|
||||||
let res = if 0
|
|
||||||
!= dc_apeerstate_load_by_addr(
|
|
||||||
&mut peerstate,
|
|
||||||
&(*contact).context.sql.clone().read().unwrap(),
|
&(*contact).context.sql.clone().read().unwrap(),
|
||||||
(*contact).addr,
|
to_str((*contact).addr),
|
||||||
) {
|
);
|
||||||
if peerstate.verified_key.is_some() {
|
|
||||||
|
let res = if let Some(ps) = peerstate {
|
||||||
|
if ps.verified_key().is_some() {
|
||||||
2
|
2
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
@@ -1129,7 +1138,6 @@ pub unsafe fn dc_contact_is_verified_ex<'a>(
|
|||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
dc_apeerstate_unref(&mut peerstate);
|
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|||||||
120
src/dc_e2ee.rs
120
src/dc_e2ee.rs
@@ -15,7 +15,6 @@ use mmime::mmapstring::*;
|
|||||||
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
|
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
|
||||||
|
|
||||||
use crate::dc_aheader::*;
|
use crate::dc_aheader::*;
|
||||||
use crate::dc_apeerstate::*;
|
|
||||||
use crate::dc_context::dc_context_t;
|
use crate::dc_context::dc_context_t;
|
||||||
use crate::dc_hash::*;
|
use crate::dc_hash::*;
|
||||||
use crate::dc_key::*;
|
use crate::dc_key::*;
|
||||||
@@ -26,6 +25,7 @@ use crate::dc_pgp::*;
|
|||||||
use crate::dc_securejoin::*;
|
use crate::dc_securejoin::*;
|
||||||
use crate::dc_sqlite3::*;
|
use crate::dc_sqlite3::*;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
|
use crate::peerstate::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use crate::x::*;
|
use crate::x::*;
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
|||||||
let imffields_unprotected: *mut mailimf_fields;
|
let imffields_unprotected: *mut mailimf_fields;
|
||||||
let mut keyring = Keyring::default();
|
let mut keyring = Keyring::default();
|
||||||
let plain: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
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() {
|
if !helper.is_null() {
|
||||||
memset(
|
memset(
|
||||||
helper as *mut libc::c_void,
|
helper as *mut libc::c_void,
|
||||||
@@ -113,21 +113,23 @@ pub unsafe fn dc_e2ee_encrypt(
|
|||||||
0 as *mut libc::c_void
|
0 as *mut libc::c_void
|
||||||
})
|
})
|
||||||
as *const libc::c_char;
|
as *const libc::c_char;
|
||||||
let mut peerstate = dc_apeerstate_new(context);
|
if strcasecmp(recipient_addr, addr) != 0 {
|
||||||
if !(strcasecmp(recipient_addr, addr) == 0i32) {
|
let peerstate = Peerstate::from_addr(
|
||||||
if 0 != dc_apeerstate_load_by_addr(
|
context,
|
||||||
&mut peerstate,
|
|
||||||
&context.sql.clone().read().unwrap(),
|
&context.sql.clone().read().unwrap(),
|
||||||
recipient_addr,
|
to_str(recipient_addr),
|
||||||
) && (peerstate.prefer_encrypt == 1i32 || 0 != e2ee_guaranteed)
|
);
|
||||||
{
|
if peerstate.is_some()
|
||||||
if let Some(key) = dc_apeerstate_peek_key(&peerstate, min_verified)
|
&& (peerstate.as_ref().unwrap().prefer_encrypt
|
||||||
|
== EncryptPreference::Mutual
|
||||||
|
|| 0 != e2ee_guaranteed)
|
||||||
{
|
{
|
||||||
|
let peerstate = peerstate.unwrap();
|
||||||
|
if let Some(key) = peerstate.peek_key(min_verified as usize) {
|
||||||
keyring.add_owned(key.clone());
|
keyring.add_owned(key.clone());
|
||||||
peerstates.push(peerstate);
|
peerstates.push(peerstate);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dc_apeerstate_unref(&mut peerstate);
|
|
||||||
do_encrypt = 0i32;
|
do_encrypt = 0i32;
|
||||||
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
|
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
|
||||||
break;
|
break;
|
||||||
@@ -183,11 +185,11 @@ pub unsafe fn dc_e2ee_encrypt(
|
|||||||
if iCnt > 1i32 {
|
if iCnt > 1i32 {
|
||||||
let mut i: libc::c_int = 0i32;
|
let mut i: libc::c_int = 0i32;
|
||||||
while i < iCnt {
|
while i < iCnt {
|
||||||
let p: *mut libc::c_char = dc_apeerstate_render_gossip_header(
|
let p = peerstates[i as usize]
|
||||||
&peerstates[i as usize],
|
.render_gossip_header(min_verified as usize);
|
||||||
min_verified,
|
|
||||||
);
|
if p.is_some() {
|
||||||
if !p.is_null() {
|
let header = to_cstring(p.unwrap());
|
||||||
mailimf_fields_add(
|
mailimf_fields_add(
|
||||||
imffields_encrypted,
|
imffields_encrypted,
|
||||||
mailimf_field_new_custom(
|
mailimf_field_new_custom(
|
||||||
@@ -195,7 +197,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
|||||||
b"Autocrypt-Gossip\x00" as *const u8
|
b"Autocrypt-Gossip\x00" as *const u8
|
||||||
as *const libc::c_char,
|
as *const libc::c_char,
|
||||||
),
|
),
|
||||||
p,
|
strdup(header.as_ptr()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -385,10 +387,6 @@ pub unsafe fn dc_e2ee_encrypt(
|
|||||||
if !plain.is_null() {
|
if !plain.is_null() {
|
||||||
mmap_string_free(plain);
|
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 */
|
(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*/
|
/*just a pointer into mailmime structure, must not be freed*/
|
||||||
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
|
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
|
||||||
let mut message_time: time_t = 0i32 as time_t;
|
let mut message_time = 0;
|
||||||
let mut peerstate = dc_apeerstate_new(context);
|
|
||||||
let mut from: *mut libc::c_char = 0 as *mut libc::c_char;
|
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 self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||||
let mut private_keyring = Keyring::default();
|
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);
|
let autocryptheader = Aheader::from_imffields(from, imffields);
|
||||||
if message_time > 0 && !from.is_null() {
|
if message_time > 0 && !from.is_null() {
|
||||||
if 0 != dc_apeerstate_load_by_addr(
|
peerstate =
|
||||||
&mut peerstate,
|
Peerstate::from_addr(context, &context.sql.clone().read().unwrap(), to_str(from));
|
||||||
&context.sql.clone().read().unwrap(),
|
|
||||||
from,
|
if let Some(ref mut peerstate) = peerstate {
|
||||||
) {
|
|
||||||
if let Some(ref header) = autocryptheader {
|
if let Some(ref header) = autocryptheader {
|
||||||
dc_apeerstate_apply_header(&mut peerstate, header, message_time);
|
peerstate.apply_header(&header, message_time as u64);
|
||||||
dc_apeerstate_save_to_db(
|
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
|
||||||
&mut peerstate,
|
} else if message_time as u64 > peerstate.last_seen_autocrypt
|
||||||
&context.sql.clone().read().unwrap(),
|
|
||||||
0i32,
|
|
||||||
);
|
|
||||||
} else if message_time > peerstate.last_seen_autocrypt
|
|
||||||
&& 0 == contains_report(in_out_message)
|
&& 0 == contains_report(in_out_message)
|
||||||
{
|
{
|
||||||
dc_apeerstate_degrade_encryption(&mut peerstate, message_time);
|
peerstate.degrade_encryption(message_time as u64);
|
||||||
dc_apeerstate_save_to_db(
|
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
|
||||||
&peerstate,
|
|
||||||
&context.sql.clone().read().unwrap(),
|
|
||||||
0i32,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else if let Some(ref header) = autocryptheader {
|
} else if let Some(ref header) = autocryptheader {
|
||||||
dc_apeerstate_init_from_header(&mut peerstate, header, message_time);
|
let p = Peerstate::from_header(context, header, message_time as u64);
|
||||||
dc_apeerstate_save_to_db(&peerstate, &context.sql.clone().read().unwrap(), 1i32);
|
p.save_to_db(&context.sql.clone().read().unwrap(), true);
|
||||||
|
peerstate = Some(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* load private key for decryption */
|
/* load private key for decryption */
|
||||||
@@ -657,14 +647,15 @@ pub unsafe fn dc_e2ee_decrypt(
|
|||||||
self_addr,
|
self_addr,
|
||||||
&context.sql.clone().read().unwrap(),
|
&context.sql.clone().read().unwrap(),
|
||||||
) {
|
) {
|
||||||
if peerstate.last_seen == 0 {
|
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
|
||||||
dc_apeerstate_load_by_addr(
|
peerstate = Peerstate::from_addr(
|
||||||
&mut peerstate,
|
&context,
|
||||||
&context.sql.clone().read().unwrap(),
|
&context.sql.clone().read().unwrap(),
|
||||||
from,
|
to_str(from),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if 0 != peerstate.degrade_event {
|
if let Some(ref peerstate) = peerstate {
|
||||||
|
if peerstate.degrade_event.is_some() {
|
||||||
dc_handle_degrade_event(context, &peerstate);
|
dc_handle_degrade_event(context, &peerstate);
|
||||||
}
|
}
|
||||||
if let Some(ref key) = peerstate.gossip_key {
|
if let Some(ref key) = peerstate.gossip_key {
|
||||||
@@ -673,6 +664,7 @@ pub unsafe fn dc_e2ee_decrypt(
|
|||||||
if let Some(ref key) = peerstate.public_key {
|
if let Some(ref key) = peerstate.public_key {
|
||||||
public_keyring_for_validate.add_ref(key);
|
public_keyring_for_validate.add_ref(key);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
(*helper).signatures = malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
(*helper).signatures = malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
||||||
dc_hash_init((*helper).signatures, 3i32, 1i32);
|
dc_hash_init((*helper).signatures, 3i32, 1i32);
|
||||||
iterations = 0i32;
|
iterations = 0i32;
|
||||||
@@ -706,7 +698,6 @@ pub unsafe fn dc_e2ee_decrypt(
|
|||||||
mailimf_fields_free(gossip_headers);
|
mailimf_fields_free(gossip_headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
dc_apeerstate_unref(&mut peerstate);
|
|
||||||
free(from as *mut libc::c_void);
|
free(from as *mut libc::c_void);
|
||||||
free(self_addr as *mut libc::c_void);
|
free(self_addr as *mut libc::c_void);
|
||||||
}
|
}
|
||||||
@@ -752,30 +743,25 @@ unsafe fn update_gossip_peerstates(
|
|||||||
)
|
)
|
||||||
.is_null()
|
.is_null()
|
||||||
{
|
{
|
||||||
let mut peerstate = dc_apeerstate_new(context);
|
let mut peerstate = Peerstate::from_addr(
|
||||||
if 0 == dc_apeerstate_load_by_addr(
|
context,
|
||||||
&mut peerstate,
|
|
||||||
&context.sql.clone().read().unwrap(),
|
&context.sql.clone().read().unwrap(),
|
||||||
CString::new(header.addr.clone()).unwrap().as_ptr(),
|
&header.addr,
|
||||||
) {
|
|
||||||
dc_apeerstate_init_from_gossip(&mut peerstate, header, message_time);
|
|
||||||
dc_apeerstate_save_to_db(
|
|
||||||
&mut peerstate,
|
|
||||||
&context.sql.clone().read().unwrap(),
|
|
||||||
1i32,
|
|
||||||
);
|
);
|
||||||
|
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 {
|
} else {
|
||||||
dc_apeerstate_apply_gossip(&mut peerstate, header, message_time);
|
let p = Peerstate::from_gossip(context, header, message_time as u64);
|
||||||
dc_apeerstate_save_to_db(
|
p.save_to_db(&context.sql.clone().read().unwrap(), true);
|
||||||
&mut peerstate,
|
peerstate = Some(p);
|
||||||
&context.sql.clone().read().unwrap(),
|
|
||||||
0i32,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if 0 != peerstate.degrade_event {
|
if let Some(peerstate) = peerstate {
|
||||||
|
if peerstate.degrade_event.is_some() {
|
||||||
dc_handle_degrade_event(context, &peerstate);
|
dc_handle_degrade_event(context, &peerstate);
|
||||||
}
|
}
|
||||||
dc_apeerstate_unref(&mut peerstate);
|
}
|
||||||
|
|
||||||
if gossipped_addr.is_null() {
|
if gossipped_addr.is_null() {
|
||||||
gossipped_addr =
|
gossipped_addr =
|
||||||
malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use crate::dc_log::*;
|
|||||||
use crate::dc_loginparam::*;
|
use crate::dc_loginparam::*;
|
||||||
use crate::dc_oauth2::dc_get_oauth2_access_token;
|
use crate::dc_oauth2::dc_get_oauth2_access_token;
|
||||||
use crate::dc_sqlite3::*;
|
use crate::dc_sqlite3::*;
|
||||||
|
use crate::dc_tools::{to_str, to_string};
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
pub const DC_IMAP_SEEN: usize = 0x0001;
|
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.
|
/// 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?
|
// TODO: lots languages missing - maybe there is a list somewhere on other MUAs?
|
||||||
// however, if we fail to find out the sent-folder,
|
// however, if we fail to find out the sent-folder,
|
||||||
|
|||||||
23
src/dc_qr.rs
23
src/dc_qr.rs
@@ -1,4 +1,3 @@
|
|||||||
use crate::dc_apeerstate::*;
|
|
||||||
use crate::dc_chat::*;
|
use crate::dc_chat::*;
|
||||||
use crate::dc_contact::*;
|
use crate::dc_contact::*;
|
||||||
use crate::dc_context::dc_context_t;
|
use crate::dc_context::dc_context_t;
|
||||||
@@ -8,6 +7,7 @@ use crate::dc_lot::*;
|
|||||||
use crate::dc_param::*;
|
use crate::dc_param::*;
|
||||||
use crate::dc_strencode::*;
|
use crate::dc_strencode::*;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
|
use crate::peerstate::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use crate::x::*;
|
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 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 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 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 qr_parsed: *mut dc_lot_t = dc_lot_new();
|
||||||
let mut chat_id: uint32_t = 0i32 as uint32_t;
|
let mut chat_id: uint32_t = 0i32 as uint32_t;
|
||||||
let mut device_msg: *mut libc::c_char = 0 as *mut libc::c_char;
|
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 => {}
|
16562876845594826114 => {}
|
||||||
_ => {
|
_ => {
|
||||||
if !fingerprint.is_null() {
|
if !fingerprint.is_null() {
|
||||||
if addr.is_null() || invitenumber.is_null() || auth.is_null() {
|
let peerstate = Peerstate::from_fingerprint(
|
||||||
if 0 != dc_apeerstate_load_by_fingerprint(
|
context,
|
||||||
&mut peerstate,
|
|
||||||
&context.sql.clone().read().unwrap(),
|
&context.sql.clone().read().unwrap(),
|
||||||
fingerprint,
|
to_str(fingerprint),
|
||||||
) {
|
);
|
||||||
|
if addr.is_null() || invitenumber.is_null() || auth.is_null() {
|
||||||
|
if let Some(peerstate) = peerstate {
|
||||||
(*qr_parsed).state = 210i32;
|
(*qr_parsed).state = 210i32;
|
||||||
|
let c_addr = peerstate.addr.as_ref().map(to_cstring);
|
||||||
(*qr_parsed).id = dc_add_or_lookup_contact(
|
(*qr_parsed).id = dc_add_or_lookup_contact(
|
||||||
context,
|
context,
|
||||||
0 as *const libc::c_char,
|
0 as *const libc::c_char,
|
||||||
peerstate.addr,
|
c_addr
|
||||||
|
.map(|a| a.as_ptr())
|
||||||
|
.unwrap_or_else(|| std::ptr::null()),
|
||||||
0x80i32,
|
0x80i32,
|
||||||
0 as *mut libc::c_int,
|
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(addr as *mut libc::c_void);
|
||||||
free(fingerprint 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(payload as *mut libc::c_void);
|
||||||
free(name as *mut libc::c_void);
|
free(name as *mut libc::c_void);
|
||||||
free(invitenumber 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(device_msg as *mut libc::c_void);
|
||||||
free(grpname as *mut libc::c_void);
|
free(grpname as *mut libc::c_void);
|
||||||
free(grpid as *mut libc::c_void);
|
free(grpid as *mut libc::c_void);
|
||||||
return qr_parsed;
|
|
||||||
|
qr_parsed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use mmime::mmapstring::*;
|
|||||||
use mmime::other::*;
|
use mmime::other::*;
|
||||||
|
|
||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use crate::dc_apeerstate::*;
|
|
||||||
use crate::dc_array::*;
|
use crate::dc_array::*;
|
||||||
use crate::dc_chat::*;
|
use crate::dc_chat::*;
|
||||||
use crate::dc_contact::*;
|
use crate::dc_contact::*;
|
||||||
@@ -27,6 +26,7 @@ use crate::dc_stock::*;
|
|||||||
use crate::dc_strbuilder::*;
|
use crate::dc_strbuilder::*;
|
||||||
use crate::dc_strencode::*;
|
use crate::dc_strencode::*;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
|
use crate::peerstate::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use crate::x::*;
|
use crate::x::*;
|
||||||
|
|
||||||
@@ -1847,10 +1847,9 @@ unsafe fn check_verified_properties(
|
|||||||
to_ids: *const dc_array_t,
|
to_ids: *const dc_array_t,
|
||||||
failure_reason: *mut *mut libc::c_char,
|
failure_reason: *mut *mut libc::c_char,
|
||||||
) -> libc::c_int {
|
) -> libc::c_int {
|
||||||
let mut current_block: u64;
|
let mut current_block: u64 = 0;
|
||||||
let mut everythings_okay: libc::c_int = 0i32;
|
let mut everythings_okay: libc::c_int = 0i32;
|
||||||
let contact: *mut dc_contact_t = dc_contact_new(context);
|
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 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 q3: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
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
|
// this check is skipped for SELF as there is no proper SELF-peerstate
|
||||||
// and results in group-splits otherwise.
|
// and results in group-splits otherwise.
|
||||||
if from_id != 1i32 as libc::c_uint {
|
if from_id != 1i32 as libc::c_uint {
|
||||||
if 0 == dc_apeerstate_load_by_addr(
|
let peerstate = Peerstate::from_addr(
|
||||||
&mut peerstate,
|
context,
|
||||||
&context.sql.clone().read().unwrap(),
|
&context.sql.clone().read().unwrap(),
|
||||||
(*contact).addr,
|
to_str((*contact).addr),
|
||||||
) || dc_contact_is_verified_ex(contact, Some(&peerstate)) != 2i32
|
);
|
||||||
{
|
|
||||||
|
if peerstate.is_none() || dc_contact_is_verified_ex(contact, peerstate.as_ref()) != 2 {
|
||||||
*failure_reason = dc_mprintf(
|
*failure_reason = dc_mprintf(
|
||||||
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char,
|
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
|
b"The sender of this message is not verified.\x00" as *const u8
|
||||||
@@ -1885,10 +1885,8 @@ unsafe fn check_verified_properties(
|
|||||||
);
|
);
|
||||||
dc_log_warning(context, 0i32, *failure_reason);
|
dc_log_warning(context, 0i32, *failure_reason);
|
||||||
current_block = 14837890932895028253;
|
current_block = 14837890932895028253;
|
||||||
} else if !dc_apeerstate_has_verified_key(
|
} else if let Some(peerstate) = peerstate {
|
||||||
&peerstate,
|
if !peerstate.has_verified_key((*(*mimeparser).e2ee_helper).signatures) {
|
||||||
(*(*mimeparser).e2ee_helper).signatures,
|
|
||||||
) {
|
|
||||||
*failure_reason = dc_mprintf(
|
*failure_reason = dc_mprintf(
|
||||||
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char,
|
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
|
b"The message was sent with non-verified encryption.\x00" as *const u8
|
||||||
@@ -1896,6 +1894,7 @@ unsafe fn check_verified_properties(
|
|||||||
);
|
);
|
||||||
dc_log_warning(context, 0i32, *failure_reason);
|
dc_log_warning(context, 0i32, *failure_reason);
|
||||||
current_block = 14837890932895028253;
|
current_block = 14837890932895028253;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
current_block = 15904375183555213903;
|
current_block = 15904375183555213903;
|
||||||
}
|
}
|
||||||
@@ -1920,27 +1919,26 @@ unsafe fn check_verified_properties(
|
|||||||
let to_addr: *const libc::c_char =
|
let to_addr: *const libc::c_char =
|
||||||
sqlite3_column_text(stmt, 0i32) as *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 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(
|
if !dc_hash_find(
|
||||||
(*(*mimeparser).e2ee_helper).gossipped_addr,
|
(*(*mimeparser).e2ee_helper).gossipped_addr,
|
||||||
to_addr as *const libc::c_void,
|
to_addr as *const libc::c_void,
|
||||||
strlen(to_addr) as libc::c_int,
|
strlen(to_addr) as libc::c_int,
|
||||||
)
|
)
|
||||||
.is_null()
|
.is_null()
|
||||||
&& 0 != dc_apeerstate_load_by_addr(
|
&& peerstate.is_some()
|
||||||
&mut peerstate,
|
|
||||||
&context.sql.clone().read().unwrap(),
|
|
||||||
to_addr,
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
let peerstate = peerstate.as_mut().unwrap();
|
||||||
if 0 == is_verified
|
if 0 == is_verified
|
||||||
|| strcmp(
|
|| peerstate.verified_key_fingerprint
|
||||||
peerstate.verified_key_fingerprint,
|
!= peerstate.public_key_fingerprint
|
||||||
peerstate.public_key_fingerprint,
|
&& peerstate.verified_key_fingerprint
|
||||||
) != 0i32
|
!= peerstate.gossip_key_fingerprint
|
||||||
&& strcmp(
|
|
||||||
peerstate.verified_key_fingerprint,
|
|
||||||
peerstate.gossip_key_fingerprint,
|
|
||||||
) != 0i32
|
|
||||||
{
|
{
|
||||||
dc_log_info(
|
dc_log_info(
|
||||||
context,
|
context,
|
||||||
@@ -1949,14 +1947,12 @@ unsafe fn check_verified_properties(
|
|||||||
(*contact).addr,
|
(*contact).addr,
|
||||||
to_addr,
|
to_addr,
|
||||||
);
|
);
|
||||||
let fp = peerstate.gossip_key_fingerprint;
|
let fp = peerstate.gossip_key_fingerprint.clone();
|
||||||
dc_apeerstate_set_verified(&mut peerstate, 0i32, fp, 2i32);
|
if let Some(fp) = fp {
|
||||||
dc_apeerstate_save_to_db(
|
peerstate.set_verified(0, &fp, 2);
|
||||||
&mut peerstate,
|
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
|
||||||
&context.sql.clone().read().unwrap(),
|
is_verified = 1i32;
|
||||||
0i32,
|
}
|
||||||
);
|
|
||||||
is_verified = 1i32
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !(0 == is_verified) {
|
if !(0 == is_verified) {
|
||||||
@@ -1985,11 +1981,11 @@ unsafe fn check_verified_properties(
|
|||||||
}
|
}
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
dc_contact_unref(contact);
|
dc_contact_unref(contact);
|
||||||
dc_apeerstate_unref(&mut peerstate);
|
|
||||||
free(to_ids_str as *mut libc::c_void);
|
free(to_ids_str as *mut libc::c_void);
|
||||||
sqlite3_free(q3 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) {
|
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 {
|
if !(*better_msg).is_null() && carray_count((*mime_parser).parts) > 0i32 as libc::c_uint {
|
||||||
let mut part: *mut dc_mimepart_t =
|
let mut part: *mut dc_mimepart_t =
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use mmime::mailimf_types::*;
|
use mmime::mailimf_types::*;
|
||||||
|
|
||||||
use crate::constants::Event;
|
use crate::constants::Event;
|
||||||
use crate::dc_apeerstate::*;
|
use crate::dc_aheader::EncryptPreference;
|
||||||
use crate::dc_array::*;
|
use crate::dc_array::*;
|
||||||
use crate::dc_chat::*;
|
use crate::dc_chat::*;
|
||||||
use crate::dc_configure::*;
|
use crate::dc_configure::*;
|
||||||
@@ -21,6 +21,7 @@ use crate::dc_stock::*;
|
|||||||
use crate::dc_strencode::*;
|
use crate::dc_strencode::*;
|
||||||
use crate::dc_token::*;
|
use crate::dc_token::*;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
|
use crate::peerstate::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use crate::x::*;
|
use crate::x::*;
|
||||||
|
|
||||||
@@ -353,27 +354,28 @@ unsafe fn fingerprint_equals_sender(
|
|||||||
let mut fingerprint_equal: libc::c_int = 0i32;
|
let mut fingerprint_equal: libc::c_int = 0i32;
|
||||||
let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id);
|
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 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) {
|
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(
|
if !(!dc_contact_load_from_db(
|
||||||
contact,
|
contact,
|
||||||
&context.sql.clone().read().unwrap(),
|
&context.sql.clone().read().unwrap(),
|
||||||
dc_array_get_id(contacts, 0i32 as size_t),
|
dc_array_get_id(contacts, 0i32 as size_t),
|
||||||
) || 0
|
) || peerstate.is_some())
|
||||||
== dc_apeerstate_load_by_addr(
|
|
||||||
&mut peerstate,
|
|
||||||
&context.sql.clone().read().unwrap(),
|
|
||||||
(*contact).addr,
|
|
||||||
))
|
|
||||||
{
|
{
|
||||||
fingerprint_normalized = dc_normalize_fingerprint_c(fingerprint);
|
let peerstate = peerstate.as_ref().unwrap();
|
||||||
if strcasecmp(fingerprint_normalized, peerstate.public_key_fingerprint) == 0i32 {
|
let fingerprint_normalized = dc_normalize_fingerprint(to_str(fingerprint));
|
||||||
fingerprint_equal = 1i32
|
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_contact_unref(contact);
|
||||||
dc_array_unref(contacts);
|
dc_array_unref(contacts);
|
||||||
|
|
||||||
@@ -973,23 +975,20 @@ unsafe fn mark_peer_as_verified(
|
|||||||
context: &dc_context_t,
|
context: &dc_context_t,
|
||||||
fingerprint: *const libc::c_char,
|
fingerprint: *const libc::c_char,
|
||||||
) -> libc::c_int {
|
) -> libc::c_int {
|
||||||
let mut success: libc::c_int = 0i32;
|
let mut success = 0;
|
||||||
let mut peerstate = dc_apeerstate_new(context);
|
|
||||||
if !(0
|
if let Some(ref mut peerstate) = Peerstate::from_fingerprint(
|
||||||
== dc_apeerstate_load_by_fingerprint(
|
context,
|
||||||
&mut peerstate,
|
|
||||||
&context.sql.clone().read().unwrap(),
|
&context.sql.clone().read().unwrap(),
|
||||||
fingerprint,
|
to_str(fingerprint),
|
||||||
))
|
) {
|
||||||
{
|
if peerstate.set_verified(1, to_str(fingerprint), 2) {
|
||||||
if !(0 == dc_apeerstate_set_verified(&mut peerstate, 1i32, fingerprint, 2i32)) {
|
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
||||||
peerstate.prefer_encrypt = 1i32;
|
peerstate.to_save = Some(ToSave::All);
|
||||||
peerstate.to_save |= 0x2i32;
|
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
|
||||||
dc_apeerstate_save_to_db(&mut peerstate, &context.sql.clone().read().unwrap(), 0i32);
|
success = 1;
|
||||||
success = 1i32
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dc_apeerstate_unref(&mut peerstate);
|
|
||||||
|
|
||||||
success
|
success
|
||||||
}
|
}
|
||||||
@@ -1047,7 +1046,7 @@ unsafe fn encrypted_and_signed(
|
|||||||
1
|
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 stmt;
|
||||||
let contact_id: uint32_t;
|
let contact_id: uint32_t;
|
||||||
let mut contact_chat_id: uint32_t = 0i32 as 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
|
// 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
|
// with things they cannot fix, so the user is just kicked from the verified group
|
||||||
// (and he will know this and can fix this)
|
// (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(
|
stmt = dc_sqlite3_prepare(
|
||||||
context,
|
context,
|
||||||
&context.sql.clone().read().unwrap(),
|
&context.sql.clone().read().unwrap(),
|
||||||
b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char,
|
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);
|
sqlite3_step(stmt);
|
||||||
contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t;
|
contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t;
|
||||||
sqlite3_finalize(stmt);
|
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,
|
&mut contact_chat_id,
|
||||||
0 as *mut libc::c_int,
|
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);
|
dc_add_device_msg(context, contact_chat_id, msg);
|
||||||
free(msg as *mut libc::c_void);
|
free(msg as *mut libc::c_void);
|
||||||
(context.cb)(
|
(context.cb)(
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use crate::dc_apeerstate::*;
|
|
||||||
use crate::dc_context::dc_context_t;
|
use crate::dc_context::dc_context_t;
|
||||||
use crate::dc_hash::*;
|
use crate::dc_hash::*;
|
||||||
use crate::dc_log::*;
|
use crate::dc_log::*;
|
||||||
use crate::dc_param::*;
|
use crate::dc_param::*;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
|
use crate::peerstate::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use crate::x::*;
|
use crate::x::*;
|
||||||
|
|
||||||
@@ -906,16 +906,14 @@ pub unsafe fn dc_sqlite3_open(
|
|||||||
as *const libc::c_char,
|
as *const libc::c_char,
|
||||||
);
|
);
|
||||||
while sqlite3_step(stmt) == 100 {
|
while sqlite3_step(stmt) == 100 {
|
||||||
let mut peerstate = dc_apeerstate_new(context);
|
if let Some(ref mut peerstate) = Peerstate::from_addr(
|
||||||
if 0 != dc_apeerstate_load_by_addr(
|
context,
|
||||||
&mut peerstate,
|
|
||||||
sql,
|
sql,
|
||||||
sqlite3_column_text(stmt, 0) as *const libc::c_char,
|
to_str(sqlite3_column_text(stmt, 0) as *const libc::c_char),
|
||||||
) && 0 != dc_apeerstate_recalc_fingerprint(&mut peerstate)
|
) {
|
||||||
{
|
peerstate.recalc_fingerprint();
|
||||||
dc_apeerstate_save_to_db(&mut peerstate, sql, 0);
|
peerstate.save_to_db(sql, false);
|
||||||
}
|
}
|
||||||
dc_apeerstate_unref(&mut peerstate);
|
|
||||||
}
|
}
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() }
|
||||||
|
}
|
||||||
|
|||||||
11
src/lib.rs
11
src/lib.rs
@@ -22,9 +22,13 @@ extern crate smallvec;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod dc_log;
|
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_array;
|
||||||
pub mod dc_chat;
|
pub mod dc_chat;
|
||||||
pub mod dc_chatlist;
|
pub mod dc_chatlist;
|
||||||
@@ -64,8 +68,5 @@ pub mod dc_strbuilder;
|
|||||||
pub mod dc_strencode;
|
pub mod dc_strencode;
|
||||||
pub mod dc_token;
|
pub mod dc_token;
|
||||||
pub mod dc_tools;
|
pub mod dc_tools;
|
||||||
pub mod types;
|
|
||||||
pub mod x;
|
|
||||||
|
|
||||||
pub mod constants;
|
|
||||||
pub use self::constants::*;
|
pub use self::constants::*;
|
||||||
|
|||||||
564
src/peerstate.rs
Normal file
564
src/peerstate.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user