mirror of
https://github.com/chatmail/core.git
synced 2026-04-27 10:26:29 +03:00
refactor: safe sql access
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::CStr;
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, str};
|
||||
|
||||
@@ -7,6 +7,7 @@ use mmime::mailimf_types::*;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::dc_contact::*;
|
||||
use crate::dc_tools::as_str;
|
||||
use crate::key::*;
|
||||
|
||||
/// Possible values for encryption preference
|
||||
@@ -93,9 +94,7 @@ impl Aheader {
|
||||
|
||||
match Self::from_str(value) {
|
||||
Ok(test) => {
|
||||
// TODO: implement rust-safe version of dc_addr_cmp
|
||||
let addr = CString::new(test.addr.clone()).unwrap();
|
||||
if unsafe { dc_addr_cmp(addr.as_ptr(), wanted_from) } == 0 {
|
||||
if dc_addr_cmp(&test.addr, as_str(wanted_from)) {
|
||||
if fine_header.is_none() {
|
||||
fine_header = Some(test);
|
||||
} else {
|
||||
|
||||
712
src/context.rs
712
src/context.rs
@@ -21,6 +21,49 @@ use crate::smtp::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
const CONFIG_KEYS: [&'static str; 33] = [
|
||||
"addr",
|
||||
"mail_server",
|
||||
"mail_user",
|
||||
"mail_pw",
|
||||
"mail_port",
|
||||
"send_server",
|
||||
"send_user",
|
||||
"send_pw",
|
||||
"send_port",
|
||||
"server_flags",
|
||||
"imap_folder",
|
||||
"displayname",
|
||||
"selfstatus",
|
||||
"selfavatar",
|
||||
"e2ee_enabled",
|
||||
"mdns_enabled",
|
||||
"inbox_watch",
|
||||
"sentbox_watch",
|
||||
"mvbox_watch",
|
||||
"mvbox_move",
|
||||
"show_emails",
|
||||
"save_mime_headers",
|
||||
"configured_addr",
|
||||
"configured_mail_server",
|
||||
"configured_mail_user",
|
||||
"configured_mail_pw",
|
||||
"configured_mail_port",
|
||||
"configured_send_server",
|
||||
"configured_send_user",
|
||||
"configured_send_pw",
|
||||
"configured_send_port",
|
||||
"configured_server_flags",
|
||||
"configured",
|
||||
];
|
||||
|
||||
// deprecated
|
||||
const SYS_CONFIG_KEYS: [&'static str; 3] = [
|
||||
"sys.version",
|
||||
"sys.msgsize_max_recommended",
|
||||
"sys.config_keys",
|
||||
];
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Context {
|
||||
pub userdata: *mut libc::c_void,
|
||||
@@ -186,7 +229,7 @@ unsafe fn cb_receive_imf(
|
||||
context: &Context,
|
||||
imf_raw_not_terminated: *const libc::c_char,
|
||||
imf_raw_bytes: size_t,
|
||||
server_folder: *const libc::c_char,
|
||||
server_folder: &str,
|
||||
server_uid: uint32_t,
|
||||
flags: uint32_t,
|
||||
) {
|
||||
@@ -203,7 +246,7 @@ unsafe fn cb_receive_imf(
|
||||
unsafe fn cb_precheck_imf(
|
||||
context: &Context,
|
||||
rfc724_mid: *const libc::c_char,
|
||||
server_folder: *const libc::c_char,
|
||||
server_folder: &str,
|
||||
server_uid: uint32_t,
|
||||
) -> libc::c_int {
|
||||
let mut rfc724_mid_exists: libc::c_int = 0i32;
|
||||
@@ -229,7 +272,7 @@ unsafe fn cb_precheck_imf(
|
||||
rfc724_mid,
|
||||
);
|
||||
mark_seen = 1i32
|
||||
} else if strcmp(old_server_folder, server_folder) != 0i32 {
|
||||
} else if as_str(old_server_folder) != server_folder {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
@@ -238,7 +281,7 @@ unsafe fn cb_precheck_imf(
|
||||
);
|
||||
dc_update_msg_move_state(context, rfc724_mid, DC_MOVE_STATE_STAY);
|
||||
}
|
||||
if strcmp(old_server_folder, server_folder) != 0i32 || old_server_uid != server_uid {
|
||||
if as_str(old_server_folder) != server_folder || old_server_uid != server_uid {
|
||||
dc_update_server_uid(context, rfc724_mid, server_folder, server_uid);
|
||||
}
|
||||
dc_do_heuristics_moves(context, server_folder, msg_id);
|
||||
@@ -257,7 +300,12 @@ unsafe fn cb_precheck_imf(
|
||||
}
|
||||
|
||||
unsafe fn cb_set_config(context: &Context, key: *const libc::c_char, value: *const libc::c_char) {
|
||||
dc_sqlite3_set_config(context, &context.sql, key, value);
|
||||
let v = if value.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(as_str(value))
|
||||
};
|
||||
dc_sqlite3_set_config(context, &context.sql, as_str(key), v);
|
||||
}
|
||||
|
||||
/* *
|
||||
@@ -272,7 +320,17 @@ unsafe fn cb_get_config(
|
||||
key: *const libc::c_char,
|
||||
def: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
dc_sqlite3_get_config(context, &context.sql, key, def)
|
||||
let d = if def.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(as_str(def))
|
||||
};
|
||||
let res = dc_sqlite3_get_config(context, &context.sql, as_str(key), d);
|
||||
if let Some(res) = res {
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_context_unref(context: &mut Context) {
|
||||
@@ -355,52 +413,48 @@ pub unsafe fn dc_get_blobdir(context: &Context) -> *mut libc::c_char {
|
||||
dc_strdup(*context.blobdir.clone().read().unwrap())
|
||||
}
|
||||
|
||||
pub unsafe fn dc_set_config(
|
||||
context: &Context,
|
||||
key: *const libc::c_char,
|
||||
value: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
pub fn dc_set_config(context: &Context, key: impl AsRef<str>, value: Option<&str>) -> libc::c_int {
|
||||
let mut ret = 0;
|
||||
let mut rel_path = 0 as *mut libc::c_char;
|
||||
|
||||
if key.is_null() || 0 == is_settable_config_key(key) {
|
||||
if !is_settable_config_key(key.as_ref()) {
|
||||
return 0;
|
||||
}
|
||||
if strcmp(key, b"selfavatar\x00" as *const u8 as *const libc::c_char) == 0 && !value.is_null() {
|
||||
rel_path = dc_strdup(value);
|
||||
if !(0 == dc_make_rel_and_copy(context, &mut rel_path)) {
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, rel_path)
|
||||
|
||||
match key.as_ref() {
|
||||
"selfavatar" if value.is_some() => {
|
||||
let mut rel_path = unsafe { dc_strdup(to_cstring(value.unwrap()).as_ptr()) };
|
||||
if 0 != unsafe { dc_make_rel_and_copy(context, &mut rel_path) } {
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, Some(as_str(rel_path)));
|
||||
}
|
||||
unsafe { free(rel_path as *mut libc::c_void) };
|
||||
}
|
||||
} else if strcmp(key, b"inbox_watch\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
|
||||
dc_interrupt_imap_idle(context);
|
||||
} else if strcmp(
|
||||
key,
|
||||
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
{
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
|
||||
dc_interrupt_sentbox_idle(context);
|
||||
} else if strcmp(key, b"mvbox_watch\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
|
||||
dc_interrupt_mvbox_idle(context);
|
||||
} else if strcmp(key, b"selfstatus\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
let def = dc_stock_str(context, 13);
|
||||
ret = dc_sqlite3_set_config(
|
||||
context,
|
||||
&context.sql,
|
||||
key,
|
||||
if value.is_null() || strcmp(value, def) == 0 {
|
||||
0 as *const libc::c_char
|
||||
"inbox_watch" => {
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
|
||||
unsafe { dc_interrupt_imap_idle(context) };
|
||||
}
|
||||
"sentbox_watch" => {
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
|
||||
unsafe { dc_interrupt_sentbox_idle(context) };
|
||||
}
|
||||
"mvbox_watch" => {
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
|
||||
unsafe { dc_interrupt_mvbox_idle(context) };
|
||||
}
|
||||
"selfstatus" => {
|
||||
let def = unsafe { dc_stock_str(context, 13) };
|
||||
let val = if value.is_none() || value.unwrap() == as_str(def) {
|
||||
None
|
||||
} else {
|
||||
value
|
||||
},
|
||||
);
|
||||
free(def as *mut libc::c_void);
|
||||
} else {
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
|
||||
};
|
||||
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, val);
|
||||
unsafe { free(def as *mut libc::c_void) };
|
||||
}
|
||||
_ => {
|
||||
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
|
||||
}
|
||||
}
|
||||
free(rel_path as *mut libc::c_void);
|
||||
ret
|
||||
}
|
||||
|
||||
@@ -408,303 +462,136 @@ pub unsafe fn dc_set_config(
|
||||
* INI-handling, Information
|
||||
******************************************************************************/
|
||||
|
||||
unsafe fn is_settable_config_key(key: *const libc::c_char) -> libc::c_int {
|
||||
let mut i = 0;
|
||||
while i
|
||||
< (::std::mem::size_of::<[*const libc::c_char; 33]>())
|
||||
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>())
|
||||
{
|
||||
if strcmp(key, config_keys[i as usize]) == 0 {
|
||||
return 1;
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
0
|
||||
fn is_settable_config_key(key: impl AsRef<str>) -> bool {
|
||||
CONFIG_KEYS
|
||||
.into_iter()
|
||||
.find(|c| **c == key.as_ref())
|
||||
.is_some()
|
||||
}
|
||||
|
||||
static mut config_keys: [*const libc::c_char; 33] = [
|
||||
b"addr\x00" as *const u8 as *const libc::c_char,
|
||||
b"mail_server\x00" as *const u8 as *const libc::c_char,
|
||||
b"mail_user\x00" as *const u8 as *const libc::c_char,
|
||||
b"mail_pw\x00" as *const u8 as *const libc::c_char,
|
||||
b"mail_port\x00" as *const u8 as *const libc::c_char,
|
||||
b"send_server\x00" as *const u8 as *const libc::c_char,
|
||||
b"send_user\x00" as *const u8 as *const libc::c_char,
|
||||
b"send_pw\x00" as *const u8 as *const libc::c_char,
|
||||
b"send_port\x00" as *const u8 as *const libc::c_char,
|
||||
b"server_flags\x00" as *const u8 as *const libc::c_char,
|
||||
b"imap_folder\x00" as *const u8 as *const libc::c_char,
|
||||
b"displayname\x00" as *const u8 as *const libc::c_char,
|
||||
b"selfstatus\x00" as *const u8 as *const libc::c_char,
|
||||
b"selfavatar\x00" as *const u8 as *const libc::c_char,
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
b"mdns_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
b"inbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
b"mvbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
b"mvbox_move\x00" as *const u8 as *const libc::c_char,
|
||||
b"show_emails\x00" as *const u8 as *const libc::c_char,
|
||||
b"save_mime_headers\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured_mail_server\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured_mail_user\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured_mail_pw\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured_mail_port\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured_send_server\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured_send_user\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured_send_pw\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured_send_port\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured_server_flags\x00" as *const u8 as *const libc::c_char,
|
||||
b"configured\x00" as *const u8 as *const libc::c_char,
|
||||
];
|
||||
|
||||
pub unsafe fn dc_get_config(context: &Context, key: *const libc::c_char) -> *mut libc::c_char {
|
||||
let mut value = 0 as *mut libc::c_char;
|
||||
if !key.is_null()
|
||||
&& *key.offset(0isize) as libc::c_int == 's' as i32
|
||||
&& *key.offset(1isize) as libc::c_int == 'y' as i32
|
||||
&& *key.offset(2isize) as libc::c_int == 's' as i32
|
||||
&& *key.offset(3isize) as libc::c_int == '.' as i32
|
||||
{
|
||||
return get_sys_config_str(key);
|
||||
pub fn dc_get_config(context: &Context, key: impl AsRef<str>) -> String {
|
||||
if key.as_ref().starts_with("sys") {
|
||||
return get_sys_config_str(key.as_ref());
|
||||
}
|
||||
|
||||
if key.is_null() || 0 == is_gettable_config_key(key) {
|
||||
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
|
||||
if !is_gettable_config_key(key.as_ref()) {
|
||||
return "".into();
|
||||
}
|
||||
|
||||
if strcmp(key, b"selfavatar\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
let rel_path: *mut libc::c_char =
|
||||
dc_sqlite3_get_config(context, &context.sql, key, 0 as *const libc::c_char);
|
||||
if !rel_path.is_null() {
|
||||
value = dc_get_abs_path(context, rel_path);
|
||||
free(rel_path as *mut libc::c_void);
|
||||
let value = match key.as_ref() {
|
||||
"selfavatar" => {
|
||||
let rel_path = dc_sqlite3_get_config(context, &context.sql, key.as_ref(), None);
|
||||
rel_path.map(|p| {
|
||||
let v = unsafe { dc_get_abs_path(context, to_cstring(p).as_ptr()) };
|
||||
let r = to_string(v);
|
||||
unsafe { free(v as *mut _) };
|
||||
r
|
||||
})
|
||||
}
|
||||
} else {
|
||||
value = dc_sqlite3_get_config(context, &context.sql, key, 0 as *const libc::c_char)
|
||||
}
|
||||
|
||||
if value.is_null() {
|
||||
if strcmp(key, b"e2ee_enabled\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
|
||||
} else if strcmp(key, b"mdns_enabled\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
|
||||
} else if strcmp(key, b"imap_folder\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
value = dc_strdup(b"INBOX\x00" as *const u8 as *const libc::c_char)
|
||||
} else if strcmp(key, b"inbox_watch\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
|
||||
} else if strcmp(
|
||||
key,
|
||||
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
{
|
||||
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
|
||||
} else if strcmp(key, b"mvbox_watch\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
|
||||
} else if strcmp(key, b"mvbox_move\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
|
||||
} else if strcmp(key, b"show_emails\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 0)
|
||||
} else if strcmp(key, b"selfstatus\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
value = dc_stock_str(context, 13)
|
||||
} else {
|
||||
value = dc_mprintf(b"\x00" as *const u8 as *const libc::c_char)
|
||||
}
|
||||
}
|
||||
|
||||
value
|
||||
}
|
||||
|
||||
unsafe fn is_gettable_config_key(key: *const libc::c_char) -> libc::c_int {
|
||||
let mut i = 0;
|
||||
while i
|
||||
< (::std::mem::size_of::<[*const libc::c_char; 3]>())
|
||||
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>())
|
||||
{
|
||||
if strcmp(key, sys_config_keys[i as usize]) == 0 {
|
||||
return 1;
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
|
||||
is_settable_config_key(key)
|
||||
}
|
||||
|
||||
// deprecated
|
||||
static mut sys_config_keys: [*const libc::c_char; 3] = [
|
||||
b"sys.version\x00" as *const u8 as *const libc::c_char,
|
||||
b"sys.msgsize_max_recommended\x00" as *const u8 as *const libc::c_char,
|
||||
b"sys.config_keys\x00" as *const u8 as *const libc::c_char,
|
||||
];
|
||||
|
||||
unsafe fn get_sys_config_str(key: *const libc::c_char) -> *mut libc::c_char {
|
||||
if strcmp(key, b"sys.version\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
return dc_strdup(DC_VERSION_STR as *const u8 as *const libc::c_char);
|
||||
} else if strcmp(
|
||||
key,
|
||||
b"sys.msgsize_max_recommended\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
{
|
||||
return dc_mprintf(
|
||||
b"%i\x00" as *const u8 as *const libc::c_char,
|
||||
24 * 1024 * 1024 / 4 * 3,
|
||||
);
|
||||
} else if strcmp(
|
||||
key,
|
||||
b"sys.config_keys\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
{
|
||||
return get_config_keys_str();
|
||||
} else {
|
||||
return dc_strdup(0 as *const libc::c_char);
|
||||
_ => dc_sqlite3_get_config(context, &context.sql, key.as_ref(), None),
|
||||
};
|
||||
|
||||
if value.is_some() {
|
||||
return value.unwrap();
|
||||
}
|
||||
|
||||
match key.as_ref() {
|
||||
"e2ee_enabled" => "1".into(),
|
||||
"mdns_enabled" => "1".into(),
|
||||
"imap_folder" => "INBOX".into(),
|
||||
"inbox_watch" => "1".into(),
|
||||
"sentbox_watch" | "mvbox_watch" | "mvbox_move" => "1".into(),
|
||||
"show_emails" => "0".into(),
|
||||
"selfstatus" => {
|
||||
let s = unsafe { dc_stock_str(context, 13) };
|
||||
let res = to_string(s);
|
||||
unsafe { free(s as *mut _) };
|
||||
res
|
||||
}
|
||||
_ => "".into(),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn get_config_keys_str() -> *mut libc::c_char {
|
||||
let mut ret = String::new();
|
||||
let mut i = 0;
|
||||
while i
|
||||
< (::std::mem::size_of::<[*const libc::c_char; 33]>())
|
||||
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>())
|
||||
{
|
||||
if !ret.is_empty() {
|
||||
ret += " ";
|
||||
}
|
||||
ret += &to_string(config_keys[i as usize]);
|
||||
i += 1
|
||||
}
|
||||
fn is_gettable_config_key(key: impl AsRef<str>) -> bool {
|
||||
SYS_CONFIG_KEYS
|
||||
.into_iter()
|
||||
.find(|c| **c == key.as_ref())
|
||||
.is_some()
|
||||
|| is_settable_config_key(key)
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while i
|
||||
< (::std::mem::size_of::<[*const libc::c_char; 3]>())
|
||||
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>())
|
||||
{
|
||||
if !ret.is_empty() {
|
||||
ret += " ";
|
||||
}
|
||||
ret += &to_string(sys_config_keys[i as usize]);
|
||||
i += 1
|
||||
fn get_sys_config_str(key: impl AsRef<str>) -> String {
|
||||
match key.as_ref() {
|
||||
"sys.version" => std::str::from_utf8(DC_VERSION_STR).unwrap().into(),
|
||||
"sys.msgsize_max_recommended" => format!("{}", 24 * 1024 * 1024 / 4 * 3),
|
||||
"sys.config_keys" => get_config_keys_str(),
|
||||
_ => "".into(),
|
||||
}
|
||||
}
|
||||
|
||||
strdup(to_cstring(ret).as_ptr())
|
||||
fn get_config_keys_str() -> String {
|
||||
let keys = &CONFIG_KEYS[..].join(" ");
|
||||
let sys_keys = &SYS_CONFIG_KEYS[..].join(" ");
|
||||
|
||||
format!("{} {}", keys, sys_keys)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
|
||||
let unset = "0";
|
||||
let l = dc_loginparam_new();
|
||||
let l2 = dc_loginparam_new();
|
||||
dc_loginparam_read(
|
||||
context,
|
||||
l,
|
||||
&context.sql,
|
||||
b"\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_loginparam_read(
|
||||
context,
|
||||
l2,
|
||||
&context.sql,
|
||||
b"configured_\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let displayname = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"displayname\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let l = dc_loginparam_read(context, &context.sql, "");
|
||||
let l2 = dc_loginparam_read(context, &context.sql, "configured_");
|
||||
let displayname = dc_sqlite3_get_config(context, &context.sql, "displayname", None);
|
||||
let chats = dc_get_chat_cnt(context) as usize;
|
||||
let real_msgs = dc_get_real_msg_cnt(context) as usize;
|
||||
let deaddrop_msgs = dc_get_deaddrop_msg_cnt(context) as usize;
|
||||
let contacts = dc_get_real_contact_cnt(context) as usize;
|
||||
let is_configured = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured\x00" as *const u8 as *const libc::c_char,
|
||||
0,
|
||||
);
|
||||
let dbversion = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"dbversion\x00" as *const u8 as *const libc::c_char,
|
||||
0,
|
||||
);
|
||||
let e2ee_enabled = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1,
|
||||
);
|
||||
let mdns_enabled = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"mdns_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1,
|
||||
);
|
||||
let mut stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT COUNT(*) FROM keypairs;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_step(stmt);
|
||||
let prv_key_cnt = sqlite3_column_int(stmt, 0);
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT COUNT(*) FROM acpeerstates;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_step(stmt);
|
||||
let pub_key_cnt = sqlite3_column_int(stmt, 0);
|
||||
sqlite3_finalize(stmt);
|
||||
let fingerprint_str =
|
||||
if let Some(key) = Key::from_self_public(context, (*l2).addr, &context.sql) {
|
||||
key.fingerprint()
|
||||
} else {
|
||||
"<Not yet calculated>".into()
|
||||
};
|
||||
let is_configured = dc_sqlite3_get_config_int(context, &context.sql, "configured", 0);
|
||||
let dbversion = dc_sqlite3_get_config_int(context, &context.sql, "dbversion", 0);
|
||||
let e2ee_enabled = dc_sqlite3_get_config_int(context, &context.sql, "e2ee_enabled", 1);
|
||||
let mdns_enabled = dc_sqlite3_get_config_int(context, &context.sql, "mdns_enabled", 1);
|
||||
|
||||
let l_readable_str = dc_loginparam_get_readable(l);
|
||||
let l2_readable_str = dc_loginparam_get_readable(l2);
|
||||
let inbox_watch = dc_sqlite3_get_config_int(
|
||||
let prv_key_cnt: Option<isize> = dc_sqlite3_query_row(
|
||||
context,
|
||||
&context.sql,
|
||||
b"inbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
1,
|
||||
);
|
||||
let sentbox_watch = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
1,
|
||||
);
|
||||
let mvbox_watch = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"mvbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
1,
|
||||
);
|
||||
let mvbox_move = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"mvbox_move\x00" as *const u8 as *const libc::c_char,
|
||||
1,
|
||||
);
|
||||
let folders_configured = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"folders_configured\x00" as *const u8 as *const libc::c_char,
|
||||
"SELECT COUNT(*) FROM keypairs;",
|
||||
rusqlite::NO_PARAMS,
|
||||
0,
|
||||
);
|
||||
|
||||
let pub_key_cnt: Option<isize> = dc_sqlite3_query_row(
|
||||
context,
|
||||
&context.sql,
|
||||
"SELECT COUNT(*) FROM acpeerstates;",
|
||||
rusqlite::NO_PARAMS,
|
||||
0,
|
||||
);
|
||||
|
||||
let fingerprint_str = if let Some(key) = Key::from_self_public(context, &l2.addr, &context.sql)
|
||||
{
|
||||
key.fingerprint()
|
||||
} else {
|
||||
"<Not yet calculated>".into()
|
||||
};
|
||||
|
||||
let l_readable_str = dc_loginparam_get_readable(&l);
|
||||
let l2_readable_str = dc_loginparam_get_readable(&l2);
|
||||
let inbox_watch = dc_sqlite3_get_config_int(context, &context.sql, "inbox_watch", 1);
|
||||
let sentbox_watch = dc_sqlite3_get_config_int(context, &context.sql, "sentbox_watch", 1);
|
||||
let mvbox_watch = dc_sqlite3_get_config_int(context, &context.sql, "mvbox_watch", 1);
|
||||
let mvbox_move = dc_sqlite3_get_config_int(context, &context.sql, "mvbox_move", 1);
|
||||
let folders_configured =
|
||||
dc_sqlite3_get_config_int(context, &context.sql, "folders_configured", 0);
|
||||
let configured_sentbox_folder = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_sentbox_folder\x00" as *const u8 as *const libc::c_char,
|
||||
b"<unset>\x00" as *const u8 as *const libc::c_char,
|
||||
"configured_sentbox_folder",
|
||||
Some("<unset>"),
|
||||
);
|
||||
let configured_mvbox_folder = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char,
|
||||
b"<unset>\x00" as *const u8 as *const libc::c_char,
|
||||
"configured_mvbox_folder",
|
||||
Some("<unset>"),
|
||||
);
|
||||
|
||||
let res = format!(
|
||||
@@ -737,7 +624,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
|
||||
fingerprint={}\n\
|
||||
level=awesome\n",
|
||||
as_str(DC_VERSION_STR as *const u8 as *const _),
|
||||
as_str(libsqlite3_sys::SQLITE_VERSION as *const u8 as *const libc::c_char),
|
||||
rusqlite::version(),
|
||||
sqlite3_threadsafe(),
|
||||
// arch
|
||||
(::std::mem::size_of::<*mut libc::c_void>()).wrapping_mul(8),
|
||||
@@ -756,36 +643,24 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
if !displayname.is_null() {
|
||||
as_str(displayname)
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
displayname.unwrap_or_else(|| unset.into()),
|
||||
is_configured,
|
||||
as_str(l_readable_str),
|
||||
as_str(l2_readable_str),
|
||||
l_readable_str,
|
||||
l2_readable_str,
|
||||
inbox_watch,
|
||||
sentbox_watch,
|
||||
mvbox_watch,
|
||||
mvbox_move,
|
||||
folders_configured,
|
||||
as_str(configured_sentbox_folder),
|
||||
as_str(configured_mvbox_folder),
|
||||
configured_sentbox_folder.unwrap_or_default(),
|
||||
configured_mvbox_folder.unwrap_or_default(),
|
||||
mdns_enabled,
|
||||
e2ee_enabled,
|
||||
prv_key_cnt,
|
||||
pub_key_cnt,
|
||||
prv_key_cnt.unwrap_or_default(),
|
||||
pub_key_cnt.unwrap_or_default(),
|
||||
fingerprint_str,
|
||||
);
|
||||
|
||||
dc_loginparam_unref(l);
|
||||
dc_loginparam_unref(l2);
|
||||
free(displayname as *mut libc::c_void);
|
||||
free(l_readable_str as *mut libc::c_void);
|
||||
free(l2_readable_str as *mut libc::c_void);
|
||||
free(configured_sentbox_folder as *mut libc::c_void);
|
||||
free(configured_mvbox_folder as *mut libc::c_void);
|
||||
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
}
|
||||
|
||||
@@ -793,155 +668,120 @@ pub unsafe fn dc_get_version_str() -> *mut libc::c_char {
|
||||
dc_strdup(DC_VERSION_STR as *const u8 as *const libc::c_char)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_fresh_msgs(context: &Context) -> *mut dc_array_t {
|
||||
pub fn dc_get_fresh_msgs(context: &Context) -> *mut dc_array_t {
|
||||
let show_deaddrop = 0;
|
||||
let ret = dc_array_new(128 as size_t);
|
||||
let mut stmt = 0 as *mut sqlite3_stmt;
|
||||
let ret = unsafe { dc_array_new(128 as size_t) };
|
||||
if !ret.is_null() {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
if let Some(ref mut stmt) = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT m.id FROM msgs m LEFT JOIN contacts ct \
|
||||
ON m.from_id=ct.id LEFT JOIN chats c ON m.chat_id=c.id WHERE m.state=? \
|
||||
AND m.hidden=0 \
|
||||
AND m.chat_id>? \
|
||||
AND ct.blocked=0 \
|
||||
AND (c.blocked=0 OR c.blocked=?) ORDER BY m.timestamp DESC,m.id DESC;\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1, 10);
|
||||
sqlite3_bind_int(stmt, 2, 9);
|
||||
sqlite3_bind_int(stmt, 3, if 0 != show_deaddrop { 2 } else { 0 });
|
||||
while sqlite3_step(stmt) == 100 {
|
||||
dc_array_add_id(ret, sqlite3_column_int(stmt, 0) as uint32_t);
|
||||
"SELECT m.id FROM msgs m LEFT JOIN contacts ct \
|
||||
ON m.from_id=ct.id LEFT JOIN chats c ON m.chat_id=c.id WHERE m.state=? \
|
||||
AND m.hidden=0 \
|
||||
AND m.chat_id>? \
|
||||
AND ct.blocked=0 \
|
||||
AND (c.blocked=0 OR c.blocked=?) ORDER BY m.timestamp DESC,m.id DESC;",
|
||||
) {
|
||||
match stmt.query_map(&[10, 9, if 0 != show_deaddrop { 2 } else { 0 }], |row| {
|
||||
row.get(0)
|
||||
}) {
|
||||
Ok(rows) => {
|
||||
for row in rows {
|
||||
if let Ok(id) = row {
|
||||
unsafe { dc_array_add_id(ret, id) };
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_err) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
pub unsafe fn dc_search_msgs(
|
||||
pub fn dc_search_msgs(
|
||||
context: &Context,
|
||||
chat_id: uint32_t,
|
||||
query: *const libc::c_char,
|
||||
) -> *mut dc_array_t {
|
||||
let mut success = 0;
|
||||
let ret = dc_array_new(100 as size_t);
|
||||
let mut strLikeInText = 0 as *mut libc::c_char;
|
||||
let mut strLikeBeg = 0 as *mut libc::c_char;
|
||||
let mut real_query = 0 as *mut libc::c_char;
|
||||
let mut stmt = 0 as *mut sqlite3_stmt;
|
||||
let mut success = false;
|
||||
let ret = unsafe { dc_array_new(100 as size_t) };
|
||||
|
||||
if !(ret.is_null() || query.is_null()) {
|
||||
real_query = dc_strdup(query);
|
||||
dc_trim(real_query);
|
||||
if *real_query.offset(0isize) as libc::c_int == 0 {
|
||||
success = 1
|
||||
let real_query = to_string(query).trim().to_string();
|
||||
if real_query.is_empty() {
|
||||
success = true;
|
||||
} else {
|
||||
strLikeInText = dc_mprintf(
|
||||
b"%%%s%%\x00" as *const u8 as *const libc::c_char,
|
||||
real_query,
|
||||
);
|
||||
strLikeBeg = dc_mprintf(b"%s%%\x00" as *const u8 as *const libc::c_char, real_query);
|
||||
if 0 != chat_id {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
let strLikeInText = format!("%{}%", &real_query);
|
||||
let strLikeBeg = format!("{}%", &real_query);
|
||||
|
||||
let rows = if 0 != chat_id {
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id WHERE m.chat_id=? \
|
||||
"SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id WHERE m.chat_id=? \
|
||||
AND m.hidden=0 \
|
||||
AND ct.blocked=0 AND (txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp,m.id;\x00"
|
||||
as *const u8 as *const libc::c_char
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1, chat_id as libc::c_int);
|
||||
sqlite3_bind_text(stmt, 2, strLikeInText, -1, None);
|
||||
sqlite3_bind_text(stmt, 3, strLikeBeg, -1, None);
|
||||
AND ct.blocked=0 AND (txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp,m.id;"
|
||||
).and_then(|mut stmt| stmt.query_map(
|
||||
params![chat_id as libc::c_int, &strLikeInText, &strLikeBeg],
|
||||
|row| row.get::<_, i32>(0)
|
||||
).and_then(|res| res.collect::<rusqlite::Result<Vec<i32>>>()).ok())
|
||||
} else {
|
||||
let show_deaddrop = 0;
|
||||
stmt = dc_sqlite3_prepare(
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id \
|
||||
"SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id \
|
||||
LEFT JOIN chats c ON m.chat_id=c.id WHERE m.chat_id>9 AND m.hidden=0 \
|
||||
AND (c.blocked=0 OR c.blocked=?) \
|
||||
AND ct.blocked=0 AND (m.txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp DESC,m.id DESC;\x00"
|
||||
as *const u8 as *const libc::c_char
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1, if 0 != show_deaddrop { 2 } else { 0 });
|
||||
sqlite3_bind_text(stmt, 2, strLikeInText, -1, None);
|
||||
sqlite3_bind_text(stmt, 3, strLikeBeg, -1, None);
|
||||
AND ct.blocked=0 AND (m.txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp DESC,m.id DESC;"
|
||||
).and_then(|mut stmt|
|
||||
stmt.query_map(params![
|
||||
if 0 != show_deaddrop { 2 } else { 0 },
|
||||
strLikeInText, strLikeBeg,
|
||||
], |row| row.get::<_, i32>(0)).and_then(|res| res.collect::<rusqlite::Result<Vec<i32>>>()).ok()
|
||||
)
|
||||
};
|
||||
if let Some(ids) = rows {
|
||||
for id in ids {
|
||||
unsafe { dc_array_add_id(ret, id as u32) };
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
while sqlite3_step(stmt) == 100 {
|
||||
dc_array_add_id(ret, sqlite3_column_int(stmt, 0) as uint32_t);
|
||||
}
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
|
||||
free(strLikeInText as *mut libc::c_void);
|
||||
free(strLikeBeg as *mut libc::c_void);
|
||||
free(real_query as *mut libc::c_void);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if 0 != success {
|
||||
if success {
|
||||
ret
|
||||
} else {
|
||||
if !ret.is_null() {
|
||||
dc_array_unref(ret);
|
||||
unsafe { dc_array_unref(ret) };
|
||||
}
|
||||
0 as *mut dc_array_t
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_is_inbox(_context: &Context, folder_name: *const libc::c_char) -> libc::c_int {
|
||||
let mut is_inbox = 0;
|
||||
if !folder_name.is_null() {
|
||||
is_inbox = if strcasecmp(
|
||||
b"INBOX\x00" as *const u8 as *const libc::c_char,
|
||||
folder_name,
|
||||
) == 0
|
||||
{
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
is_inbox
|
||||
pub fn dc_is_inbox(_context: &Context, folder_name: impl AsRef<str>) -> bool {
|
||||
folder_name.as_ref() == "INBOX"
|
||||
}
|
||||
|
||||
pub unsafe fn dc_is_sentbox(context: &Context, folder_name: *const libc::c_char) -> libc::c_int {
|
||||
let sentbox_name = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_sentbox_folder\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let mut is_sentbox = 0;
|
||||
if !sentbox_name.is_null() && !folder_name.is_null() {
|
||||
is_sentbox = if strcasecmp(sentbox_name, folder_name) == 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
pub fn dc_is_sentbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
|
||||
let sentbox_name =
|
||||
dc_sqlite3_get_config(context, &context.sql, "configured_sentbox_folder", None);
|
||||
if let Some(name) = sentbox_name {
|
||||
name == folder_name.as_ref()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
free(sentbox_name as *mut libc::c_void);
|
||||
is_sentbox
|
||||
}
|
||||
|
||||
pub unsafe fn dc_is_mvbox(context: &Context, folder_name: *const libc::c_char) -> libc::c_int {
|
||||
let mvbox_name = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let mut is_mvbox = 0;
|
||||
if !mvbox_name.is_null() && !folder_name.is_null() {
|
||||
is_mvbox = if strcasecmp(mvbox_name, folder_name) == 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
pub fn dc_is_mvbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
|
||||
let mvbox_name = dc_sqlite3_get_config(context, &context.sql, "configured_mvbox_folder", None);
|
||||
|
||||
if let Some(name) = mvbox_name {
|
||||
name == folder_name.as_ref()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
free(mvbox_name as *mut libc::c_void);
|
||||
is_mvbox
|
||||
}
|
||||
|
||||
1971
src/dc_chat.rs
1971
src/dc_chat.rs
File diff suppressed because it is too large
Load Diff
@@ -120,146 +120,163 @@ unsafe fn dc_chatlist_load_from_db(
|
||||
mut chatlist: *mut dc_chatlist_t,
|
||||
listflags: libc::c_int,
|
||||
query__: *const libc::c_char,
|
||||
query_contact_id: uint32_t,
|
||||
query_contact_id: u32,
|
||||
) -> libc::c_int {
|
||||
let current_block: u64;
|
||||
//clock_t start = clock();
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut add_archived_link_item: libc::c_int = 0i32;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
let mut strLikeCmd: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut query: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !(chatlist.is_null() || (*chatlist).magic != 0xc4a71157u32) {
|
||||
dc_chatlist_empty(chatlist);
|
||||
// select with left join and minimum:
|
||||
// - the inner select must use `hidden` and _not_ `m.hidden`
|
||||
// which would refer the outer select and take a lot of time
|
||||
// - `GROUP BY` is needed several messages may have the same timestamp
|
||||
// - the list starts with the newest chats
|
||||
// nb: the query currently shows messages from blocked contacts in groups.
|
||||
// however, for normal-groups, this is okay as the message is also returned by dc_get_chat_msgs()
|
||||
// (otherwise it would be hard to follow conversations, wa and tg do the same)
|
||||
// for the deaddrop, however, they should really be hidden, however, _currently_ the deaddrop is not
|
||||
// shown at all permanent in the chatlist.
|
||||
if 0 != query_contact_id {
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
(*chatlist).context,
|
||||
&(*chatlist).context.sql,
|
||||
b"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m ON c.id=m.chat_id AND m.timestamp=( SELECT MAX(timestamp) FROM msgs WHERE chat_id=c.id AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 AND c.blocked=0 AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?) GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;\x00"
|
||||
as *const u8 as *const libc::c_char
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1i32, query_contact_id as libc::c_int);
|
||||
current_block = 3437258052017859086;
|
||||
} else if 0 != listflags & 0x1i32 {
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
(*chatlist).context,
|
||||
&(*chatlist).context.sql,
|
||||
b"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m ON c.id=m.chat_id AND m.timestamp=( SELECT MAX(timestamp) FROM msgs WHERE chat_id=c.id AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 AND c.blocked=0 AND c.archived=1 GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
current_block = 3437258052017859086;
|
||||
} else if query__.is_null() {
|
||||
if 0 == listflags & 0x2i32 {
|
||||
let last_deaddrop_fresh_msg_id: uint32_t =
|
||||
get_last_deaddrop_fresh_msg((*chatlist).context);
|
||||
if last_deaddrop_fresh_msg_id > 0i32 as libc::c_uint {
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, 1i32 as uint32_t);
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, last_deaddrop_fresh_msg_id);
|
||||
}
|
||||
add_archived_link_item = 1i32
|
||||
}
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
(*chatlist).context,
|
||||
&(*chatlist).context.sql,
|
||||
b"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m ON c.id=m.chat_id AND m.timestamp=( SELECT MAX(timestamp) FROM msgs WHERE chat_id=c.id AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 AND c.blocked=0 AND c.archived=0 GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
current_block = 3437258052017859086;
|
||||
} else {
|
||||
query = dc_strdup(query__);
|
||||
dc_trim(query);
|
||||
if *query.offset(0isize) as libc::c_int == 0i32 {
|
||||
success = 1i32;
|
||||
current_block = 15179736777190528364;
|
||||
} else {
|
||||
strLikeCmd = dc_mprintf(b"%%%s%%\x00" as *const u8 as *const libc::c_char, query);
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
(*chatlist).context,
|
||||
&(*chatlist).context.sql,
|
||||
b"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m ON c.id=m.chat_id AND m.timestamp=( SELECT MAX(timestamp) FROM msgs WHERE chat_id=c.id AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 AND c.blocked=0 AND c.name LIKE ? GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;\x00"
|
||||
as *const u8 as
|
||||
*const libc::c_char);
|
||||
sqlite3_bind_text(stmt, 1i32, strLikeCmd, -1i32, None);
|
||||
current_block = 3437258052017859086;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
15179736777190528364 => {}
|
||||
_ => {
|
||||
while sqlite3_step(stmt) == 100i32 {
|
||||
dc_array_add_id(
|
||||
(*chatlist).chatNlastmsg_ids,
|
||||
sqlite3_column_int(stmt, 0i32) as uint32_t,
|
||||
);
|
||||
dc_array_add_id(
|
||||
(*chatlist).chatNlastmsg_ids,
|
||||
sqlite3_column_int(stmt, 1i32) as uint32_t,
|
||||
);
|
||||
}
|
||||
if 0 != add_archived_link_item && dc_get_archived_cnt((*chatlist).context) > 0i32 {
|
||||
if dc_array_get_cnt((*chatlist).chatNlastmsg_ids) == 0
|
||||
&& 0 != listflags & 0x4i32
|
||||
{
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, 7i32 as uint32_t);
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, 0i32 as uint32_t);
|
||||
}
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, 6i32 as uint32_t);
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, 0i32 as uint32_t);
|
||||
}
|
||||
(*chatlist).cnt = dc_array_get_cnt((*chatlist).chatNlastmsg_ids).wrapping_div(2);
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
|
||||
if chatlist.is_null() || (*chatlist).magic != 0xc4a71157u32 {
|
||||
return 0;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
free(query as *mut libc::c_void);
|
||||
free(strLikeCmd as *mut libc::c_void);
|
||||
success
|
||||
dc_chatlist_empty(chatlist);
|
||||
|
||||
let mut add_archived_link_item = 0;
|
||||
|
||||
// select with left join and minimum:
|
||||
// - the inner select must use `hidden` and _not_ `m.hidden`
|
||||
// which would refer the outer select and take a lot of time
|
||||
// - `GROUP BY` is needed several messages may have the same timestamp
|
||||
// - the list starts with the newest chats
|
||||
// nb: the query currently shows messages from blocked contacts in groups.
|
||||
// however, for normal-groups, this is okay as the message is also returned by dc_get_chat_msgs()
|
||||
// (otherwise it would be hard to follow conversations, wa and tg do the same)
|
||||
// for the deaddrop, however, they should really be hidden, however, _currently_ the deaddrop is not
|
||||
// shown at all permanent in the chatlist.
|
||||
|
||||
let process_fn = |row: &rusqlite::Row| {
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, row.get(0)?);
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, row.get(1)?);
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let success = if query_contact_id != 0 {
|
||||
if let Some(mut stmt) = dc_sqlite3_prepare(
|
||||
(*chatlist).context,
|
||||
&(*chatlist).context.sql,
|
||||
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
|
||||
ON c.id=m.chat_id \
|
||||
AND m.timestamp=( SELECT MAX(timestamp) \
|
||||
FROM msgs WHERE chat_id=c.id \
|
||||
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
|
||||
AND c.blocked=0 AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?) \
|
||||
GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
|
||||
) {
|
||||
stmt.query_map(params![query_contact_id as i32], process_fn)
|
||||
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>())
|
||||
.is_ok()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else if 0 != listflags & 0x1 {
|
||||
if let Some(mut stmt) = dc_sqlite3_prepare(
|
||||
(*chatlist).context,
|
||||
&(*chatlist).context,
|
||||
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
|
||||
ON c.id=m.chat_id \
|
||||
AND m.timestamp=( SELECT MAX(timestamp) \
|
||||
FROM msgs WHERE chat_id=c.id \
|
||||
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
|
||||
AND c.blocked=0 AND c.archived=1 GROUP BY c.id \
|
||||
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
|
||||
) {
|
||||
stmt.query_map(params![], process_fn)
|
||||
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>())
|
||||
.is_ok()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else if query__.is_null() {
|
||||
if 0 == listflags & 0x2 {
|
||||
let last_deaddrop_fresh_msg_id = get_last_deaddrop_fresh_msg((*chatlist).context);
|
||||
if last_deaddrop_fresh_msg_id > 0 {
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, 1);
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, last_deaddrop_fresh_msg_id);
|
||||
}
|
||||
add_archived_link_item = 1;
|
||||
}
|
||||
if let Some(mut stmt) = dc_sqlite3_prepare(
|
||||
(*chatlist).context,
|
||||
&(*chatlist).context.sql,
|
||||
"SELECT c.id, m.id FROM chats c \
|
||||
LEFT JOIN msgs m \
|
||||
ON c.id=m.chat_id \
|
||||
AND m.timestamp=( SELECT MAX(timestamp) \
|
||||
FROM msgs WHERE chat_id=c.id \
|
||||
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
|
||||
AND c.blocked=0 AND c.archived=0 \
|
||||
GROUP BY c.id \
|
||||
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
|
||||
) {
|
||||
stmt.query_map(params![], process_fn)
|
||||
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>())
|
||||
.is_ok()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
let query = to_string(query__).trim().to_string();
|
||||
if query.is_empty() {
|
||||
return 1;
|
||||
} else {
|
||||
let strLikeCmd = format!("%{}%", query);
|
||||
if let Some(mut stmt) = dc_sqlite3_prepare(
|
||||
(*chatlist).context,
|
||||
&(*chatlist).context.sql.clone().read().unwrap(),
|
||||
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
|
||||
ON c.id=m.chat_id \
|
||||
AND m.timestamp=( SELECT MAX(timestamp) \
|
||||
FROM msgs WHERE chat_id=c.id \
|
||||
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
|
||||
AND c.blocked=0 AND c.name LIKE ? \
|
||||
GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
|
||||
) {
|
||||
stmt.query_map(params![strLikeCmd], process_fn)
|
||||
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>())
|
||||
.is_ok()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if 0 != add_archived_link_item && dc_get_archived_cnt((*chatlist).context) > 0 {
|
||||
if dc_array_get_cnt((*chatlist).chatNlastmsg_ids) == 0 && 0 != listflags & 0x4 {
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, 7 as uint32_t);
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, 0 as uint32_t);
|
||||
}
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, 6 as uint32_t);
|
||||
dc_array_add_id((*chatlist).chatNlastmsg_ids, 0 as uint32_t);
|
||||
}
|
||||
(*chatlist).cnt = dc_array_get_cnt((*chatlist).chatNlastmsg_ids).wrapping_div(2);
|
||||
|
||||
success as libc::c_int
|
||||
}
|
||||
|
||||
// Context functions to work with chatlist
|
||||
pub unsafe fn dc_get_archived_cnt(context: &Context) -> libc::c_int {
|
||||
let mut ret: libc::c_int = 0i32;
|
||||
let stmt: *mut sqlite3_stmt = dc_sqlite3_prepare(
|
||||
pub fn dc_get_archived_cnt(context: &Context) -> libc::c_int {
|
||||
dc_sqlite3_query_row(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT COUNT(*) FROM chats WHERE blocked=0 AND archived=1;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
if sqlite3_step(stmt) == 100i32 {
|
||||
ret = sqlite3_column_int(stmt, 0i32)
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
ret
|
||||
"SELECT COUNT(*) FROM chats WHERE blocked=0 AND archived=1;",
|
||||
params![],
|
||||
0,
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
unsafe fn get_last_deaddrop_fresh_msg(context: &Context) -> uint32_t {
|
||||
let mut ret: uint32_t = 0i32 as uint32_t;
|
||||
let stmt: *mut sqlite3_stmt;
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT m.id FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id WHERE m.state=10 AND m.hidden=0 AND c.blocked=2 ORDER BY m.timestamp DESC, m.id DESC;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
/* we have an index over the state-column, this should be sufficient as there are typically only few fresh messages */
|
||||
if !(sqlite3_step(stmt) != 100i32) {
|
||||
ret = sqlite3_column_int(stmt, 0i32) as uint32_t
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
ret
|
||||
fn get_last_deaddrop_fresh_msg(context: &Context) -> u32 {
|
||||
// we have an index over the state-column, this should be sufficient as there are typically only few fresh messages
|
||||
dc_sqlite3_query_row(
|
||||
context,
|
||||
&context.sql,
|
||||
"SELECT m.id FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id \
|
||||
WHERE m.state=10 \
|
||||
AND m.hidden=0 \
|
||||
AND c.blocked=2 \
|
||||
ORDER BY m.timestamp DESC, m.id DESC;",
|
||||
params![],
|
||||
0,
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chatlist_get_cnt(chatlist: *const dc_chatlist_t) -> size_t {
|
||||
|
||||
1573
src/dc_configure.rs
1573
src/dc_configure.rs
File diff suppressed because it is too large
Load Diff
1059
src/dc_contact.rs
1059
src/dc_contact.rs
File diff suppressed because it is too large
Load Diff
107
src/dc_e2ee.rs
107
src/dc_e2ee.rs
@@ -82,28 +82,18 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
|| plain.is_null())
|
||||
{
|
||||
/* libEtPan's pgp_encrypt_mime() takes the parent as the new root. We just expect the root as being given to this function. */
|
||||
let prefer_encrypt = if 0
|
||||
!= dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1,
|
||||
) {
|
||||
EncryptPreference::Mutual
|
||||
} else {
|
||||
EncryptPreference::NoPreference
|
||||
};
|
||||
let prefer_encrypt =
|
||||
if 0 != dc_sqlite3_get_config_int(context, &context.sql, "e2ee_enabled", 1) {
|
||||
EncryptPreference::Mutual
|
||||
} else {
|
||||
EncryptPreference::NoPreference
|
||||
};
|
||||
|
||||
let addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let addr = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None);
|
||||
|
||||
if !addr.is_null() {
|
||||
if let Some(addr) = addr {
|
||||
if let Some(public_key) =
|
||||
load_or_generate_self_public_key(context, addr, in_out_message)
|
||||
load_or_generate_self_public_key(context, &addr, in_out_message)
|
||||
{
|
||||
/*only for random-seed*/
|
||||
if prefer_encrypt == EncryptPreference::Mutual || 0 != e2ee_guaranteed {
|
||||
@@ -111,15 +101,10 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
let mut iter1: *mut clistiter;
|
||||
iter1 = (*recipients_addr).first;
|
||||
while !iter1.is_null() {
|
||||
let recipient_addr: *const libc::c_char = (if !iter1.is_null() {
|
||||
(*iter1).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
})
|
||||
as *const libc::c_char;
|
||||
if strcasecmp(recipient_addr, addr) != 0 {
|
||||
let recipient_addr = to_string((*iter1).data as *const libc::c_char);
|
||||
if recipient_addr != addr {
|
||||
let peerstate =
|
||||
Peerstate::from_addr(context, &context.sql, as_str(recipient_addr));
|
||||
Peerstate::from_addr(context, &context.sql, &recipient_addr);
|
||||
if peerstate.is_some()
|
||||
&& (peerstate.as_ref().unwrap().prefer_encrypt
|
||||
== EncryptPreference::Mutual
|
||||
@@ -366,8 +351,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
match current_block {
|
||||
14181132614457621749 => {}
|
||||
_ => {
|
||||
let addr = CStr::from_ptr(addr).to_str().unwrap();
|
||||
let aheader = Aheader::new(addr.into(), public_key, prefer_encrypt);
|
||||
let aheader = Aheader::new(addr, public_key, prefer_encrypt);
|
||||
let rendered = CString::new(aheader.to_string()).unwrap();
|
||||
|
||||
mailimf_fields_add(
|
||||
@@ -503,13 +487,13 @@ unsafe fn new_data_part(
|
||||
******************************************************************************/
|
||||
unsafe fn load_or_generate_self_public_key(
|
||||
context: &Context,
|
||||
self_addr: *const libc::c_char,
|
||||
self_addr: impl AsRef<str>,
|
||||
_random_data_mime: *mut mailmime,
|
||||
) -> Option<Key> {
|
||||
/* avoid double creation (we unlock the database during creation) */
|
||||
static mut s_in_key_creation: libc::c_int = 0i32;
|
||||
static mut s_in_key_creation: libc::c_int = 0;
|
||||
|
||||
let mut key = Key::from_self_public(context, self_addr, &context.sql);
|
||||
let mut key = Key::from_self_public(context, &self_addr, &context.sql);
|
||||
if key.is_some() {
|
||||
return key;
|
||||
}
|
||||
@@ -521,36 +505,33 @@ unsafe fn load_or_generate_self_public_key(
|
||||
let key_creation_here = 1;
|
||||
s_in_key_creation = 1;
|
||||
|
||||
let start: libc::clock_t = clock();
|
||||
dc_log_info(
|
||||
let start = clock();
|
||||
info!(
|
||||
context,
|
||||
0i32,
|
||||
b"Generating keypair with %i bits, e=%i ...\x00" as *const u8 as *const libc::c_char,
|
||||
2048i32,
|
||||
65537i32,
|
||||
0, "Generating keypair with {} bits, e={} ...", 2048, 65537,
|
||||
);
|
||||
|
||||
if let Some((public_key, private_key)) = dc_pgp_create_keypair(self_addr) {
|
||||
if let Some((public_key, private_key)) = dc_pgp_create_keypair(&self_addr) {
|
||||
if !dc_key_save_self_keypair(
|
||||
context,
|
||||
&public_key,
|
||||
&private_key,
|
||||
self_addr,
|
||||
&self_addr,
|
||||
1i32,
|
||||
&context.sql,
|
||||
) {
|
||||
/*set default*/
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"Cannot save keypair.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"Keypair generated in %.3f s.\x00" as *const u8 as *const libc::c_char,
|
||||
clock().wrapping_sub(start) as libc::c_double / 1000000i32 as libc::c_double,
|
||||
clock().wrapping_sub(start) as libc::c_double / 1000000 as libc::c_double,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -558,7 +539,7 @@ unsafe fn load_or_generate_self_public_key(
|
||||
} else {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"Cannot create keypair.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
@@ -583,7 +564,6 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
|
||||
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();
|
||||
let mut public_keyring_for_validate = Keyring::default();
|
||||
let mut gossip_headers: *mut mailimf_fields = 0 as *mut mailimf_fields;
|
||||
@@ -612,28 +592,23 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
|
||||
if let Some(ref mut peerstate) = peerstate {
|
||||
if let Some(ref header) = autocryptheader {
|
||||
peerstate.apply_header(&header, message_time as u64);
|
||||
peerstate.apply_header(&header, message_time);
|
||||
peerstate.save_to_db(&context.sql, false);
|
||||
} else if message_time as u64 > peerstate.last_seen_autocrypt
|
||||
} else if message_time > peerstate.last_seen_autocrypt
|
||||
&& 0 == contains_report(in_out_message)
|
||||
{
|
||||
peerstate.degrade_encryption(message_time as u64);
|
||||
peerstate.degrade_encryption(message_time);
|
||||
peerstate.save_to_db(&context.sql, false);
|
||||
}
|
||||
} else if let Some(ref header) = autocryptheader {
|
||||
let p = Peerstate::from_header(context, header, message_time as u64);
|
||||
let p = Peerstate::from_header(context, header, message_time);
|
||||
p.save_to_db(&context.sql, true);
|
||||
peerstate = Some(p);
|
||||
}
|
||||
}
|
||||
/* load private key for decryption */
|
||||
self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !self_addr.is_null() {
|
||||
let self_addr = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None);
|
||||
if let Some(self_addr) = self_addr {
|
||||
if private_keyring.load_self_private_for_decrypting(context, self_addr, &context.sql) {
|
||||
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
|
||||
peerstate = Peerstate::from_addr(&context, &context.sql, as_str(from));
|
||||
@@ -681,7 +656,6 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
}
|
||||
|
||||
free(from as *mut libc::c_void);
|
||||
free(self_addr as *mut libc::c_void);
|
||||
}
|
||||
|
||||
unsafe fn update_gossip_peerstates(
|
||||
@@ -722,10 +696,10 @@ unsafe fn update_gossip_peerstates(
|
||||
let mut peerstate =
|
||||
Peerstate::from_addr(context, &context.sql, &header.addr);
|
||||
if let Some(ref mut peerstate) = peerstate {
|
||||
peerstate.apply_gossip(header, message_time as u64);
|
||||
peerstate.apply_gossip(header, message_time);
|
||||
peerstate.save_to_db(&context.sql, false);
|
||||
} else {
|
||||
let p = Peerstate::from_gossip(context, header, message_time as u64);
|
||||
let p = Peerstate::from_gossip(context, header, message_time);
|
||||
p.save_to_db(&context.sql, true);
|
||||
peerstate = Some(p);
|
||||
}
|
||||
@@ -1103,25 +1077,20 @@ pub unsafe fn dc_ensure_secret_key_exists(context: &Context) -> libc::c_int {
|
||||
(this is to gain some extra-random-seed by the message content and the timespan between program start and message sending) */
|
||||
let mut success: libc::c_int = 0i32;
|
||||
|
||||
let self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if self_addr.is_null() {
|
||||
let self_addr = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None);
|
||||
if self_addr.is_none() {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot ensure secret key if context is not configured.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else if load_or_generate_self_public_key(context, self_addr, 0 as *mut mailmime).is_some() {
|
||||
} else if load_or_generate_self_public_key(context, self_addr.unwrap(), 0 as *mut mailmime)
|
||||
.is_some()
|
||||
{
|
||||
/*no random text data for seeding available*/
|
||||
success = 1i32
|
||||
}
|
||||
|
||||
free(self_addr as *mut libc::c_void);
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
590
src/dc_imex.rs
590
src/dc_imex.rs
@@ -236,7 +236,6 @@ pub unsafe extern "C" fn dc_render_setup_file(
|
||||
passphrase: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
let stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
|
||||
let mut passphrase_begin: [libc::c_char; 8] = [0; 8];
|
||||
let mut ret_setupfilecontent: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
@@ -245,19 +244,11 @@ pub unsafe extern "C" fn dc_render_setup_file(
|
||||
passphrase_begin[2usize] = 0i32 as libc::c_char;
|
||||
/* create the payload */
|
||||
if !(0 == dc_ensure_secret_key_exists(context)) {
|
||||
self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let curr_private_key = Key::from_self_private(context, self_addr, &context.sql);
|
||||
let e2ee_enabled: libc::c_int = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
);
|
||||
let self_addr = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None)
|
||||
.unwrap_or_default();
|
||||
let curr_private_key =
|
||||
Key::from_self_private(context, self_addr, &context.sql.clone().read().unwrap());
|
||||
let e2ee_enabled = dc_sqlite3_get_config_int(context, &context.sql, "e2ee_enabled", 1);
|
||||
|
||||
let headers = if 0 != e2ee_enabled {
|
||||
Some(("Autocrypt-Prefer-Encrypt", "mutual"))
|
||||
@@ -311,8 +302,6 @@ pub unsafe extern "C" fn dc_render_setup_file(
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
free(self_addr as *mut libc::c_void);
|
||||
|
||||
ret_setupfilecontent
|
||||
}
|
||||
|
||||
@@ -355,7 +344,7 @@ pub unsafe fn dc_continue_key_transfer(
|
||||
if !(msg_id <= 9i32 as libc::c_uint || setup_code.is_null()) {
|
||||
msg = dc_get_msg(context, msg_id);
|
||||
if msg.is_null()
|
||||
|| 0 == dc_msg_is_setupmessage(msg)
|
||||
|| !dc_msg_is_setupmessage(msg)
|
||||
|| {
|
||||
filename = dc_msg_get_file(msg);
|
||||
filename.is_null()
|
||||
@@ -400,7 +389,7 @@ pub unsafe fn dc_continue_key_transfer(
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
unsafe fn set_self_key(
|
||||
fn set_self_key(
|
||||
context: &Context,
|
||||
armored_c: *const libc::c_char,
|
||||
set_default: libc::c_int,
|
||||
@@ -413,88 +402,80 @@ unsafe fn set_self_key(
|
||||
assert!(!armored_c.is_null(), "invalid buffer");
|
||||
let armored = as_str(armored_c);
|
||||
|
||||
if let Some((private_key, public_key, header)) =
|
||||
Key::from_armored_string(armored, KeyType::Private)
|
||||
.and_then(|(k, h)| if k.verify() { Some((k, h)) } else { None })
|
||||
.and_then(|(k, h)| k.split_key().map(|pub_key| (k, pub_key, h)))
|
||||
{
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"DELETE FROM keypairs WHERE public_key=? OR private_key=?;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
let pub_bytes = public_key.to_bytes();
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
1,
|
||||
pub_bytes.as_ptr() as *const _,
|
||||
pub_bytes.len() as libc::c_int,
|
||||
None,
|
||||
);
|
||||
let priv_bytes = private_key.to_bytes();
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
2,
|
||||
priv_bytes.as_ptr() as *const _,
|
||||
priv_bytes.len() as libc::c_int,
|
||||
None,
|
||||
);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = 0 as *mut sqlite3_stmt;
|
||||
if 0 != set_default {
|
||||
dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
b"UPDATE keypairs SET is_default=0;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !dc_key_save_self_keypair(
|
||||
context,
|
||||
&public_key,
|
||||
&private_key,
|
||||
self_addr,
|
||||
set_default,
|
||||
&context.sql,
|
||||
) {
|
||||
error!(context, 0, "Cannot save keypair.",);
|
||||
} else {
|
||||
let prefer_encrypt = header.get("Autocrypt-Prefer-Encrypt");
|
||||
let keys = Key::from_armored_string(armored, KeyType::Private)
|
||||
.and_then(|(k, h)| if k.verify() { Some((k, h)) } else { None })
|
||||
.and_then(|(k, h)| k.split_key().map(|pub_key| (k, pub_key, h)));
|
||||
|
||||
if let Some(prefer_encrypt) = prefer_encrypt {
|
||||
if prefer_encrypt == "nopreference" {
|
||||
dc_sqlite3_set_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
0i32,
|
||||
);
|
||||
} else if prefer_encrypt == "mutual" {
|
||||
dc_sqlite3_set_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
);
|
||||
}
|
||||
}
|
||||
success = 1;
|
||||
if keys.is_none() {
|
||||
error!(context, 0, "File does not contain a valid private key.",);
|
||||
return 0;
|
||||
}
|
||||
|
||||
let (private_key, public_key, header) = keys.unwrap();
|
||||
let preferencrypt = header.get("Autocrypt-Prefer-Encrypt");
|
||||
|
||||
if !dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"DELETE FROM keypairs WHERE public_key=? OR private_key=?;",
|
||||
params![public_key.to_bytes(), private_key.to_bytes()],
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if 0 != set_default {
|
||||
if !dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"UPDATE keypairs SET is_default=0;",
|
||||
params![],
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
error!(context, 0, "File does not contain a private key.",);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
free(self_addr as *mut libc::c_void);
|
||||
let self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"configured_addr",
|
||||
None,
|
||||
);
|
||||
|
||||
success
|
||||
if self_addr.is_none() {
|
||||
error!(context, 0, "Missing self addr");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if !dc_key_save_self_keypair(
|
||||
context,
|
||||
&public_key,
|
||||
&private_key,
|
||||
self_addr.unwrap(),
|
||||
set_default,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
) {
|
||||
error!(context, 0, "Cannot save keypair.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
match preferencrypt.as_str() {
|
||||
"" => 0,
|
||||
"nopreference" => dc_sqlite3_set_config_int(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"e2ee_enabled",
|
||||
0,
|
||||
),
|
||||
"mutual" => dc_sqlite3_set_config_int(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"e2ee_enabled",
|
||||
1,
|
||||
),
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_decrypt_setup_file(
|
||||
@@ -842,65 +823,72 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
|
||||
|
||||
// TODO should return bool /rtn
|
||||
unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char) -> libc::c_int {
|
||||
let current_block: u64;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut processed_files_cnt: libc::c_int = 0i32;
|
||||
let total_files_cnt: libc::c_int;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
let mut pathNfilename: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let repl_from: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let repl_to: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
dc_log_info(
|
||||
let mut success = 0;
|
||||
let mut processed_files_cnt = 0;
|
||||
|
||||
let total_files_cnt: usize;
|
||||
|
||||
info!(
|
||||
context,
|
||||
0i32,
|
||||
b"Import \"%s\" to \"%s\".\x00" as *const u8 as *const libc::c_char,
|
||||
backup_to_import,
|
||||
context.get_dbfile(),
|
||||
0,
|
||||
"Import \"{}\" to \"{}\".",
|
||||
as_str(backup_to_import),
|
||||
as_str(context.get_dbfile()),
|
||||
);
|
||||
|
||||
if 0 != dc_is_configured(context) {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot import backups to accounts in use.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
error!(context, 0, "Cannot import backups to accounts in use.");
|
||||
} else {
|
||||
&context.sql.close(&context);
|
||||
dc_delete_file(context, context.get_dbfile());
|
||||
if 0 != dc_file_exist(context, context.get_dbfile()) {
|
||||
dc_log_error(
|
||||
error!(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot import backups: Cannot delete the old file.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
0, "Cannot import backups: Cannot delete the old file.",
|
||||
);
|
||||
} else if !(0 == dc_copy_file(context, backup_to_import, context.get_dbfile())) {
|
||||
/* error already logged */
|
||||
/* re-open copied database file */
|
||||
if context.sql.open(&context, as_path(context.get_dbfile()), 0) {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
total_files_cnt = dc_sqlite3_query_row::<_, isize>(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT COUNT(*) FROM backup_blobs;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_step(stmt);
|
||||
total_files_cnt = sqlite3_column_int(stmt, 0i32);
|
||||
"SELECT COUNT(*) FROM backup_blobs;",
|
||||
params![],
|
||||
0,
|
||||
)
|
||||
.unwrap_or_default() as usize;
|
||||
info!(
|
||||
context,
|
||||
0, "***IMPORT-in-progress: total_files_cnt={:?}", total_files_cnt
|
||||
0, "***IMPORT-in-progress: total_files_cnt={:?}", total_files_cnt,
|
||||
);
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = dc_sqlite3_prepare(
|
||||
|
||||
let files = if let Some(mut stmt) = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT file_name, file_content FROM backup_blobs ORDER BY id;\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
);
|
||||
loop {
|
||||
if !(sqlite3_step(stmt) == 100i32) {
|
||||
current_block = 10891380440665537214;
|
||||
"SELECT file_name, file_content FROM backup_blobs ORDER BY id;",
|
||||
) {
|
||||
stmt.query_map(params![], |row| {
|
||||
let name: String = row.get(0)?;
|
||||
let blob: Vec<u8> = row.get(1)?;
|
||||
|
||||
Ok((name, blob))
|
||||
})
|
||||
.map(|res| res.collect::<Vec<_>>())
|
||||
.unwrap()
|
||||
} else {
|
||||
panic!("invalid sql");
|
||||
};
|
||||
|
||||
let mut loop_success = true;
|
||||
|
||||
for file in files {
|
||||
if file.is_err() {
|
||||
loop_success = false;
|
||||
break;
|
||||
}
|
||||
let (file_name, file_blob) = file.unwrap();
|
||||
|
||||
if context
|
||||
.running_state
|
||||
.clone()
|
||||
@@ -908,82 +896,52 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
{
|
||||
current_block = 8648553629232744886;
|
||||
loop_success = false;
|
||||
break;
|
||||
}
|
||||
processed_files_cnt += 1;
|
||||
let mut permille: libc::c_int = processed_files_cnt * 1000i32 / total_files_cnt;
|
||||
if permille < 10i32 {
|
||||
permille = 10i32
|
||||
let mut permille = processed_files_cnt * 1000 / total_files_cnt;
|
||||
if permille < 10 {
|
||||
permille = 10
|
||||
}
|
||||
if permille > 990i32 {
|
||||
permille = 990i32
|
||||
if permille > 990 {
|
||||
permille = 990
|
||||
}
|
||||
context.call_cb(
|
||||
Event::IMEX_PROGRESS,
|
||||
permille as uintptr_t,
|
||||
0i32 as uintptr_t,
|
||||
);
|
||||
let file_name: *const libc::c_char =
|
||||
sqlite3_column_text(stmt, 0i32) as *const libc::c_char;
|
||||
let file_bytes: libc::c_int = sqlite3_column_bytes(stmt, 1i32);
|
||||
let file_content: *const libc::c_void = sqlite3_column_blob(stmt, 1i32);
|
||||
if !(file_bytes > 0i32 && !file_content.is_null()) {
|
||||
context.call_cb(Event::IMEX_PROGRESS, permille as uintptr_t, 0);
|
||||
if file_blob.is_empty() {
|
||||
continue;
|
||||
}
|
||||
free(pathNfilename as *mut libc::c_void);
|
||||
pathNfilename = dc_mprintf(
|
||||
b"%s/%s\x00" as *const u8 as *const libc::c_char,
|
||||
context.get_blobdir(),
|
||||
file_name,
|
||||
);
|
||||
if !(0
|
||||
== dc_write_file(
|
||||
context,
|
||||
pathNfilename,
|
||||
file_content,
|
||||
file_bytes as size_t,
|
||||
))
|
||||
{
|
||||
|
||||
let pathNfilename = format!("{}/{}", as_str(context.get_blobdir()), file_name);
|
||||
if dc_write_file_safe(context, &pathNfilename, &file_blob) {
|
||||
continue;
|
||||
}
|
||||
dc_log_error(
|
||||
|
||||
error!(
|
||||
context,
|
||||
0i32,
|
||||
b"Storage full? Cannot write file %s with %i bytes.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
pathNfilename,
|
||||
file_bytes,
|
||||
0,
|
||||
"Storage full? Cannot write file {} with {} bytes.",
|
||||
&pathNfilename,
|
||||
file_blob.len(),
|
||||
);
|
||||
/* otherwise the user may believe the stuff is imported correctly, but there are files missing ... */
|
||||
current_block = 8648553629232744886;
|
||||
// otherwise the user may believe the stuff is imported correctly, but there are files missing ...
|
||||
loop_success = false;
|
||||
break;
|
||||
}
|
||||
match current_block {
|
||||
8648553629232744886 => {}
|
||||
_ => {
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = 0 as *mut sqlite3_stmt;
|
||||
dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
b"DROP TABLE backup_blobs;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_try_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
b"VACUUM;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
success = 1i32
|
||||
}
|
||||
|
||||
if loop_success {
|
||||
dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"DROP TABLE backup_blobs;",
|
||||
params![],
|
||||
);
|
||||
dc_sqlite3_try_execute(context, &context.sql, "VACUUM;");
|
||||
success = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(pathNfilename as *mut libc::c_void);
|
||||
free(repl_from as *mut libc::c_void);
|
||||
free(repl_to as *mut libc::c_void);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
success
|
||||
}
|
||||
@@ -996,15 +954,10 @@ The macro avoids weird values of 0% or 100% while still working. */
|
||||
// TODO should return bool /rtn
|
||||
unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut success: libc::c_int = 0;
|
||||
let mut closed: libc::c_int;
|
||||
|
||||
let mut curr_pathNfilename: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut buf: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut buf_bytes: size_t = 0i32 as size_t;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
let mut delete_dest_file: libc::c_int = 0i32;
|
||||
let mut dest_sql: Option<SQLite> = None;
|
||||
let mut delete_dest_file: libc::c_int = 0;
|
||||
// get a fine backup file name (the name includes the date so that multiple backup instances are possible)
|
||||
// FIXME: we should write to a temporary file first and rename it on success. this would guarantee the backup is complete. however, currently it is not clear it the import exists in the long run (may be replaced by a restore-from-imap)
|
||||
let now = time();
|
||||
@@ -1016,7 +969,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
if dest_pathNfilename.is_null() {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"Cannot get backup file name.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
|
||||
@@ -1024,40 +977,36 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
}
|
||||
|
||||
dc_housekeeping(context);
|
||||
dc_sqlite3_try_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
b"VACUUM;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
context.sql.close(&context);
|
||||
closed = 1i32;
|
||||
info!(
|
||||
|
||||
dc_sqlite3_try_execute(context, &context.sql, "VACUUM;");
|
||||
dc_sqlite3_close(context, &mut context.sql);
|
||||
closed = 1;
|
||||
dc_log_info(
|
||||
context,
|
||||
0,
|
||||
"Backup \"{}\" to \"{}\".",
|
||||
as_str(context.get_dbfile()),
|
||||
as_str(dest_pathNfilename),
|
||||
b"Backup \"%s\" to \"%s\".\x00" as *const u8 as *const libc::c_char,
|
||||
context.get_dbfile(),
|
||||
dest_pathNfilename,
|
||||
);
|
||||
if !(0 == dc_copy_file(context, context.get_dbfile(), dest_pathNfilename)) {
|
||||
context.sql.open(&context, as_path(context.get_dbfile()), 0);
|
||||
closed = 0i32;
|
||||
closed = 0;
|
||||
/* add all files as blobs to the database copy (this does not require the source to be locked, neigher the destination as it is used only here) */
|
||||
/*for logging only*/
|
||||
let sql = SQLite::new();
|
||||
if sql.open(context, as_path(dest_pathNfilename), 0) {
|
||||
if 0 == dc_sqlite3_table_exists(
|
||||
context,
|
||||
&sql,
|
||||
b"backup_blobs\x00" as *const u8 as *const libc::c_char,
|
||||
) {
|
||||
if 0 ==
|
||||
dc_sqlite3_execute(context, &sql,
|
||||
b"CREATE TABLE backup_blobs (id INTEGER PRIMARY KEY, file_name, file_content);\x00"
|
||||
as *const u8 as
|
||||
*const libc::c_char) {
|
||||
/* error already logged */
|
||||
current_block = 11487273724841241105;
|
||||
} else { current_block = 14648156034262866959; }
|
||||
if 0 == dc_sqlite3_table_exists(context, &sql, "backup_blobs") {
|
||||
if !dc_sqlite3_execute(
|
||||
context,
|
||||
&sql,
|
||||
"CREATE TABLE backup_blobs (id INTEGER PRIMARY KEY, file_name, file_content);",
|
||||
params![],
|
||||
) {
|
||||
/* error already logged */
|
||||
current_block = 11487273724841241105;
|
||||
} else {
|
||||
current_block = 14648156034262866959;
|
||||
}
|
||||
} else {
|
||||
current_block = 14648156034262866959;
|
||||
}
|
||||
@@ -1070,7 +1019,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
if dir_handle.is_err() {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"Backup: Cannot get info for blob-directory \"%s\".\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
context.get_blobdir(),
|
||||
@@ -1088,17 +1037,15 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
context,
|
||||
0,
|
||||
"Backup: Cannot copy from blob-directory \"{}\".",
|
||||
as_str(context.get_blobdir()),
|
||||
context.get_blobdir(),
|
||||
);
|
||||
} else {
|
||||
let dir_handle = dir_handle.unwrap();
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&sql,
|
||||
b"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);\x00"
|
||||
as *const u8 as
|
||||
*const libc::c_char
|
||||
);
|
||||
let mut stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&sql,
|
||||
"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);"
|
||||
).expect("bad sql state");
|
||||
|
||||
let mut processed_files_cnt = 0;
|
||||
for entry in dir_handle {
|
||||
@@ -1130,92 +1077,73 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
context.call_cb(
|
||||
Event::IMEX_PROGRESS,
|
||||
permille as uintptr_t,
|
||||
0i32 as uintptr_t,
|
||||
0 as uintptr_t,
|
||||
);
|
||||
|
||||
let name_f = entry.file_name();
|
||||
let name = name_f.to_string_lossy();
|
||||
if name.starts_with("delt-chat") && name.ends_with(".bak") {
|
||||
if name.starts_with("delta-chat") && name.ends_with(".bak")
|
||||
{
|
||||
continue;
|
||||
} else {
|
||||
info!(context, 0, "EXPORTing filename={}", name);
|
||||
free(curr_pathNfilename as *mut libc::c_void);
|
||||
let name_c = to_cstring(name);
|
||||
curr_pathNfilename = dc_mprintf(
|
||||
b"%s/%s\x00" as *const u8 as *const libc::c_char,
|
||||
context.get_blobdir(),
|
||||
name_c.as_ptr(),
|
||||
let curr_pathNfilename = format!(
|
||||
"{}/{}",
|
||||
as_str(context.get_blobdir()),
|
||||
name
|
||||
);
|
||||
free(buf);
|
||||
if 0 == dc_read_file(
|
||||
context,
|
||||
curr_pathNfilename,
|
||||
&mut buf,
|
||||
&mut buf_bytes,
|
||||
) || buf.is_null()
|
||||
|| buf_bytes <= 0
|
||||
|
||||
if let Some(buf) =
|
||||
dc_read_file_safe(context, &curr_pathNfilename)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sqlite3_bind_text(
|
||||
stmt,
|
||||
1i32,
|
||||
name_c.as_ptr(),
|
||||
-1i32,
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
2i32,
|
||||
buf,
|
||||
buf_bytes as libc::c_int,
|
||||
None,
|
||||
);
|
||||
if sqlite3_step(stmt) != 101i32 {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
b"Disk full? Cannot add file \"%s\" to backup.\x00"
|
||||
as *const u8
|
||||
as *const libc::c_char,
|
||||
curr_pathNfilename,
|
||||
);
|
||||
/* this is not recoverable! writing to the sqlite database should work! */
|
||||
current_block = 11487273724841241105;
|
||||
break;
|
||||
if buf.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if stmt.execute(params![name, buf]).is_err() {
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Disk full? Cannot add file \"{}\" to backup.",
|
||||
&curr_pathNfilename,
|
||||
);
|
||||
/* this is not recoverable! writing to the sqlite database should work! */
|
||||
current_block = 11487273724841241105;
|
||||
break;
|
||||
}
|
||||
// TODO: do we need to reset the stmt?
|
||||
} else {
|
||||
sqlite3_reset(stmt);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!(context, 0, "Backup: No files to copy.");
|
||||
info!(context, 0, "Backup: No files to copy.",);
|
||||
current_block = 2631791190359682872;
|
||||
}
|
||||
match current_block {
|
||||
11487273724841241105 => {}
|
||||
_ => {
|
||||
dc_sqlite3_set_config_int(
|
||||
if 0 != dc_sqlite3_set_config_int(
|
||||
context,
|
||||
&sql,
|
||||
b"backup_time\x00" as *const u8 as *const libc::c_char,
|
||||
now as int32_t,
|
||||
);
|
||||
context.call_cb(
|
||||
Event::IMEX_FILE_WRITTEN,
|
||||
dest_pathNfilename as uintptr_t,
|
||||
0i32 as uintptr_t,
|
||||
);
|
||||
success = 1i32
|
||||
"backup_time",
|
||||
now as i32,
|
||||
) {
|
||||
context.call_cb(
|
||||
Event::IMEX_FILE_WRITTEN,
|
||||
dest_pathNfilename as uintptr_t,
|
||||
0,
|
||||
);
|
||||
success = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dest_sql = Some(sql);
|
||||
}
|
||||
if 0 != closed {
|
||||
context.sql.open(&context, as_path(context.get_dbfile()), 0);
|
||||
@@ -1228,8 +1156,6 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
dc_delete_file(context, dest_pathNfilename);
|
||||
}
|
||||
free(dest_pathNfilename as *mut libc::c_void);
|
||||
free(curr_pathNfilename as *mut libc::c_void);
|
||||
free(buf);
|
||||
|
||||
success
|
||||
}
|
||||
@@ -1244,12 +1170,12 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
|
||||
Maybe we should make the "default" key handlong also a little bit smarter
|
||||
(currently, the last imported key is the standard key unless it contains the string "legacy" in its name) */
|
||||
let mut imported_cnt: libc::c_int = 0i32;
|
||||
let mut imported_cnt: libc::c_int = 0;
|
||||
let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut path_plus_name: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut set_default: libc::c_int;
|
||||
let mut buf: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut buf_bytes: size_t = 0i32 as size_t;
|
||||
let mut buf_bytes: size_t = 0 as size_t;
|
||||
// a pointer inside buf, MUST NOT be free()'d
|
||||
let mut private_key: *const libc::c_char;
|
||||
let mut buf2: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
@@ -1261,7 +1187,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
if dir_handle.is_err() {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"Import: Cannot open directory \"%s\".\x00" as *const u8 as *const libc::c_char,
|
||||
dir_name,
|
||||
);
|
||||
@@ -1277,7 +1203,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
let name_c = to_cstring(name_f.to_string_lossy());
|
||||
suffix = dc_get_filesuffix_lc(name_c.as_ptr());
|
||||
if suffix.is_null()
|
||||
|| strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0i32
|
||||
|| strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1289,7 +1215,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
);
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"Checking: %s\x00" as *const u8 as *const libc::c_char,
|
||||
path_plus_name,
|
||||
);
|
||||
@@ -1316,7 +1242,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
) && strcmp(
|
||||
buf2_headerline,
|
||||
b"-----BEGIN PGP PUBLIC KEY BLOCK-----\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
) == 0
|
||||
{
|
||||
private_key = strstr(
|
||||
buf,
|
||||
@@ -1327,7 +1253,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
continue;
|
||||
}
|
||||
}
|
||||
set_default = 1i32;
|
||||
set_default = 1;
|
||||
if !strstr(
|
||||
name_c.as_ptr(),
|
||||
b"legacy\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -1369,45 +1295,55 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
|
||||
// TODO should return bool /rtn
|
||||
unsafe fn export_self_keys(context: &Context, dir: *const libc::c_char) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut export_errors: libc::c_int = 0i32;
|
||||
let mut id: libc::c_int;
|
||||
let mut is_default: libc::c_int;
|
||||
let stmt = dc_sqlite3_prepare(
|
||||
let mut export_errors = 0;
|
||||
|
||||
if let Some(mut stmt) = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT id, public_key, private_key, is_default FROM keypairs;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
if !stmt.is_null() {
|
||||
while sqlite3_step(stmt) == 100i32 {
|
||||
id = sqlite3_column_int(stmt, 0i32);
|
||||
let public_key = Key::from_stmt(stmt, 1, KeyType::Public);
|
||||
let private_key = Key::from_stmt(stmt, 2, KeyType::Private);
|
||||
"SELECT id, public_key, private_key, is_default FROM keypairs;",
|
||||
) {
|
||||
let rows = stmt.query_map(params![], |row| {
|
||||
let id = row.get(0)?;
|
||||
let public_key_blob: Vec<u8> = row.get(1)?;
|
||||
let public_key = Key::from_slice(&public_key_blob, KeyType::Public);
|
||||
let private_key_blob: Vec<u8> = row.get(2)?;
|
||||
let private_key = Key::from_slice(&private_key_blob, KeyType::Private);
|
||||
let is_default = row.get(3)?;
|
||||
|
||||
is_default = sqlite3_column_int(stmt, 3i32);
|
||||
if let Some(key) = public_key {
|
||||
if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) {
|
||||
export_errors += 1
|
||||
Ok((id, public_key, private_key, is_default))
|
||||
});
|
||||
|
||||
if let Ok(keys) = rows {
|
||||
for key_pair in keys {
|
||||
if let Ok((id, public_key, private_key, is_default)) = key_pair {
|
||||
if let Some(key) = public_key {
|
||||
if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) {
|
||||
export_errors += 1;
|
||||
}
|
||||
} else {
|
||||
export_errors += 1;
|
||||
}
|
||||
if let Some(key) = private_key {
|
||||
if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) {
|
||||
export_errors += 1;
|
||||
}
|
||||
} else {
|
||||
export_errors += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
export_errors += 1;
|
||||
}
|
||||
if let Some(key) = private_key {
|
||||
if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) {
|
||||
export_errors += 1
|
||||
}
|
||||
} else {
|
||||
export_errors += 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
if export_errors == 0i32 {
|
||||
success = 1i32
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
success
|
||||
if export_errors == 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
499
src/dc_job.rs
499
src/dc_job.rs
@@ -67,72 +67,74 @@ pub unsafe fn dc_perform_imap_jobs(context: &Context) {
|
||||
);
|
||||
}
|
||||
unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: libc::c_int) {
|
||||
let mut select_stmt: *mut sqlite3_stmt;
|
||||
let mut job = dc_job_t {
|
||||
job_id: 0,
|
||||
action: 0,
|
||||
foreign_id: 0,
|
||||
desired_timestamp: 0,
|
||||
added_timestamp: 0,
|
||||
tries: 0,
|
||||
param: 0 as *mut dc_param_t,
|
||||
try_again: 0,
|
||||
pending_error: 0 as *mut libc::c_char,
|
||||
};
|
||||
job.param = dc_param_new();
|
||||
let process_row = |row: &rusqlite::Row| {
|
||||
let job = dc_job_t {
|
||||
job_id: row.get(0)?,
|
||||
action: row.get(1)?,
|
||||
foreign_id: row.get(2)?,
|
||||
desired_timestamp: row.get(5)?,
|
||||
added_timestamp: row.get(4)?,
|
||||
tries: row.get(6)?,
|
||||
param: dc_param_new(),
|
||||
try_again: 0,
|
||||
pending_error: 0 as *mut libc::c_char,
|
||||
};
|
||||
|
||||
if probe_network == 0i32 {
|
||||
select_stmt =
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries FROM jobs WHERE thread=? AND desired_timestamp<=? ORDER BY action DESC, added_timestamp;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_int64(select_stmt, 1i32, thread as sqlite3_int64);
|
||||
sqlite3_bind_int64(select_stmt, 2i32, time() as sqlite3_int64);
|
||||
} else {
|
||||
select_stmt =
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries FROM jobs WHERE thread=? AND tries>0 ORDER BY desired_timestamp, action DESC;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_int64(select_stmt, 1i32, thread as sqlite3_int64);
|
||||
}
|
||||
while sqlite3_step(select_stmt) == 100i32 {
|
||||
job.job_id = sqlite3_column_int(select_stmt, 0i32) as uint32_t;
|
||||
job.action = sqlite3_column_int(select_stmt, 1i32);
|
||||
job.foreign_id = sqlite3_column_int(select_stmt, 2i32) as uint32_t;
|
||||
dc_param_set_packed(
|
||||
job.param,
|
||||
sqlite3_column_text(select_stmt, 3i32) as *mut libc::c_char,
|
||||
);
|
||||
job.added_timestamp = sqlite3_column_int64(select_stmt, 4i32) as i64;
|
||||
job.desired_timestamp = sqlite3_column_int64(select_stmt, 5i32) as i64;
|
||||
job.tries = sqlite3_column_int(select_stmt, 6i32);
|
||||
dc_log_info(
|
||||
let packed: String = row.get(3)?;
|
||||
dc_param_set_packed(job.param, to_cstring(packed).as_ptr());
|
||||
Ok(job)
|
||||
};
|
||||
|
||||
let jobs = if probe_network == 0 {
|
||||
if let Some(mut stmt) = dc_sqlite3_prepare(
|
||||
context,
|
||||
0i32,
|
||||
b"%s-job #%i, action %i started...\x00" as *const u8 as *const libc::c_char,
|
||||
if thread == 100i32 {
|
||||
b"INBOX\x00" as *const u8 as *const libc::c_char
|
||||
} else {
|
||||
b"SMTP\x00" as *const u8 as *const libc::c_char
|
||||
},
|
||||
job.job_id as libc::c_int,
|
||||
job.action as libc::c_int,
|
||||
&context.sql,
|
||||
"SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \
|
||||
FROM jobs WHERE thread=? AND desired_timestamp<=? ORDER BY action DESC, added_timestamp;"
|
||||
) {
|
||||
stmt.query_map(params![thread as i64, time()], process_row)
|
||||
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
if let Some(mut stmt) = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
"SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \
|
||||
FROM jobs WHERE thread=? AND tries>0 ORDER BY desired_timestamp, action DESC;",
|
||||
) {
|
||||
stmt.query_map(params![thread as i64], process_row)
|
||||
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>())
|
||||
.ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if jobs.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
for mut job in jobs.unwrap() {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"{}-job #{}, action {} started...",
|
||||
if thread == 100 { "INBOX" } else { "SMTP" },
|
||||
job.job_id,
|
||||
job.action,
|
||||
);
|
||||
if 900i32 == job.action || 910i32 == job.action {
|
||||
|
||||
if 900 == job.action || 910 == job.action {
|
||||
dc_job_kill_action(context, job.action);
|
||||
sqlite3_finalize(select_stmt);
|
||||
select_stmt = 0 as *mut sqlite3_stmt;
|
||||
dc_jobthread_suspend(context, &context.sentbox_thread.clone().read().unwrap(), 1);
|
||||
dc_jobthread_suspend(context, &context.mvbox_thread.clone().read().unwrap(), 1);
|
||||
dc_suspend_smtp_thread(context, 1i32);
|
||||
dc_suspend_smtp_thread(context, 1);
|
||||
}
|
||||
let mut tries: libc::c_int = 0i32;
|
||||
while tries <= 1i32 {
|
||||
job.try_again = 0i32;
|
||||
let mut tries = 0;
|
||||
while tries <= 1 {
|
||||
job.try_again = 0;
|
||||
match job.action {
|
||||
5901 => {
|
||||
dc_job_do_DC_JOB_SEND(context, &mut job);
|
||||
@@ -169,12 +171,12 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if job.try_again != -1i32 {
|
||||
if job.try_again != -1 {
|
||||
break;
|
||||
}
|
||||
tries += 1
|
||||
}
|
||||
if 900i32 == job.action || 910i32 == job.action {
|
||||
if 900 == job.action || 910 == job.action {
|
||||
dc_jobthread_suspend(
|
||||
context,
|
||||
&mut context.sentbox_thread.clone().read().unwrap(),
|
||||
@@ -185,57 +187,49 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
|
||||
&mut context.mvbox_thread.clone().read().unwrap(),
|
||||
0,
|
||||
);
|
||||
dc_suspend_smtp_thread(context, 0i32);
|
||||
dc_suspend_smtp_thread(context, 0);
|
||||
break;
|
||||
} else if job.try_again == 2i32 {
|
||||
dc_log_info(
|
||||
} else if job.try_again == 2 {
|
||||
info!(
|
||||
context,
|
||||
0i32,
|
||||
b"%s-job #%i not yet ready and will be delayed.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
if thread == 100i32 {
|
||||
b"INBOX\x00" as *const u8 as *const libc::c_char
|
||||
} else {
|
||||
b"SMTP\x00" as *const u8 as *const libc::c_char
|
||||
},
|
||||
job.job_id as libc::c_int,
|
||||
0,
|
||||
"{}-job #{} not yet ready and will be delayed.",
|
||||
if thread == 100 { "INBOX" } else { "SMTP" },
|
||||
job.job_id
|
||||
);
|
||||
} else if job.try_again == -1i32 || job.try_again == 3i32 {
|
||||
let tries_0: libc::c_int = job.tries + 1i32;
|
||||
if tries_0 < 17i32 {
|
||||
job.tries = tries_0;
|
||||
let time_offset = get_backoff_time_offset(tries_0);
|
||||
} else if job.try_again == -1 || job.try_again == 3 {
|
||||
let tries = job.tries + 1;
|
||||
if tries < 17 {
|
||||
job.tries = tries;
|
||||
let time_offset = get_backoff_time_offset(tries);
|
||||
job.desired_timestamp = job.added_timestamp + time_offset;
|
||||
dc_job_update(context, &mut job);
|
||||
dc_log_info(context, 0i32,
|
||||
b"%s-job #%i not succeeded on try #%i, retry in ADD_TIME+%i (in %i seconds).\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
if thread == 100i32 {
|
||||
b"INBOX\x00" as *const u8 as
|
||||
*const libc::c_char
|
||||
} else {
|
||||
b"SMTP\x00" as *const u8 as
|
||||
*const libc::c_char
|
||||
}, job.job_id as libc::c_int, tries_0,
|
||||
time_offset,
|
||||
job.added_timestamp + time_offset -
|
||||
time());
|
||||
if thread == 5000i32 && tries_0 < 17i32 - 1i32 {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"{}-job #{} not succeeded on try #{}, retry in ADD_TIME+{} (in {} seconds).",
|
||||
if thread == 100 { "INBOX" } else { "SMTP" },
|
||||
job.job_id as libc::c_int,
|
||||
tries,
|
||||
time_offset,
|
||||
job.added_timestamp + time_offset - time()
|
||||
);
|
||||
if thread == 5000 && tries < 17 - 1 {
|
||||
context
|
||||
.smtp_state
|
||||
.clone()
|
||||
.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.perform_jobs_needed = 2i32;
|
||||
.perform_jobs_needed = 2;
|
||||
}
|
||||
} else {
|
||||
if job.action == 5901i32 {
|
||||
if job.action == 5901 {
|
||||
dc_set_msg_failed(context, job.foreign_id, job.pending_error);
|
||||
}
|
||||
dc_job_delete(context, &mut job);
|
||||
}
|
||||
if !(0 != probe_network) {
|
||||
if 0 == probe_network {
|
||||
continue;
|
||||
}
|
||||
// on dc_maybe_network() we stop trying here;
|
||||
@@ -246,21 +240,18 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
|
||||
} else {
|
||||
dc_job_delete(context, &mut job);
|
||||
}
|
||||
dc_param_unref(job.param);
|
||||
free(job.pending_error as *mut libc::c_void);
|
||||
}
|
||||
dc_param_unref(job.param);
|
||||
free(job.pending_error as *mut libc::c_void);
|
||||
sqlite3_finalize(select_stmt);
|
||||
}
|
||||
|
||||
unsafe fn dc_job_delete(context: &Context, job: &dc_job_t) {
|
||||
let delete_stmt: *mut sqlite3_stmt = dc_sqlite3_prepare(
|
||||
fn dc_job_delete(context: &Context, job: &dc_job_t) -> bool {
|
||||
dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
b"DELETE FROM jobs WHERE id=?;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int(delete_stmt, 1i32, job.job_id as libc::c_int);
|
||||
sqlite3_step(delete_stmt);
|
||||
sqlite3_finalize(delete_stmt);
|
||||
"DELETE FROM jobs WHERE id=?;",
|
||||
params![job.job_id as i32],
|
||||
)
|
||||
}
|
||||
|
||||
/* ******************************************************************************
|
||||
@@ -279,20 +270,20 @@ unsafe fn get_backoff_time_offset(c_tries: libc::c_int) -> i64 {
|
||||
seconds as i64
|
||||
}
|
||||
|
||||
unsafe fn dc_job_update(context: &Context, job: &dc_job_t) {
|
||||
let stmt: *mut sqlite3_stmt = dc_sqlite3_prepare(
|
||||
fn dc_job_update(context: &Context, job: &dc_job_t) -> bool {
|
||||
dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
b"UPDATE jobs SET desired_timestamp=?, tries=?, param=? WHERE id=?;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int64(stmt, 1i32, job.desired_timestamp as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 2i32, job.tries as sqlite3_int64);
|
||||
sqlite3_bind_text(stmt, 3i32, (*job.param).packed, -1i32, None);
|
||||
sqlite3_bind_int(stmt, 4i32, job.job_id as libc::c_int);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
"UPDATE jobs SET desired_timestamp=?, tries=?, param=? WHERE id=?;",
|
||||
params![
|
||||
job.desired_timestamp,
|
||||
job.tries as i64,
|
||||
as_str(unsafe { (*job.param).packed }),
|
||||
job.job_id as i32,
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: libc::c_int) {
|
||||
context.smtp_state.0.lock().unwrap().suspended = suspend;
|
||||
if 0 != suspend {
|
||||
@@ -310,18 +301,12 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
|
||||
let mut buf: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut buf_bytes: size_t = 0i32 as size_t;
|
||||
let mut recipients: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
|
||||
/* connect to SMTP server, if not yet done */
|
||||
if !context.smtp.lock().unwrap().is_connected() {
|
||||
let loginparam: *mut dc_loginparam_t = dc_loginparam_new();
|
||||
dc_loginparam_read(
|
||||
context,
|
||||
loginparam,
|
||||
&context.sql,
|
||||
b"configured_\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let connected = context.smtp.lock().unwrap().connect(context, loginparam);
|
||||
dc_loginparam_unref(loginparam);
|
||||
let loginparam = dc_loginparam_read(context, &context.sql, "configured_");
|
||||
let connected = context.smtp.lock().unwrap().connect(context, &loginparam);
|
||||
|
||||
if 0 == connected {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
current_block = 14216916617354591294;
|
||||
@@ -404,18 +389,14 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
|
||||
dc_delete_file(context, filename);
|
||||
if 0 != job.foreign_id {
|
||||
dc_update_msg_state(context, job.foreign_id, 26i32);
|
||||
stmt = dc_sqlite3_prepare(
|
||||
let chat_id: i32 = dc_sqlite3_query_row(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT chat_id FROM msgs WHERE id=?\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1i32, job.foreign_id as libc::c_int);
|
||||
let chat_id: libc::c_int = if sqlite3_step(stmt) == 100i32 {
|
||||
sqlite3_column_int(stmt, 0i32)
|
||||
} else {
|
||||
0i32
|
||||
};
|
||||
"SELECT chat_id FROM msgs WHERE id=?",
|
||||
params![job.foreign_id as i32],
|
||||
0,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
context.call_cb(
|
||||
Event::MSG_DELIVERED,
|
||||
chat_id as uintptr_t,
|
||||
@@ -430,11 +411,11 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
free(recipients as *mut libc::c_void);
|
||||
free(buf);
|
||||
free(filename as *mut libc::c_void);
|
||||
}
|
||||
|
||||
// this value does not increase the number of tries
|
||||
pub unsafe fn dc_job_try_again_later(
|
||||
job: &mut dc_job_t,
|
||||
@@ -448,8 +429,7 @@ pub unsafe fn dc_job_try_again_later(
|
||||
|
||||
unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
|
||||
let mut current_block: u64;
|
||||
let msg: *mut dc_msg_t = dc_msg_new_untyped(context);
|
||||
let mut dest_folder: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let msg = dc_msg_new_untyped(context);
|
||||
let mut dest_uid: uint32_t = 0i32 as uint32_t;
|
||||
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
@@ -468,30 +448,20 @@ unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
|
||||
match current_block {
|
||||
2473556513754201174 => {
|
||||
if dc_msg_load_from_db(msg, context, job.foreign_id) {
|
||||
if dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"folders_configured\x00" as *const u8 as *const libc::c_char,
|
||||
0i32,
|
||||
) < 3i32
|
||||
{
|
||||
if dc_sqlite3_get_config_int(context, &context.sql, "folders_configured", 0) < 3 {
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
dest_folder = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let dest_folder =
|
||||
dc_sqlite3_get_config(context, &context.sql, "configured_mvbox_folder", None);
|
||||
|
||||
if !dest_folder.is_null() {
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
let server_folder = as_str((*msg).server_folder);
|
||||
|
||||
match inbox.mv(
|
||||
context,
|
||||
server_folder,
|
||||
(*msg).server_uid,
|
||||
as_str(dest_folder),
|
||||
&dest_folder,
|
||||
&mut dest_uid,
|
||||
) as libc::c_uint
|
||||
{
|
||||
@@ -502,7 +472,7 @@ unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
|
||||
dc_update_server_uid(
|
||||
context,
|
||||
(*msg).rfc724_mid,
|
||||
dest_folder,
|
||||
&dest_folder,
|
||||
dest_uid,
|
||||
);
|
||||
}
|
||||
@@ -518,7 +488,7 @@ unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
|
||||
dc_update_server_uid(
|
||||
context,
|
||||
(*msg).rfc724_mid,
|
||||
dest_folder,
|
||||
&dest_folder,
|
||||
dest_uid,
|
||||
);
|
||||
}
|
||||
@@ -534,18 +504,17 @@ unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(dest_folder as *mut libc::c_void);
|
||||
|
||||
dc_msg_unref(msg);
|
||||
}
|
||||
|
||||
/* ******************************************************************************
|
||||
* IMAP-jobs
|
||||
******************************************************************************/
|
||||
fn connect_to_inbox(context: &Context, inbox: &Imap) -> libc::c_int {
|
||||
let ret_connected: libc::c_int;
|
||||
|
||||
ret_connected = unsafe { dc_connect_to_configured_imap(context, inbox) };
|
||||
if !(0 == ret_connected) {
|
||||
inbox.set_watch_folder(b"INBOX\x00" as *const u8 as *const libc::c_char);
|
||||
let ret_connected = unsafe { dc_connect_to_configured_imap(context, inbox) };
|
||||
if 0 != ret_connected {
|
||||
inbox.set_watch_folder("INBOX".into());
|
||||
}
|
||||
ret_connected
|
||||
}
|
||||
@@ -554,7 +523,6 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context: &Context, job: &mut dc_
|
||||
let current_block: u64;
|
||||
let folder: *mut libc::c_char = dc_param_get(job.param, 'Z' as i32, 0 as *const libc::c_char);
|
||||
let uid: uint32_t = dc_param_get_int(job.param, 'z' as i32, 0i32) as uint32_t;
|
||||
let mut dest_folder: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut dest_uid: uint32_t = 0i32 as uint32_t;
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
|
||||
@@ -576,23 +544,12 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context: &Context, job: &mut dc_
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
if 0 != dc_param_get_int(job.param, 'M' as i32, 0i32) {
|
||||
if dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"folders_configured\x00" as *const u8 as *const libc::c_char,
|
||||
0i32,
|
||||
) < 3i32
|
||||
{
|
||||
if dc_sqlite3_get_config_int(context, &context.sql, "folders_configured", 0) < 3 {
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
dest_folder = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !dest_folder.is_null() {
|
||||
let dest_folder = as_str(dest_folder);
|
||||
let dest_folder =
|
||||
dc_sqlite3_get_config(context, &context.sql, "configured_mvbox_folder", None);
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid)
|
||||
as libc::c_uint
|
||||
{
|
||||
@@ -604,8 +561,8 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context: &Context, job: &mut dc_
|
||||
_ => {}
|
||||
}
|
||||
free(folder as *mut libc::c_void);
|
||||
free(dest_folder as *mut libc::c_void);
|
||||
}
|
||||
|
||||
unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_job_t) {
|
||||
let mut current_block: u64;
|
||||
let msg: *mut dc_msg_t = dc_msg_new_untyped(context);
|
||||
@@ -639,8 +596,8 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
|
||||
&& 0 != dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"mdns_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
"mdns_enabled",
|
||||
1,
|
||||
)
|
||||
{
|
||||
let folder =
|
||||
@@ -695,8 +652,8 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
|
||||
&& 0 != dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"mdns_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
"mdns_enabled",
|
||||
1,
|
||||
)
|
||||
{
|
||||
let folder =
|
||||
@@ -862,49 +819,39 @@ pub unsafe fn dc_job_add(
|
||||
delay_seconds: libc::c_int,
|
||||
) {
|
||||
let timestamp = time();
|
||||
let stmt: *mut sqlite3_stmt;
|
||||
let thread: libc::c_int;
|
||||
if action >= 100i32 && action < 100i32 + 1000i32 {
|
||||
thread = 100i32
|
||||
} else if action >= 5000i32 && action < 5000i32 + 1000i32 {
|
||||
thread = 5000i32
|
||||
let thread = if action >= 100 && action < 100 + 1000 {
|
||||
100
|
||||
} else if action >= 5000 && action < 5000 + 1000 {
|
||||
5000
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"INSERT INTO jobs (added_timestamp, thread, action, foreign_id, param, desired_timestamp) VALUES (?,?,?,?,?,?);\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_int64(stmt, 1i32, timestamp as sqlite3_int64);
|
||||
sqlite3_bind_int(stmt, 2i32, thread);
|
||||
sqlite3_bind_int(stmt, 3i32, action);
|
||||
sqlite3_bind_int(stmt, 4i32, foreign_id);
|
||||
sqlite3_bind_text(
|
||||
stmt,
|
||||
5i32,
|
||||
if !param.is_null() {
|
||||
param
|
||||
} else {
|
||||
b"\x00" as *const u8 as *const libc::c_char
|
||||
},
|
||||
-1i32,
|
||||
None,
|
||||
};
|
||||
|
||||
dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"INSERT INTO jobs (added_timestamp, thread, action, foreign_id, param, desired_timestamp) VALUES (?,?,?,?,?,?);",
|
||||
params![
|
||||
timestamp,
|
||||
thread,
|
||||
action,
|
||||
foreign_id,
|
||||
if !param.is_null() {
|
||||
as_str(param)
|
||||
} else {
|
||||
""
|
||||
},
|
||||
(timestamp + delay_seconds as i64)
|
||||
]
|
||||
);
|
||||
sqlite3_bind_int64(
|
||||
stmt,
|
||||
6i32,
|
||||
(timestamp + delay_seconds as i64) as sqlite3_int64,
|
||||
);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
if thread == 100i32 {
|
||||
|
||||
if thread == 100 {
|
||||
dc_interrupt_imap_idle(context);
|
||||
} else {
|
||||
dc_interrupt_smtp_idle(context);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_interrupt_smtp_idle(context: &Context) {
|
||||
dc_log_info(
|
||||
context,
|
||||
@@ -991,57 +938,49 @@ unsafe fn dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(context: &Context, job: &mut dc_jo
|
||||
}
|
||||
|
||||
/* delete all pending jobs with the given action */
|
||||
pub unsafe fn dc_job_kill_action(context: &Context, action: libc::c_int) {
|
||||
let stmt = dc_sqlite3_prepare(
|
||||
pub fn dc_job_kill_action(context: &Context, action: libc::c_int) -> bool {
|
||||
dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql,
|
||||
b"DELETE FROM jobs WHERE action=?;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1i32, action);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
"DELETE FROM jobs WHERE action=?;",
|
||||
params![action],
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_perform_imap_fetch(context: &Context) {
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
let start = clock();
|
||||
|
||||
let start: libc::clock_t = clock();
|
||||
if 0 == connect_to_inbox(context, &inbox) {
|
||||
return;
|
||||
}
|
||||
if dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"inbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
) == 0i32
|
||||
{
|
||||
if dc_sqlite3_get_config_int(context, &context.sql, "inbox_watch", 1) == 0 {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"INBOX-watch disabled.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
return;
|
||||
}
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"INBOX-fetch started...\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
inbox.fetch(context);
|
||||
if inbox.should_reconnect() {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"INBOX-fetch aborted, starting over...\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
inbox.fetch(context);
|
||||
}
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"INBOX-fetch done in %.0f ms.\x00" as *const u8 as *const libc::c_char,
|
||||
clock().wrapping_sub(start) as libc::c_double * 1000.0f64 / 1000000i32 as libc::c_double,
|
||||
clock().wrapping_sub(start) as libc::c_double * 1000.0f64 / 1000000 as libc::c_double,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1063,12 +1002,7 @@ pub fn dc_perform_imap_idle(context: &Context) {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_perform_mvbox_fetch(context: &Context) {
|
||||
let use_network: libc::c_int = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"mvbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
);
|
||||
let use_network = dc_sqlite3_get_config_int(context, &context.sql, "mvbox_watch", 1);
|
||||
dc_jobthread_fetch(
|
||||
context,
|
||||
&mut context.mvbox_thread.clone().write().unwrap(),
|
||||
@@ -1077,12 +1011,8 @@ pub unsafe fn dc_perform_mvbox_fetch(context: &Context) {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_perform_mvbox_idle(context: &Context) {
|
||||
let use_network: libc::c_int = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"mvbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
);
|
||||
let use_network = dc_sqlite3_get_config_int(context, &context.sql, "mvbox_watch", 1);
|
||||
|
||||
dc_jobthread_idle(
|
||||
context,
|
||||
&context.mvbox_thread.clone().read().unwrap(),
|
||||
@@ -1095,12 +1025,7 @@ pub unsafe fn dc_interrupt_mvbox_idle(context: &Context) {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_perform_sentbox_fetch(context: &Context) {
|
||||
let use_network: libc::c_int = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
);
|
||||
let use_network = dc_sqlite3_get_config_int(context, &context.sql, "sentbox_watch", 1);
|
||||
dc_jobthread_fetch(
|
||||
context,
|
||||
&mut context.sentbox_thread.clone().write().unwrap(),
|
||||
@@ -1109,12 +1034,7 @@ pub unsafe fn dc_perform_sentbox_fetch(context: &Context) {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_perform_sentbox_idle(context: &Context) {
|
||||
let use_network: libc::c_int = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
);
|
||||
let use_network = dc_sqlite3_get_config_int(context, &context.sql, "sentbox_watch", 1);
|
||||
dc_jobthread_idle(
|
||||
context,
|
||||
&context.sentbox_thread.clone().read().unwrap(),
|
||||
@@ -1138,7 +1058,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) {
|
||||
if 0 != state.suspended {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"SMTP-jobs suspended.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
return;
|
||||
@@ -1155,7 +1075,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) {
|
||||
dc_job_perform(context, 5000, probe_smtp_network);
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"SMTP-jobs ended.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
|
||||
@@ -1170,7 +1090,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) {
|
||||
pub unsafe fn dc_perform_smtp_idle(context: &Context) {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"SMTP-idle started...\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
{
|
||||
@@ -1202,35 +1122,31 @@ pub unsafe fn dc_perform_smtp_idle(context: &Context) {
|
||||
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
0,
|
||||
b"SMTP-idle ended.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
|
||||
unsafe fn get_next_wakeup_time(context: &Context, thread: libc::c_int) -> Duration {
|
||||
let stmt = dc_sqlite3_prepare(
|
||||
let t: i64 = dc_sqlite3_query_row(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT MIN(desired_timestamp) FROM jobs WHERE thread=?;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1, thread);
|
||||
"SELECT MIN(desired_timestamp) FROM jobs WHERE thread=?;",
|
||||
params![thread],
|
||||
0,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut wakeup_time = Duration::new(10 * 60, 0);
|
||||
|
||||
if sqlite3_step(stmt) == 100 {
|
||||
let t = sqlite3_column_int(stmt, 0) as i64;
|
||||
let now = time();
|
||||
if t > 0 {
|
||||
if t > now {
|
||||
wakeup_time = Duration::new((t - now) as u64, 0);
|
||||
} else {
|
||||
wakeup_time = Duration::new(0, 0);
|
||||
}
|
||||
let now = time();
|
||||
if t > 0 {
|
||||
if t > now {
|
||||
wakeup_time = Duration::new((t - now) as u64, 0);
|
||||
} else {
|
||||
wakeup_time = Duration::new(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
wakeup_time
|
||||
}
|
||||
|
||||
@@ -1249,19 +1165,12 @@ pub unsafe fn dc_maybe_network(context: &Context) {
|
||||
dc_interrupt_sentbox_idle(context);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_job_action_exists(context: &Context, action: libc::c_int) -> libc::c_int {
|
||||
let job_exists: libc::c_int;
|
||||
let stmt;
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT id FROM jobs WHERE action=?;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1i32, action);
|
||||
job_exists = (sqlite3_step(stmt) == 100i32) as libc::c_int;
|
||||
sqlite3_finalize(stmt);
|
||||
return job_exists;
|
||||
pub fn dc_job_action_exists(context: &Context, action: libc::c_int) -> bool {
|
||||
dc_sqlite3_prepare(context, &context.sql, "SELECT id FROM jobs WHERE action=?;")
|
||||
.and_then(|mut stmt| stmt.exists(params![action]).ok())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/* special case for DC_JOB_SEND_MSG_TO_SMTP */
|
||||
pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
|
||||
@@ -133,39 +133,29 @@ pub unsafe fn dc_jobthread_fetch(
|
||||
|
||||
unsafe fn connect_to_imap(context: &Context, jobthread: &dc_jobthread_t) -> libc::c_int {
|
||||
let mut ret_connected: libc::c_int;
|
||||
let mut mvbox_name: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
|
||||
if jobthread.imap.is_connected() {
|
||||
ret_connected = 1;
|
||||
} else {
|
||||
ret_connected = dc_connect_to_configured_imap(context, &jobthread.imap);
|
||||
if !(0 == ret_connected) {
|
||||
if dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"folders_configured\x00" as *const u8 as *const libc::c_char,
|
||||
0,
|
||||
) < 3
|
||||
{
|
||||
if dc_sqlite3_get_config_int(context, &context.sql, "folders_configured", 0) < 3 {
|
||||
jobthread.imap.configure_folders(context, 0x1);
|
||||
}
|
||||
mvbox_name = dc_sqlite3_get_config(
|
||||
let mvbox_name = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
CString::new(&jobthread.folder_config_name[..])
|
||||
.unwrap()
|
||||
.as_ptr(),
|
||||
0 as *const libc::c_char,
|
||||
as_str(&jobthread.folder_config_name[..]),
|
||||
None,
|
||||
);
|
||||
if mvbox_name.is_null() {
|
||||
if let Some(name) = mvbox_name {
|
||||
jobthread.imap.set_watch_folder(name);
|
||||
} else {
|
||||
jobthread.imap.disconnect(context);
|
||||
ret_connected = 0;
|
||||
} else {
|
||||
jobthread.imap.set_watch_folder(mvbox_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(mvbox_name as *mut libc::c_void);
|
||||
|
||||
ret_connected
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,283 +1,167 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct dc_loginparam_t {
|
||||
pub addr: *mut libc::c_char,
|
||||
pub mail_server: *mut libc::c_char,
|
||||
pub mail_user: *mut libc::c_char,
|
||||
pub mail_pw: *mut libc::c_char,
|
||||
pub addr: String,
|
||||
pub mail_server: String,
|
||||
pub mail_user: String,
|
||||
pub mail_pw: String,
|
||||
pub mail_port: i32,
|
||||
pub send_server: *mut libc::c_char,
|
||||
pub send_user: *mut libc::c_char,
|
||||
pub send_pw: *mut libc::c_char,
|
||||
pub send_server: String,
|
||||
pub send_user: String,
|
||||
pub send_pw: String,
|
||||
pub send_port: i32,
|
||||
pub server_flags: i32,
|
||||
}
|
||||
|
||||
pub unsafe fn dc_loginparam_new() -> *mut dc_loginparam_t {
|
||||
let loginparam: *mut dc_loginparam_t;
|
||||
loginparam = calloc(1, ::std::mem::size_of::<dc_loginparam_t>()) as *mut dc_loginparam_t;
|
||||
assert!(!loginparam.is_null());
|
||||
|
||||
loginparam
|
||||
}
|
||||
|
||||
pub unsafe fn dc_loginparam_unref(loginparam: *mut dc_loginparam_t) {
|
||||
if loginparam.is_null() {
|
||||
return;
|
||||
impl dc_loginparam_t {
|
||||
pub fn addr_str(&self) -> &str {
|
||||
self.addr.as_str()
|
||||
}
|
||||
dc_loginparam_empty(loginparam);
|
||||
free(loginparam as *mut libc::c_void);
|
||||
}
|
||||
|
||||
/* clears all data and frees its memory. All pointers are NULL after this function is called. */
|
||||
pub unsafe fn dc_loginparam_empty(mut loginparam: *mut dc_loginparam_t) {
|
||||
if loginparam.is_null() {
|
||||
return;
|
||||
}
|
||||
free((*loginparam).addr as *mut libc::c_void);
|
||||
(*loginparam).addr = 0 as *mut libc::c_char;
|
||||
free((*loginparam).mail_server as *mut libc::c_void);
|
||||
(*loginparam).mail_server = 0 as *mut libc::c_char;
|
||||
(*loginparam).mail_port = 0i32;
|
||||
free((*loginparam).mail_user as *mut libc::c_void);
|
||||
(*loginparam).mail_user = 0 as *mut libc::c_char;
|
||||
free((*loginparam).mail_pw as *mut libc::c_void);
|
||||
(*loginparam).mail_pw = 0 as *mut libc::c_char;
|
||||
free((*loginparam).send_server as *mut libc::c_void);
|
||||
(*loginparam).send_server = 0 as *mut libc::c_char;
|
||||
(*loginparam).send_port = 0i32;
|
||||
free((*loginparam).send_user as *mut libc::c_void);
|
||||
(*loginparam).send_user = 0 as *mut libc::c_char;
|
||||
free((*loginparam).send_pw as *mut libc::c_void);
|
||||
(*loginparam).send_pw = 0 as *mut libc::c_char;
|
||||
(*loginparam).server_flags = 0i32;
|
||||
pub fn dc_loginparam_new() -> dc_loginparam_t {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_loginparam_read(
|
||||
pub fn dc_loginparam_read(
|
||||
context: &Context,
|
||||
loginparam: *mut dc_loginparam_t,
|
||||
sql: &SQLite,
|
||||
prefix: *const libc::c_char,
|
||||
) {
|
||||
let mut key: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
dc_loginparam_empty(loginparam);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"addr\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
(*loginparam).addr = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"mail_server\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
(*loginparam).mail_server = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"mail_port\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
(*loginparam).mail_port = dc_sqlite3_get_config_int(context, sql, key, 0i32);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"mail_user\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
(*loginparam).mail_user = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"mail_pw\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
(*loginparam).mail_pw = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"send_server\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
(*loginparam).send_server = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"send_port\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
(*loginparam).send_port = dc_sqlite3_get_config_int(context, sql, key, 0i32);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"send_user\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
(*loginparam).send_user = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"send_pw\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
(*loginparam).send_pw = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"server_flags\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
(*loginparam).server_flags = dc_sqlite3_get_config_int(context, sql, key, 0i32);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
}
|
||||
prefix: impl AsRef<str>,
|
||||
) -> dc_loginparam_t {
|
||||
let prefix = prefix.as_ref();
|
||||
|
||||
pub unsafe fn dc_loginparam_write(
|
||||
context: &Context,
|
||||
loginparam: *const dc_loginparam_t,
|
||||
sql: &SQLite,
|
||||
prefix: *const libc::c_char,
|
||||
) {
|
||||
let mut key: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"addr\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_set_config(context, sql, key, (*loginparam).addr);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"mail_server\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_set_config(context, sql, key, (*loginparam).mail_server);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"mail_port\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_set_config_int(context, sql, key, (*loginparam).mail_port);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"mail_user\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_set_config(context, sql, key, (*loginparam).mail_user);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"mail_pw\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_set_config(context, sql, key, (*loginparam).mail_pw);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"send_server\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_set_config(context, sql, key, (*loginparam).send_server);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"send_port\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_set_config_int(context, sql, key, (*loginparam).send_port);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"send_user\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_set_config(context, sql, key, (*loginparam).send_user);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"send_pw\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_set_config(context, sql, key, (*loginparam).send_pw);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
key = sqlite3_mprintf(
|
||||
b"%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
prefix,
|
||||
b"server_flags\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_sqlite3_set_config_int(context, sql, key, (*loginparam).server_flags);
|
||||
sqlite3_free(key as *mut libc::c_void);
|
||||
}
|
||||
let key = format!("{}addr", prefix);
|
||||
let addr = dc_sqlite3_get_config(context, sql, key, None)
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
pub unsafe fn dc_loginparam_get_readable(loginparam: *const dc_loginparam_t) -> *mut libc::c_char {
|
||||
let unset: *const libc::c_char = b"0\x00" as *const u8 as *const libc::c_char;
|
||||
let pw: *const libc::c_char = b"***\x00" as *const u8 as *const libc::c_char;
|
||||
if loginparam.is_null() {
|
||||
return dc_strdup(0 as *const libc::c_char);
|
||||
let key = format!("{}mail_server", prefix);
|
||||
let mail_server = dc_sqlite3_get_config(context, sql, key, None).unwrap_or_default();
|
||||
|
||||
let key = format!("{}mail_port", prefix);
|
||||
let mail_port = dc_sqlite3_get_config_int(context, sql, key, 0);
|
||||
|
||||
let key = format!("{}mail_user", prefix);
|
||||
let mail_user = dc_sqlite3_get_config(context, sql, key, None).unwrap_or_default();
|
||||
|
||||
let key = format!("{}mail_pw", prefix);
|
||||
let mail_pw = dc_sqlite3_get_config(context, sql, key, None).unwrap_or_default();
|
||||
|
||||
let key = format!("{}send_server", prefix);
|
||||
let send_server = dc_sqlite3_get_config(context, sql, key, None).unwrap_or_default();
|
||||
|
||||
let key = format!("{}send_port", prefix);
|
||||
let send_port = dc_sqlite3_get_config_int(context, sql, key, 0);
|
||||
|
||||
let key = format!("{}send_user", prefix);
|
||||
let send_user = dc_sqlite3_get_config(context, sql, key, None).unwrap_or_default();
|
||||
|
||||
let key = format!("{}send_pw", prefix);
|
||||
let send_pw = dc_sqlite3_get_config(context, sql, key, None).unwrap_or_default();
|
||||
|
||||
let key = format!("{}server_flags", prefix);
|
||||
let server_flags = dc_sqlite3_get_config_int(context, sql, key, 0);
|
||||
|
||||
dc_loginparam_t {
|
||||
addr: addr.to_string(),
|
||||
mail_server,
|
||||
mail_user,
|
||||
mail_pw,
|
||||
mail_port,
|
||||
send_server,
|
||||
send_user,
|
||||
send_pw,
|
||||
send_port,
|
||||
server_flags,
|
||||
}
|
||||
let flags_readable: *mut libc::c_char = get_readable_flags((*loginparam).server_flags);
|
||||
let ret: *mut libc::c_char = dc_mprintf(
|
||||
b"%s %s:%s:%s:%i %s:%s:%s:%i %s\x00" as *const u8 as *const libc::c_char,
|
||||
if !(*loginparam).addr.is_null() {
|
||||
(*loginparam).addr
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
if !(*loginparam).mail_user.is_null() {
|
||||
(*loginparam).mail_user
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
if !(*loginparam).mail_pw.is_null() {
|
||||
}
|
||||
|
||||
pub fn dc_loginparam_write(
|
||||
context: &Context,
|
||||
loginparam: &dc_loginparam_t,
|
||||
sql: &SQLite,
|
||||
prefix: impl AsRef<str>,
|
||||
) {
|
||||
let prefix = prefix.as_ref();
|
||||
|
||||
let key = format!("{}addr", prefix);
|
||||
dc_sqlite3_set_config(context, sql, key, Some(&loginparam.addr));
|
||||
|
||||
let key = format!("{}mail_server", prefix);
|
||||
dc_sqlite3_set_config(context, sql, key, Some(&loginparam.mail_server));
|
||||
|
||||
let key = format!("{}mail_port", prefix);
|
||||
dc_sqlite3_set_config_int(context, sql, key, loginparam.mail_port);
|
||||
|
||||
let key = format!("{}mail_user", prefix);
|
||||
dc_sqlite3_set_config(context, sql, key, Some(&loginparam.mail_user));
|
||||
|
||||
let key = format!("{}mail_pw", prefix);
|
||||
dc_sqlite3_set_config(context, sql, key, Some(&loginparam.mail_pw));
|
||||
|
||||
let key = format!("{}send_server", prefix);
|
||||
dc_sqlite3_set_config(context, sql, key, Some(&loginparam.send_server));
|
||||
|
||||
let key = format!("{}send_port", prefix);
|
||||
dc_sqlite3_set_config_int(context, sql, key, loginparam.send_port);
|
||||
|
||||
let key = format!("{}send_user", prefix);
|
||||
dc_sqlite3_set_config(context, sql, key, Some(&loginparam.send_user));
|
||||
|
||||
let key = format!("{}send_pw", prefix);
|
||||
dc_sqlite3_set_config(context, sql, key, Some(&loginparam.send_pw));
|
||||
|
||||
let key = format!("{}server_flags", prefix);
|
||||
dc_sqlite3_set_config_int(context, sql, key, loginparam.server_flags);
|
||||
}
|
||||
|
||||
fn unset_empty(s: &String) -> Cow<String> {
|
||||
if s.is_empty() {
|
||||
Cow::Owned("unset".to_string())
|
||||
} else {
|
||||
Cow::Borrowed(s)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_loginparam_get_readable(loginparam: &dc_loginparam_t) -> String {
|
||||
let unset = "0";
|
||||
let pw = "***";
|
||||
|
||||
let flags_readable = get_readable_flags(loginparam.server_flags);
|
||||
|
||||
format!(
|
||||
"{} {}:{}:{}:{} {}:{}:{}:{} {}",
|
||||
unset_empty(&loginparam.addr),
|
||||
unset_empty(&loginparam.mail_user),
|
||||
if !loginparam.mail_pw.is_empty() {
|
||||
pw
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
if !(*loginparam).mail_server.is_null() {
|
||||
(*loginparam).mail_server
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
(*loginparam).mail_port,
|
||||
if !(*loginparam).send_user.is_null() {
|
||||
(*loginparam).send_user
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
if !(*loginparam).send_pw.is_null() {
|
||||
unset_empty(&loginparam.mail_server),
|
||||
loginparam.mail_port,
|
||||
unset_empty(&loginparam.send_user),
|
||||
if !loginparam.send_pw.is_empty() {
|
||||
pw
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
if !(*loginparam).send_server.is_null() {
|
||||
(*loginparam).send_server
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
(*loginparam).send_port,
|
||||
unset_empty(&loginparam.send_server),
|
||||
loginparam.send_port,
|
||||
flags_readable,
|
||||
);
|
||||
free(flags_readable as *mut libc::c_void);
|
||||
|
||||
ret
|
||||
)
|
||||
}
|
||||
|
||||
fn get_readable_flags(flags: libc::c_int) -> *mut libc::c_char {
|
||||
fn get_readable_flags(flags: i32) -> String {
|
||||
let mut res = String::new();
|
||||
for bit in 0..31 {
|
||||
if 0 != flags & 1 << bit {
|
||||
let mut flag_added: libc::c_int = 0;
|
||||
let mut flag_added = 0;
|
||||
if 1 << bit == 0x2 {
|
||||
res += "OAUTH2 ";
|
||||
flag_added = 1;
|
||||
@@ -319,5 +203,5 @@ fn get_readable_flags(flags: libc::c_int) -> *mut libc::c_char {
|
||||
res += "0";
|
||||
}
|
||||
|
||||
unsafe { strdup(to_cstring(res).as_ptr()) }
|
||||
res
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ pub unsafe fn dc_mimefactory_empty(mut factory: *mut dc_mimefactory_t) {
|
||||
mmap_string_free((*factory).out);
|
||||
(*factory).out = 0 as *mut MMAPString
|
||||
}
|
||||
(*factory).out_encrypted = 0i32;
|
||||
(*factory).out_encrypted = 0;
|
||||
(*factory).loaded = DC_MF_NOTHING_LOADED;
|
||||
free((*factory).error as *mut libc::c_void);
|
||||
(*factory).error = 0 as *mut libc::c_char;
|
||||
@@ -111,158 +111,184 @@ pub unsafe fn dc_mimefactory_load_msg(
|
||||
mut factory: *mut dc_mimefactory_t,
|
||||
msg_id: uint32_t,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !(factory.is_null() || msg_id <= 9i32 as libc::c_uint || !(*factory).msg.is_null()) {
|
||||
/*call empty() before */
|
||||
let context = (*factory).context;
|
||||
(*factory).recipients_names = clist_new();
|
||||
(*factory).recipients_addr = clist_new();
|
||||
(*factory).msg = dc_msg_new_untyped(context);
|
||||
(*factory).chat = dc_chat_new(context);
|
||||
if dc_msg_load_from_db((*factory).msg, context, msg_id)
|
||||
&& dc_chat_load_from_db((*factory).chat, (*(*factory).msg).chat_id)
|
||||
{
|
||||
load_from(factory);
|
||||
(*factory).req_mdn = 0i32;
|
||||
if 0 != dc_chat_is_self_talk((*factory).chat) {
|
||||
clist_insert_after(
|
||||
(*factory).recipients_names,
|
||||
(*(*factory).recipients_names).last,
|
||||
dc_strdup_keep_null((*factory).from_displayname) as *mut libc::c_void,
|
||||
);
|
||||
clist_insert_after(
|
||||
(*factory).recipients_addr,
|
||||
(*(*factory).recipients_addr).last,
|
||||
dc_strdup((*factory).from_addr) as *mut libc::c_void,
|
||||
);
|
||||
if factory.is_null() || msg_id <= 9 || !(*factory).msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut success = 0;
|
||||
|
||||
/*call empty() before */
|
||||
let context = (*factory).context;
|
||||
(*factory).recipients_names = clist_new();
|
||||
(*factory).recipients_addr = clist_new();
|
||||
(*factory).msg = dc_msg_new_untyped(context);
|
||||
(*factory).chat = dc_chat_new(context);
|
||||
if dc_msg_load_from_db((*factory).msg, context, msg_id)
|
||||
&& dc_chat_load_from_db((*factory).chat, (*(*factory).msg).chat_id)
|
||||
{
|
||||
load_from(factory);
|
||||
(*factory).req_mdn = 0;
|
||||
if 0 != dc_chat_is_self_talk((*factory).chat) {
|
||||
clist_insert_after(
|
||||
(*factory).recipients_names,
|
||||
(*(*factory).recipients_names).last,
|
||||
dc_strdup_keep_null((*factory).from_displayname) as *mut libc::c_void,
|
||||
);
|
||||
clist_insert_after(
|
||||
(*factory).recipients_addr,
|
||||
(*(*factory).recipients_addr).last,
|
||||
dc_strdup((*factory).from_addr) as *mut libc::c_void,
|
||||
);
|
||||
} else {
|
||||
let rows = if let Some(mut stmt) = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"SELECT c.authname, c.addr \
|
||||
FROM chats_contacts cc \
|
||||
LEFT JOIN contacts c ON cc.contact_id=c.id \
|
||||
WHERE cc.chat_id=? AND cc.contact_id>9;",
|
||||
) {
|
||||
stmt.query_map(params![(*(*factory).msg).chat_id as i32], |row| {
|
||||
let authname: String = row.get(0)?;
|
||||
let addr: String = row.get(1)?;
|
||||
Ok((authname, addr))
|
||||
})
|
||||
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>())
|
||||
.ok()
|
||||
} else {
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT c.authname, c.addr FROM chats_contacts cc LEFT JOIN contacts c ON cc.contact_id=c.id WHERE cc.chat_id=? AND cc.contact_id>9;\x00"
|
||||
as *const u8 as
|
||||
*const libc::c_char);
|
||||
sqlite3_bind_int(stmt, 1i32, (*(*factory).msg).chat_id as libc::c_int);
|
||||
while sqlite3_step(stmt) == 100i32 {
|
||||
let authname: *const libc::c_char =
|
||||
sqlite3_column_text(stmt, 0i32) as *const libc::c_char;
|
||||
let addr: *const libc::c_char =
|
||||
sqlite3_column_text(stmt, 1i32) as *const libc::c_char;
|
||||
if clist_search_string_nocase((*factory).recipients_addr, addr) == 0i32 {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(rows) = rows {
|
||||
for (authname, addr) in rows {
|
||||
let addr_c = to_cstring(addr);
|
||||
if clist_search_string_nocase((*factory).recipients_addr, addr_c.as_ptr()) == 0
|
||||
{
|
||||
clist_insert_after(
|
||||
(*factory).recipients_names,
|
||||
(*(*factory).recipients_names).last,
|
||||
(if !authname.is_null() && 0 != *authname.offset(0isize) as libc::c_int
|
||||
{
|
||||
dc_strdup(authname)
|
||||
if !authname.is_empty() {
|
||||
dc_strdup(to_cstring(authname).as_ptr())
|
||||
} else {
|
||||
0 as *mut libc::c_char
|
||||
}) as *mut libc::c_void,
|
||||
} as *mut libc::c_void,
|
||||
);
|
||||
clist_insert_after(
|
||||
(*factory).recipients_addr,
|
||||
(*(*factory).recipients_addr).last,
|
||||
dc_strdup(addr) as *mut libc::c_void,
|
||||
dc_strdup(addr_c.as_ptr()) as *mut libc::c_void,
|
||||
);
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
let command: libc::c_int =
|
||||
dc_param_get_int((*(*factory).msg).param, 'S' as i32, 0i32);
|
||||
if command == 5i32 {
|
||||
let email_to_remove: *mut libc::c_char = dc_param_get(
|
||||
(*(*factory).msg).param,
|
||||
'E' as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let self_addr: *mut libc::c_char = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
b"\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
if !email_to_remove.is_null() && strcasecmp(email_to_remove, self_addr) != 0i32
|
||||
}
|
||||
|
||||
let command = dc_param_get_int((*(*factory).msg).param, 'S' as i32, 0);
|
||||
if command == 5 {
|
||||
let email_to_remove_c = dc_param_get(
|
||||
(*(*factory).msg).param,
|
||||
'E' as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let email_to_remove = to_string(email_to_remove_c);
|
||||
let self_addr =
|
||||
dc_sqlite3_get_config(context, &context.sql, "configured_addr", Some(""))
|
||||
.unwrap_or_default();
|
||||
|
||||
if !email_to_remove.is_empty() && email_to_remove != self_addr {
|
||||
if clist_search_string_nocase((*factory).recipients_addr, email_to_remove_c)
|
||||
== 0
|
||||
{
|
||||
if clist_search_string_nocase((*factory).recipients_addr, email_to_remove)
|
||||
== 0i32
|
||||
{
|
||||
clist_insert_after(
|
||||
(*factory).recipients_names,
|
||||
(*(*factory).recipients_names).last,
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_insert_after(
|
||||
(*factory).recipients_addr,
|
||||
(*(*factory).recipients_addr).last,
|
||||
email_to_remove as *mut libc::c_void,
|
||||
);
|
||||
}
|
||||
clist_insert_after(
|
||||
(*factory).recipients_names,
|
||||
(*(*factory).recipients_names).last,
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_insert_after(
|
||||
(*factory).recipients_addr,
|
||||
(*(*factory).recipients_addr).last,
|
||||
email_to_remove_c as *mut libc::c_void,
|
||||
);
|
||||
}
|
||||
free(self_addr as *mut libc::c_void);
|
||||
}
|
||||
if command != 6i32
|
||||
&& command != 7i32
|
||||
&& 0 != dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"mdns_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
)
|
||||
{
|
||||
(*factory).req_mdn = 1i32
|
||||
}
|
||||
}
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1i32, (*(*factory).msg).id as libc::c_int);
|
||||
if sqlite3_step(stmt) == 100i32 {
|
||||
(*factory).in_reply_to =
|
||||
dc_strdup(sqlite3_column_text(stmt, 0i32) as *const libc::c_char);
|
||||
(*factory).references =
|
||||
dc_strdup(sqlite3_column_text(stmt, 1i32) as *const libc::c_char)
|
||||
if command != 6
|
||||
&& command != 7
|
||||
&& 0 != dc_sqlite3_get_config_int(context, &context.sql, "mdns_enabled", 1)
|
||||
{
|
||||
(*factory).req_mdn = 1
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = 0 as *mut sqlite3_stmt;
|
||||
success = 1i32;
|
||||
(*factory).loaded = DC_MF_MSG_LOADED;
|
||||
(*factory).timestamp = (*(*factory).msg).timestamp_sort;
|
||||
(*factory).rfc724_mid = dc_strdup((*(*factory).msg).rfc724_mid)
|
||||
}
|
||||
if 0 != success {
|
||||
(*factory).increation = dc_msg_is_increation((*factory).msg)
|
||||
|
||||
let row = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?",
|
||||
)
|
||||
.and_then(|mut stmt| {
|
||||
stmt.query_row(params![(*(*factory).msg).id as i32], |row| {
|
||||
let in_reply_to: String = row.get(0)?;
|
||||
let references: String = row.get(1)?;
|
||||
|
||||
Ok((in_reply_to, references))
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
if let Some((in_reply_to, references)) = row {
|
||||
(*factory).in_reply_to = dc_strdup(to_cstring(in_reply_to).as_ptr());
|
||||
(*factory).references = dc_strdup(to_cstring(references).as_ptr());
|
||||
}
|
||||
|
||||
success = 1;
|
||||
(*factory).loaded = DC_MF_MSG_LOADED;
|
||||
(*factory).timestamp = (*(*factory).msg).timestamp_sort;
|
||||
(*factory).rfc724_mid = dc_strdup((*(*factory).msg).rfc724_mid)
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
return success;
|
||||
if 0 != success {
|
||||
(*factory).increation = dc_msg_is_increation((*factory).msg)
|
||||
}
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
unsafe fn load_from(mut factory: *mut dc_mimefactory_t) {
|
||||
(*factory).from_addr = dc_sqlite3_get_config(
|
||||
(*factory).context,
|
||||
&(*factory).context.sql,
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
(*factory).from_addr = strdup(
|
||||
to_cstring(
|
||||
dc_sqlite3_get_config(
|
||||
(*factory).context,
|
||||
&mut (*factory).context.sql,
|
||||
"configured_addr",
|
||||
None,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.as_ptr(),
|
||||
);
|
||||
(*factory).from_displayname = dc_sqlite3_get_config(
|
||||
(*factory).context,
|
||||
&(*factory).context.sql,
|
||||
b"displayname\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
(*factory).from_displayname = strdup(
|
||||
to_cstring(
|
||||
dc_sqlite3_get_config(
|
||||
(*factory).context,
|
||||
&mut (*factory).context.sql,
|
||||
"displayname",
|
||||
None,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.as_ptr(),
|
||||
);
|
||||
(*factory).selfstatus = dc_sqlite3_get_config(
|
||||
(*factory).context,
|
||||
&(*factory).context.sql,
|
||||
b"selfstatus\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
(*factory).selfstatus = strdup(
|
||||
to_cstring(
|
||||
dc_sqlite3_get_config(
|
||||
(*factory).context,
|
||||
&mut (*factory).context.sql,
|
||||
"selfstatus",
|
||||
None,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.as_ptr(),
|
||||
);
|
||||
if (*factory).selfstatus.is_null() {
|
||||
(*factory).selfstatus = dc_stock_str((*factory).context, 13i32)
|
||||
(*factory).selfstatus = dc_stock_str((*factory).context, 13)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -270,61 +296,63 @@ pub unsafe fn dc_mimefactory_load_mdn(
|
||||
mut factory: *mut dc_mimefactory_t,
|
||||
msg_id: uint32_t,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t;
|
||||
if !factory.is_null() {
|
||||
(*factory).recipients_names = clist_new();
|
||||
(*factory).recipients_addr = clist_new();
|
||||
(*factory).msg = dc_msg_new_untyped((*factory).context);
|
||||
if !(0
|
||||
== dc_sqlite3_get_config_int(
|
||||
(*factory).context,
|
||||
if factory.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut success = 0;
|
||||
let mut contact = 0 as *mut dc_contact_t;
|
||||
|
||||
(*factory).recipients_names = clist_new();
|
||||
(*factory).recipients_addr = clist_new();
|
||||
(*factory).msg = dc_msg_new_untyped((*factory).context);
|
||||
if 0 != dc_sqlite3_get_config_int(
|
||||
(*factory).context,
|
||||
&(*factory).context.sql,
|
||||
"mdns_enabled",
|
||||
1,
|
||||
) {
|
||||
// MDNs not enabled - check this is late, in the job. the use may have changed its choice while offline ...
|
||||
contact = dc_contact_new((*factory).context);
|
||||
if !(!dc_msg_load_from_db((*factory).msg, (*factory).context, msg_id)
|
||||
|| !dc_contact_load_from_db(
|
||||
contact,
|
||||
&(*factory).context.sql,
|
||||
b"mdns_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
(*(*factory).msg).from_id,
|
||||
))
|
||||
{
|
||||
/* MDNs not enabled - check this is late, in the job. the use may have changed its choice while offline ... */
|
||||
contact = dc_contact_new((*factory).context);
|
||||
if !(!dc_msg_load_from_db((*factory).msg, (*factory).context, msg_id)
|
||||
|| !dc_contact_load_from_db(
|
||||
contact,
|
||||
&(*factory).context.sql,
|
||||
(*(*factory).msg).from_id,
|
||||
))
|
||||
{
|
||||
if !(0 != (*contact).blocked || (*(*factory).msg).chat_id <= 9i32 as libc::c_uint) {
|
||||
/* Do not send MDNs trash etc.; chats.blocked is already checked by the caller in dc_markseen_msgs() */
|
||||
if !((*(*factory).msg).from_id <= 9i32 as libc::c_uint) {
|
||||
clist_insert_after(
|
||||
(*factory).recipients_names,
|
||||
(*(*factory).recipients_names).last,
|
||||
(if !(*contact).authname.is_null()
|
||||
&& 0 != *(*contact).authname.offset(0isize) as libc::c_int
|
||||
{
|
||||
dc_strdup((*contact).authname)
|
||||
} else {
|
||||
0 as *mut libc::c_char
|
||||
}) as *mut libc::c_void,
|
||||
);
|
||||
clist_insert_after(
|
||||
(*factory).recipients_addr,
|
||||
(*(*factory).recipients_addr).last,
|
||||
dc_strdup((*contact).addr) as *mut libc::c_void,
|
||||
);
|
||||
load_from(factory);
|
||||
(*factory).timestamp = dc_create_smeared_timestamp((*factory).context);
|
||||
(*factory).rfc724_mid = dc_create_outgoing_rfc724_mid(
|
||||
0 as *const libc::c_char,
|
||||
(*factory).from_addr,
|
||||
);
|
||||
success = 1i32;
|
||||
(*factory).loaded = DC_MF_MDN_LOADED
|
||||
}
|
||||
if !(0 != (*contact).blocked || (*(*factory).msg).chat_id <= 9 as libc::c_uint) {
|
||||
// Do not send MDNs trash etc.; chats.blocked is already checked by the caller in dc_markseen_msgs()
|
||||
if !((*(*factory).msg).from_id <= 9 as libc::c_uint) {
|
||||
clist_insert_after(
|
||||
(*factory).recipients_names,
|
||||
(*(*factory).recipients_names).last,
|
||||
(if !(*contact).authname.is_null()
|
||||
&& 0 != *(*contact).authname.offset(0isize) as libc::c_int
|
||||
{
|
||||
dc_strdup((*contact).authname)
|
||||
} else {
|
||||
0 as *mut libc::c_char
|
||||
}) as *mut libc::c_void,
|
||||
);
|
||||
clist_insert_after(
|
||||
(*factory).recipients_addr,
|
||||
(*(*factory).recipients_addr).last,
|
||||
dc_strdup((*contact).addr) as *mut libc::c_void,
|
||||
);
|
||||
load_from(factory);
|
||||
(*factory).timestamp = dc_create_smeared_timestamp((*factory).context);
|
||||
(*factory).rfc724_mid = dc_create_outgoing_rfc724_mid(
|
||||
0 as *const libc::c_char,
|
||||
(*factory).from_addr,
|
||||
);
|
||||
success = 1;
|
||||
(*factory).loaded = DC_MF_MDN_LOADED
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dc_contact_unref(contact);
|
||||
|
||||
success
|
||||
@@ -339,15 +367,15 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
let mut message_text: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut message_text2: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut subject_str: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut afwd_email: libc::c_int = 0i32;
|
||||
let mut col: libc::c_int = 0i32;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut parts: libc::c_int = 0i32;
|
||||
let mut e2ee_guaranteed: libc::c_int = 0i32;
|
||||
let mut min_verified: libc::c_int = 0i32;
|
||||
let mut afwd_email: libc::c_int = 0;
|
||||
let mut col: libc::c_int = 0;
|
||||
let mut success: libc::c_int = 0;
|
||||
let mut parts: libc::c_int = 0;
|
||||
let mut e2ee_guaranteed: libc::c_int = 0;
|
||||
let mut min_verified: libc::c_int = 0;
|
||||
// 1=add Autocrypt-header (needed eg. for handshaking), 2=no Autocrypte-header (used for MDN)
|
||||
let mut force_plaintext: libc::c_int = 0i32;
|
||||
let mut do_gossip: libc::c_int = 0i32;
|
||||
let mut force_plaintext: libc::c_int = 0;
|
||||
let mut do_gossip: libc::c_int = 0;
|
||||
let mut grpimage: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut e2ee_helper = dc_e2ee_helper_t {
|
||||
encryption_successfull: 0,
|
||||
@@ -382,7 +410,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
let mut to: *mut mailimf_address_list = 0 as *mut mailimf_address_list;
|
||||
if !(*factory).recipients_names.is_null()
|
||||
&& !(*factory).recipients_addr.is_null()
|
||||
&& (*(*factory).recipients_addr).count > 0i32
|
||||
&& (*(*factory).recipients_addr).count > 0
|
||||
{
|
||||
let mut iter1: *mut clistiter;
|
||||
let mut iter2: *mut clistiter;
|
||||
@@ -505,7 +533,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
let msg: *mut dc_msg_t = (*factory).msg;
|
||||
let mut meta_part: *mut mailmime = 0 as *mut mailmime;
|
||||
let mut placeholdertext: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if (*chat).type_0 == 130i32 {
|
||||
if (*chat).type_0 == 130 {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
@@ -513,23 +541,23 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
strdup(b"1\x00" as *const u8 as *const libc::c_char),
|
||||
),
|
||||
);
|
||||
force_plaintext = 0i32;
|
||||
e2ee_guaranteed = 1i32;
|
||||
min_verified = 2i32
|
||||
force_plaintext = 0;
|
||||
e2ee_guaranteed = 1;
|
||||
min_verified = 2
|
||||
} else {
|
||||
force_plaintext = dc_param_get_int((*(*factory).msg).param, 'u' as i32, 0i32);
|
||||
if force_plaintext == 0i32 {
|
||||
e2ee_guaranteed = dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0i32)
|
||||
force_plaintext = dc_param_get_int((*(*factory).msg).param, 'u' as i32, 0);
|
||||
if force_plaintext == 0 {
|
||||
e2ee_guaranteed = dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0)
|
||||
}
|
||||
}
|
||||
if (*chat).gossiped_timestamp == 0
|
||||
|| ((*chat).gossiped_timestamp + (2 * 24 * 60 * 60)) < time()
|
||||
{
|
||||
do_gossip = 1i32
|
||||
do_gossip = 1
|
||||
}
|
||||
/* build header etc. */
|
||||
let command: libc::c_int = dc_param_get_int((*msg).param, 'S' as i32, 0i32);
|
||||
if (*chat).type_0 == 120i32 || (*chat).type_0 == 130i32 {
|
||||
let command: libc::c_int = dc_param_get_int((*msg).param, 'S' as i32, 0);
|
||||
if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
@@ -544,7 +572,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
dc_encode_header_words((*chat).name),
|
||||
),
|
||||
);
|
||||
if command == 5i32 {
|
||||
if command == 5 {
|
||||
let email_to_remove: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
|
||||
if !email_to_remove.is_null() {
|
||||
@@ -559,8 +587,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if command == 4i32 {
|
||||
do_gossip = 1i32;
|
||||
} else if command == 4 {
|
||||
do_gossip = 1;
|
||||
let email_to_add: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
|
||||
if !email_to_add.is_null() {
|
||||
@@ -576,10 +604,10 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
);
|
||||
grpimage = dc_param_get((*chat).param, 'i' as i32, 0 as *const libc::c_char)
|
||||
}
|
||||
if 0 != dc_param_get_int((*msg).param, 'F' as i32, 0i32) & 0x1i32 {
|
||||
if 0 != dc_param_get_int((*msg).param, 'F' as i32, 0) & 0x1 {
|
||||
dc_log_info(
|
||||
(*msg).context,
|
||||
0i32,
|
||||
0,
|
||||
b"sending secure-join message \'%s\' >>>>>>>>>>>>>>>>>>>>>>>>>\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
b"vg-member-added\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -592,7 +620,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if command == 2i32 {
|
||||
} else if command == 2 {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
@@ -606,7 +634,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if command == 3i32 {
|
||||
} else if command == 3 {
|
||||
grpimage = dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
|
||||
if grpimage.is_null() {
|
||||
mailimf_fields_add(
|
||||
@@ -619,7 +647,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
}
|
||||
}
|
||||
}
|
||||
if command == 8i32 {
|
||||
if command == 8 {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
@@ -630,7 +658,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
),
|
||||
);
|
||||
}
|
||||
if command == 6i32 {
|
||||
if command == 6 {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
@@ -638,15 +666,15 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
strdup(b"v1\x00" as *const u8 as *const libc::c_char),
|
||||
),
|
||||
);
|
||||
placeholdertext = dc_stock_str((*factory).context, 43i32)
|
||||
placeholdertext = dc_stock_str((*factory).context, 43)
|
||||
}
|
||||
if command == 7i32 {
|
||||
if command == 7 {
|
||||
let step: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
|
||||
if !step.is_null() {
|
||||
dc_log_info(
|
||||
(*msg).context,
|
||||
0i32,
|
||||
0,
|
||||
b"sending secure-join message \'%s\' >>>>>>>>>>>>>>>>>>>>>>>>>\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
step,
|
||||
@@ -667,12 +695,12 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
if strcmp(
|
||||
step,
|
||||
b"vg-request-with-auth\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
) == 0
|
||||
|| strcmp(
|
||||
step,
|
||||
b"vc-request-with-auth\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
) == 0i32
|
||||
) == 0
|
||||
{
|
||||
strdup(
|
||||
b"Secure-Join-Auth\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -718,7 +746,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
}
|
||||
if !grpimage.is_null() {
|
||||
let mut meta: *mut dc_msg_t = dc_msg_new_untyped((*factory).context);
|
||||
(*meta).type_0 = 20i32;
|
||||
(*meta).type_0 = 20;
|
||||
dc_param_set((*meta).param, 'f' as i32, grpimage);
|
||||
let mut filename_as_sent: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
meta_part = build_body_file(
|
||||
@@ -737,8 +765,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
}
|
||||
dc_msg_unref(meta);
|
||||
}
|
||||
if (*msg).type_0 == 41i32 || (*msg).type_0 == 40i32 || (*msg).type_0 == 50i32 {
|
||||
if (*msg).type_0 == 41i32 {
|
||||
if (*msg).type_0 == 41 || (*msg).type_0 == 40 || (*msg).type_0 == 50 {
|
||||
if (*msg).type_0 == 41 {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
@@ -747,8 +775,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
),
|
||||
);
|
||||
}
|
||||
let duration_ms: libc::c_int = dc_param_get_int((*msg).param, 'd' as i32, 0i32);
|
||||
if duration_ms > 0i32 {
|
||||
let duration_ms: libc::c_int = dc_param_get_int((*msg).param, 'd' as i32, 0);
|
||||
if duration_ms > 0 {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
@@ -813,18 +841,18 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
free(fwdhint as *mut libc::c_void);
|
||||
free(placeholdertext as *mut libc::c_void);
|
||||
/* add attachment part */
|
||||
if (*msg).type_0 == 20i32
|
||||
|| (*msg).type_0 == 21i32
|
||||
|| (*msg).type_0 == 40i32
|
||||
|| (*msg).type_0 == 41i32
|
||||
|| (*msg).type_0 == 50i32
|
||||
|| (*msg).type_0 == 60i32
|
||||
if (*msg).type_0 == 20
|
||||
|| (*msg).type_0 == 21
|
||||
|| (*msg).type_0 == 40
|
||||
|| (*msg).type_0 == 41
|
||||
|| (*msg).type_0 == 50
|
||||
|| (*msg).type_0 == 60
|
||||
{
|
||||
if 0 == is_file_size_okay(msg) {
|
||||
let error: *mut libc::c_char = dc_mprintf(
|
||||
b"Message exceeds the recommended %i MB.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
24i32 * 1024i32 * 1024i32 / 4i32 * 3i32 / 1000i32 / 1000i32,
|
||||
24 * 1024 * 1024 / 4 * 3 / 1000 / 1000,
|
||||
);
|
||||
set_error(factory, error);
|
||||
free(error as *mut libc::c_void);
|
||||
@@ -844,7 +872,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
match current_block {
|
||||
11328123142868406523 => {}
|
||||
_ => {
|
||||
if parts == 0i32 {
|
||||
if parts == 0 {
|
||||
set_error(
|
||||
factory,
|
||||
b"Empty message.\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -887,8 +915,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
}
|
||||
}
|
||||
|
||||
if 0 != dc_is_sending_locations_to_chat((*msg).context, (*msg).chat_id) {
|
||||
let mut last_added_location_id: uint32_t = 0i32 as uint32_t;
|
||||
if dc_is_sending_locations_to_chat((*msg).context, (*msg).chat_id) {
|
||||
let mut last_added_location_id: uint32_t = 0 as uint32_t;
|
||||
let kml_file: *mut libc::c_char = dc_get_location_kml(
|
||||
(*msg).context,
|
||||
(*msg).chat_id,
|
||||
@@ -943,12 +971,12 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
mailmime_add_part(message, multipart);
|
||||
let p1: *mut libc::c_char;
|
||||
let p2: *mut libc::c_char;
|
||||
if 0 != dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0i32) {
|
||||
p1 = dc_stock_str((*factory).context, 24i32)
|
||||
if 0 != dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0) {
|
||||
p1 = dc_stock_str((*factory).context, 24)
|
||||
} else {
|
||||
p1 = dc_msg_get_summarytext((*factory).msg, 32i32)
|
||||
p1 = dc_msg_get_summarytext((*factory).msg, 32)
|
||||
}
|
||||
p2 = dc_stock_str_repl_string((*factory).context, 32i32, p1);
|
||||
p2 = dc_stock_str_repl_string((*factory).context, 32, p1);
|
||||
message_text = dc_mprintf(b"%s\r\n\x00" as *const u8 as *const libc::c_char, p2);
|
||||
free(p2 as *mut libc::c_void);
|
||||
free(p1 as *mut libc::c_void);
|
||||
@@ -968,7 +996,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
let mach_mime_part: *mut mailmime = mailmime_new_empty(content_type_0, mime_fields_0);
|
||||
mailmime_set_body_text(mach_mime_part, message_text2, strlen(message_text2));
|
||||
mailmime_add_part(multipart, mach_mime_part);
|
||||
force_plaintext = 2i32;
|
||||
force_plaintext = 2;
|
||||
current_block = 9952640327414195044;
|
||||
} else {
|
||||
set_error(
|
||||
@@ -983,7 +1011,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
if (*factory).loaded as libc::c_uint
|
||||
== DC_MF_MDN_LOADED as libc::c_int as libc::c_uint
|
||||
{
|
||||
let e: *mut libc::c_char = dc_stock_str((*factory).context, 31i32);
|
||||
let e: *mut libc::c_char = dc_stock_str((*factory).context, 31);
|
||||
subject_str =
|
||||
dc_mprintf(b"Chat: %s\x00" as *const u8 as *const libc::c_char, e);
|
||||
free(e as *mut libc::c_void);
|
||||
@@ -1019,7 +1047,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
0 as *mut mailimf_optional_field,
|
||||
),
|
||||
);
|
||||
if force_plaintext != 2i32 {
|
||||
if force_plaintext != 2 {
|
||||
dc_e2ee_encrypt(
|
||||
(*factory).context,
|
||||
(*factory).recipients_addr,
|
||||
@@ -1032,14 +1060,14 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
);
|
||||
}
|
||||
if 0 != e2ee_helper.encryption_successfull {
|
||||
(*factory).out_encrypted = 1i32;
|
||||
(*factory).out_encrypted = 1;
|
||||
if 0 != do_gossip {
|
||||
(*factory).out_gossiped = 1i32
|
||||
(*factory).out_gossiped = 1
|
||||
}
|
||||
}
|
||||
(*factory).out = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
mailmime_write_mem((*factory).out, &mut col, message);
|
||||
success = 1i32
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1063,15 +1091,15 @@ unsafe fn get_subject(
|
||||
let context = (*chat).context;
|
||||
let ret: *mut libc::c_char;
|
||||
let raw_subject: *mut libc::c_char =
|
||||
dc_msg_get_summarytext_by_raw((*msg).type_0, (*msg).text, (*msg).param, 32i32, context);
|
||||
dc_msg_get_summarytext_by_raw((*msg).type_0, (*msg).text, (*msg).param, 32, context);
|
||||
let fwd: *const libc::c_char = if 0 != afwd_email {
|
||||
b"Fwd: \x00" as *const u8 as *const libc::c_char
|
||||
} else {
|
||||
b"\x00" as *const u8 as *const libc::c_char
|
||||
};
|
||||
if dc_param_get_int((*msg).param, 'S' as i32, 0i32) == 6i32 {
|
||||
ret = dc_stock_str(context, 42i32)
|
||||
} else if (*chat).type_0 == 120i32 || (*chat).type_0 == 130i32 {
|
||||
if dc_param_get_int((*msg).param, 'S' as i32, 0) == 6 {
|
||||
ret = dc_stock_str(context, 42)
|
||||
} else if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
|
||||
ret = dc_mprintf(
|
||||
b"Chat: %s: %s%s\x00" as *const u8 as *const libc::c_char,
|
||||
(*chat).name,
|
||||
@@ -1135,7 +1163,7 @@ unsafe fn build_body_file(
|
||||
let mut filename_to_send: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut filename_encoded: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !pathNfilename.is_null() {
|
||||
if (*msg).type_0 == 41i32 {
|
||||
if (*msg).type_0 == 41 {
|
||||
let ts = chrono::Utc.timestamp((*msg).timestamp_sort as i64, 0);
|
||||
|
||||
let suffix = if !suffix.is_null() {
|
||||
@@ -1147,9 +1175,9 @@ unsafe fn build_body_file(
|
||||
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
|
||||
.to_string();
|
||||
filename_to_send = strdup(to_cstring(res).as_ptr());
|
||||
} else if (*msg).type_0 == 40i32 {
|
||||
} else if (*msg).type_0 == 40 {
|
||||
filename_to_send = dc_get_filename(pathNfilename)
|
||||
} else if (*msg).type_0 == 20i32 || (*msg).type_0 == 21i32 {
|
||||
} else if (*msg).type_0 == 20 || (*msg).type_0 == 21 {
|
||||
if base_name.is_null() {
|
||||
base_name = b"image\x00" as *const u8 as *const libc::c_char
|
||||
}
|
||||
@@ -1162,7 +1190,7 @@ unsafe fn build_body_file(
|
||||
b"dat\x00" as *const u8 as *const libc::c_char
|
||||
},
|
||||
)
|
||||
} else if (*msg).type_0 == 50i32 {
|
||||
} else if (*msg).type_0 == 50 {
|
||||
filename_to_send = dc_mprintf(
|
||||
b"video.%s\x00" as *const u8 as *const libc::c_char,
|
||||
if !suffix.is_null() {
|
||||
@@ -1178,14 +1206,14 @@ unsafe fn build_body_file(
|
||||
if suffix.is_null() {
|
||||
mimetype =
|
||||
dc_strdup(b"application/octet-stream\x00" as *const u8 as *const libc::c_char)
|
||||
} else if strcmp(suffix, b"png\x00" as *const u8 as *const libc::c_char) == 0i32 {
|
||||
} else if strcmp(suffix, b"png\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
mimetype = dc_strdup(b"image/png\x00" as *const u8 as *const libc::c_char)
|
||||
} else if strcmp(suffix, b"jpg\x00" as *const u8 as *const libc::c_char) == 0i32
|
||||
|| strcmp(suffix, b"jpeg\x00" as *const u8 as *const libc::c_char) == 0i32
|
||||
|| strcmp(suffix, b"jpe\x00" as *const u8 as *const libc::c_char) == 0i32
|
||||
} else if strcmp(suffix, b"jpg\x00" as *const u8 as *const libc::c_char) == 0
|
||||
|| strcmp(suffix, b"jpeg\x00" as *const u8 as *const libc::c_char) == 0
|
||||
|| strcmp(suffix, b"jpe\x00" as *const u8 as *const libc::c_char) == 0
|
||||
{
|
||||
mimetype = dc_strdup(b"image/jpeg\x00" as *const u8 as *const libc::c_char)
|
||||
} else if strcmp(suffix, b"gif\x00" as *const u8 as *const libc::c_char) == 0i32 {
|
||||
} else if strcmp(suffix, b"gif\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
mimetype = dc_strdup(b"image/gif\x00" as *const u8 as *const libc::c_char)
|
||||
} else {
|
||||
mimetype =
|
||||
@@ -1228,7 +1256,7 @@ unsafe fn build_body_file(
|
||||
0 as *mut libc::c_char,
|
||||
0 as *mut libc::c_char,
|
||||
0 as *mut libc::c_char,
|
||||
0i32 as size_t,
|
||||
0 as size_t,
|
||||
mailmime_parameter_new(
|
||||
strdup(
|
||||
b"filename*\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -1285,12 +1313,12 @@ unsafe fn build_body_file(
|
||||
******************************************************************************/
|
||||
|
||||
unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> libc::c_int {
|
||||
let mut file_size_okay: libc::c_int = 1i32;
|
||||
let mut file_size_okay: libc::c_int = 1;
|
||||
let pathNfilename: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'f' as i32, 0 as *const libc::c_char);
|
||||
let bytes: uint64_t = dc_get_filebytes((*msg).context, pathNfilename);
|
||||
if bytes > (49i32 * 1024i32 * 1024i32 / 4i32 * 3i32) as libc::c_ulonglong {
|
||||
file_size_okay = 0i32
|
||||
if bytes > (49 * 1024 * 1024 / 4 * 3) as libc::c_ulonglong {
|
||||
file_size_okay = 0;
|
||||
}
|
||||
free(pathNfilename as *mut libc::c_void);
|
||||
|
||||
|
||||
@@ -3,43 +3,39 @@ use crate::context::*;
|
||||
use crate::dc_job::*;
|
||||
use crate::dc_msg::*;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::types::*;
|
||||
|
||||
pub unsafe fn dc_do_heuristics_moves(
|
||||
context: &Context,
|
||||
folder: *const libc::c_char,
|
||||
msg_id: uint32_t,
|
||||
) {
|
||||
// for already seen messages, folder may be different from msg->folder
|
||||
let mut msg: *mut dc_msg_t = 0 as *mut dc_msg_t;
|
||||
let stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !(dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql,
|
||||
b"mvbox_move\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
) == 0i32)
|
||||
{
|
||||
if !(0 == dc_is_inbox(context, folder) && 0 == dc_is_sentbox(context, folder)) {
|
||||
msg = dc_msg_new_load(context, msg_id);
|
||||
if !(0 != dc_msg_is_setupmessage(msg)) {
|
||||
// do not move setup messages;
|
||||
// there may be a non-delta device that wants to handle it
|
||||
if 0 != dc_is_mvbox(context, folder) {
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_STAY);
|
||||
} else if 0 != (*msg).is_dc_message {
|
||||
dc_job_add(
|
||||
context,
|
||||
200i32,
|
||||
(*msg).id as libc::c_int,
|
||||
0 as *const libc::c_char,
|
||||
0i32,
|
||||
);
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_MOVING);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub unsafe fn dc_do_heuristics_moves(context: &Context, folder: &str, msg_id: u32) {
|
||||
if dc_sqlite3_get_config_int(context, &context.sql, "mvbox_move", 1) == 0 {
|
||||
return;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if !dc_is_inbox(context, folder) && !dc_is_sentbox(context, folder) {
|
||||
return;
|
||||
}
|
||||
|
||||
let msg = dc_msg_new_load(context, msg_id);
|
||||
if dc_msg_is_setupmessage(msg) {
|
||||
// do not move setup messages;
|
||||
// there may be a non-delta device that wants to handle it
|
||||
dc_msg_unref(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if dc_is_mvbox(context, folder) {
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_STAY);
|
||||
}
|
||||
|
||||
// 1 = dc message, 2 = reply to dc message
|
||||
if 0 != (*msg).is_dc_message {
|
||||
dc_job_add(
|
||||
context,
|
||||
200,
|
||||
(*msg).id as libc::c_int,
|
||||
0 as *const libc::c_char,
|
||||
0,
|
||||
);
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_MOVING);
|
||||
}
|
||||
|
||||
dc_msg_unref(msg);
|
||||
}
|
||||
|
||||
1129
src/dc_msg.rs
1129
src/dc_msg.rs
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
use mmime::mailimf_types::*;
|
||||
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
|
||||
|
||||
use crate::aheader::EncryptPreference;
|
||||
use crate::constants::Event;
|
||||
@@ -28,22 +29,18 @@ pub unsafe fn dc_get_securejoin_qr(
|
||||
context: &Context,
|
||||
group_chat_id: uint32_t,
|
||||
) -> *mut libc::c_char {
|
||||
let current_block: u64;
|
||||
/* =========================================================
|
||||
==== Alice - the inviter side ====
|
||||
==== Step 1 in "Setup verified contact" protocol ====
|
||||
========================================================= */
|
||||
let mut qr: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let self_addr: *mut libc::c_char;
|
||||
let mut self_addr_urlencoded: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut self_name: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut self_name_urlencoded: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut fingerprint: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
|
||||
let mut fingerprint = 0 as *mut libc::c_char;
|
||||
let mut invitenumber: *mut libc::c_char;
|
||||
let mut auth: *mut libc::c_char;
|
||||
let mut chat: *mut Chat = 0 as *mut Chat;
|
||||
let mut group_name: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut group_name_urlencoded: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut chat = 0 as *mut Chat;
|
||||
let mut group_name = 0 as *mut libc::c_char;
|
||||
let mut group_name_urlencoded = 0 as *mut libc::c_char;
|
||||
let mut qr = None;
|
||||
|
||||
dc_ensure_secret_key_exists(context);
|
||||
invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id);
|
||||
@@ -56,110 +53,88 @@ pub unsafe fn dc_get_securejoin_qr(
|
||||
auth = dc_create_id();
|
||||
dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth);
|
||||
}
|
||||
self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if self_addr.is_null() {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
b"Not configured, cannot generate QR code.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
self_name = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"displayname\x00" as *const u8 as *const libc::c_char,
|
||||
b"\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
fingerprint = get_self_fingerprint(context);
|
||||
if !fingerprint.is_null() {
|
||||
self_addr_urlencoded = dc_urlencode(self_addr);
|
||||
self_name_urlencoded = dc_urlencode(self_name);
|
||||
if 0 != group_chat_id {
|
||||
chat = dc_get_chat(context, group_chat_id);
|
||||
if chat.is_null() {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot get QR-code for chat-id %i\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
group_chat_id,
|
||||
);
|
||||
current_block = 9531737720721467826;
|
||||
} else {
|
||||
group_name = dc_chat_get_name(chat);
|
||||
group_name_urlencoded = dc_urlencode(group_name);
|
||||
qr = dc_mprintf(
|
||||
b"OPENPGP4FPR:%s#a=%s&g=%s&x=%s&i=%s&s=%s\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
fingerprint,
|
||||
self_addr_urlencoded,
|
||||
group_name_urlencoded,
|
||||
(*chat).grpid,
|
||||
invitenumber,
|
||||
auth,
|
||||
);
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
} else {
|
||||
qr = dc_mprintf(
|
||||
b"OPENPGP4FPR:%s#a=%s&n=%s&i=%s&s=%s\x00" as *const u8 as *const libc::c_char,
|
||||
fingerprint,
|
||||
self_addr_urlencoded,
|
||||
self_name_urlencoded,
|
||||
invitenumber,
|
||||
auth,
|
||||
);
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
match current_block {
|
||||
9531737720721467826 => {}
|
||||
_ => {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Generated QR code: %s\x00" as *const u8 as *const libc::c_char,
|
||||
qr,
|
||||
);
|
||||
}
|
||||
}
|
||||
let self_addr = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None);
|
||||
|
||||
let cleanup = |fingerprint, chat, group_name, group_name_urlencoded| {
|
||||
free(fingerprint as *mut libc::c_void);
|
||||
free(invitenumber as *mut libc::c_void);
|
||||
free(auth as *mut libc::c_void);
|
||||
dc_chat_unref(chat);
|
||||
free(group_name as *mut libc::c_void);
|
||||
free(group_name_urlencoded as *mut libc::c_void);
|
||||
|
||||
if let Some(qr) = qr {
|
||||
strdup(to_cstring(qr).as_ptr())
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
};
|
||||
|
||||
if self_addr.is_none() {
|
||||
error!(context, 0, "Not configured, cannot generate QR code.",);
|
||||
return cleanup(fingerprint, chat, group_name, group_name_urlencoded);
|
||||
}
|
||||
|
||||
free(self_addr_urlencoded as *mut libc::c_void);
|
||||
free(self_addr as *mut libc::c_void);
|
||||
free(self_name as *mut libc::c_void);
|
||||
free(self_name_urlencoded as *mut libc::c_void);
|
||||
free(fingerprint as *mut libc::c_void);
|
||||
free(invitenumber as *mut libc::c_void);
|
||||
free(auth as *mut libc::c_void);
|
||||
dc_chat_unref(chat);
|
||||
free(group_name as *mut libc::c_void);
|
||||
free(group_name_urlencoded as *mut libc::c_void);
|
||||
return if !qr.is_null() {
|
||||
qr
|
||||
let self_addr = self_addr.unwrap();
|
||||
let self_name = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"displayname",
|
||||
Some(""),
|
||||
)
|
||||
.unwrap();
|
||||
fingerprint = get_self_fingerprint(context);
|
||||
|
||||
if fingerprint.is_null() {
|
||||
return cleanup(fingerprint, chat, group_name, group_name_urlencoded);
|
||||
}
|
||||
|
||||
let self_addr_urlencoded = utf8_percent_encode(&self_addr, DEFAULT_ENCODE_SET).to_string();
|
||||
let self_name_urlencoded = utf8_percent_encode(&self_name, DEFAULT_ENCODE_SET).to_string();
|
||||
|
||||
qr = if 0 != group_chat_id {
|
||||
chat = dc_get_chat(context, group_chat_id);
|
||||
if chat.is_null() {
|
||||
error!(
|
||||
context,
|
||||
0, "Cannot get QR-code for chat-id {}", group_chat_id,
|
||||
);
|
||||
return cleanup(fingerprint, chat, group_name, group_name_urlencoded);
|
||||
}
|
||||
|
||||
group_name = dc_chat_get_name(chat);
|
||||
group_name_urlencoded = dc_urlencode(group_name);
|
||||
|
||||
Some(format!(
|
||||
"OPENPGP4FPR:{}#a={}&g={}&x={}&i={}&s={}",
|
||||
as_str(fingerprint),
|
||||
self_addr_urlencoded,
|
||||
as_str(group_name_urlencoded),
|
||||
as_str((*chat).grpid),
|
||||
as_str(invitenumber),
|
||||
as_str(auth),
|
||||
))
|
||||
} else {
|
||||
dc_strdup(0 as *const libc::c_char)
|
||||
Some(format!(
|
||||
"OPENPGP4FPR:{}#a={}&n={}&i={}&s={}",
|
||||
as_str(fingerprint),
|
||||
self_addr_urlencoded,
|
||||
self_name_urlencoded,
|
||||
as_str(invitenumber),
|
||||
as_str(auth),
|
||||
))
|
||||
};
|
||||
|
||||
info!(context, 0, "Generated QR code: {}", qr.as_ref().unwrap());
|
||||
|
||||
cleanup(fingerprint, chat, group_name, group_name_urlencoded)
|
||||
}
|
||||
|
||||
unsafe fn get_self_fingerprint(context: &Context) -> *mut libc::c_char {
|
||||
let self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if self_addr.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
if let Some(key) = Key::from_self_public(context, self_addr, &context.sql) {
|
||||
return key.fingerprint_c();
|
||||
fn get_self_fingerprint(context: &Context) -> *mut libc::c_char {
|
||||
if let Some(self_addr) = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None) {
|
||||
if let Some(key) = Key::from_self_public(context, self_addr, &context.sql) {
|
||||
return key.fingerprint_c();
|
||||
}
|
||||
}
|
||||
|
||||
std::ptr::null_mut()
|
||||
@@ -443,27 +418,14 @@ pub unsafe fn dc_handle_securejoin_handshake(
|
||||
b"Secure-Join-Invitenumber\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
if invitenumber.is_null() {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Secure-join denied (invitenumber missing).\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
warn!(context, 0, "Secure-join denied (invitenumber missing).",);
|
||||
current_block = 4378276786830486580;
|
||||
} else if dc_token_exists(context, DC_TOKEN_INVITENUMBER, invitenumber) == 0i32 {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Secure-join denied (bad invitenumber).\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else if !dc_token_exists(context, DC_TOKEN_INVITENUMBER, invitenumber) {
|
||||
warn!(context, 0, "Secure-join denied (bad invitenumber).",);
|
||||
current_block = 4378276786830486580;
|
||||
} else {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Secure-join requested.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
info!(context, 0, "Secure-join requested.",);
|
||||
|
||||
context.call_cb(
|
||||
Event::SECUREJOIN_INVITER_PROGRESS,
|
||||
contact_id as uintptr_t,
|
||||
@@ -634,7 +596,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
|
||||
b"Auth not provided.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
current_block = 4378276786830486580;
|
||||
} else if dc_token_exists(context, DC_TOKEN_AUTH, auth_0) == 0i32 {
|
||||
} else if !dc_token_exists(context, DC_TOKEN_AUTH, auth_0) {
|
||||
could_not_establish_secure_connection(
|
||||
context,
|
||||
contact_chat_id,
|
||||
@@ -1047,9 +1009,7 @@ unsafe fn encrypted_and_signed(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_handle_degrade_event(context: &Context, peerstate: &Peerstate) {
|
||||
let stmt;
|
||||
let contact_id: uint32_t;
|
||||
let mut contact_chat_id: uint32_t = 0i32 as uint32_t;
|
||||
let mut contact_chat_id = 0;
|
||||
|
||||
// - we do not issue an warning for DC_DE_ENCRYPTION_PAUSED as this is quite normal
|
||||
// - currently, we do not issue an extra warning for DC_DE_VERIFICATION_LOST - this always comes
|
||||
@@ -1057,38 +1017,35 @@ pub unsafe fn dc_handle_degrade_event(context: &Context, peerstate: &Peerstate)
|
||||
// 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 Some(DegradeEvent::FingerprintChanged) == peerstate.degrade_event {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
let contact_id: i32 = dc_sqlite3_query_row(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let c_addr = peerstate.addr.as_ref().map(to_cstring).unwrap_or_default();
|
||||
|
||||
let c_addr_ptr = if peerstate.addr.is_some() {
|
||||
c_addr.as_ptr()
|
||||
} else {
|
||||
std::ptr::null()
|
||||
};
|
||||
|
||||
sqlite3_bind_text(stmt, 1i32, c_addr_ptr, -1i32, None);
|
||||
sqlite3_step(stmt);
|
||||
contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t;
|
||||
sqlite3_finalize(stmt);
|
||||
if !(contact_id == 0i32 as libc::c_uint) {
|
||||
"SELECT id FROM contacts WHERE addr=?;",
|
||||
params![&peerstate.addr],
|
||||
0,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
if contact_id > 0 {
|
||||
dc_create_or_lookup_nchat_by_contact_id(
|
||||
context,
|
||||
contact_id,
|
||||
2i32,
|
||||
contact_id as u32,
|
||||
2,
|
||||
&mut contact_chat_id,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
let msg = dc_stock_str_repl_string(context, 37i32, c_addr_ptr);
|
||||
let c_addr = peerstate.addr.as_ref().map(to_cstring).unwrap_or_default();
|
||||
let c_addr_ptr = if peerstate.addr.is_some() {
|
||||
c_addr.as_ptr()
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
};
|
||||
let msg = dc_stock_str_repl_string(context, 37, c_addr_ptr);
|
||||
dc_add_device_msg(context, contact_chat_id, msg);
|
||||
free(msg as *mut libc::c_void);
|
||||
context.call_cb(
|
||||
Event::CHAT_MODIFIED,
|
||||
contact_chat_id as uintptr_t,
|
||||
0i32 as uintptr_t,
|
||||
0 as uintptr_t,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
2396
src/dc_sqlite3.rs
2396
src/dc_sqlite3.rs
File diff suppressed because it is too large
Load Diff
@@ -1,76 +1,65 @@
|
||||
use crate::context::Context;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::types::*;
|
||||
use crate::x::strdup;
|
||||
|
||||
// Token namespaces
|
||||
pub type dc_tokennamespc_t = libc::c_uint;
|
||||
pub type dc_tokennamespc_t = usize;
|
||||
pub const DC_TOKEN_AUTH: dc_tokennamespc_t = 110;
|
||||
pub const DC_TOKEN_INVITENUMBER: dc_tokennamespc_t = 100;
|
||||
|
||||
// Functions to read/write token from/to the database. A token is any string associated with a key.
|
||||
pub unsafe fn dc_token_save(
|
||||
|
||||
pub fn dc_token_save(
|
||||
context: &Context,
|
||||
namespc: dc_tokennamespc_t,
|
||||
foreign_id: uint32_t,
|
||||
foreign_id: u32,
|
||||
token: *const libc::c_char,
|
||||
) {
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !token.is_null() {
|
||||
// foreign_id may be 0
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"INSERT INTO tokens (namespc, foreign_id, token, timestamp) VALUES (?, ?, ?, ?);\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1i32, namespc as libc::c_int);
|
||||
sqlite3_bind_int(stmt, 2i32, foreign_id as libc::c_int);
|
||||
sqlite3_bind_text(stmt, 3i32, token, -1i32, None);
|
||||
sqlite3_bind_int64(stmt, 4i32, time() as sqlite3_int64);
|
||||
sqlite3_step(stmt);
|
||||
) -> bool {
|
||||
if token.is_null() {
|
||||
return false;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
// foreign_id may be 0
|
||||
dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"INSERT INTO tokens (namespc, foreign_id, token, timestamp) VALUES (?, ?, ?, ?);",
|
||||
params![namespc as i32, foreign_id as i32, as_str(token), time()],
|
||||
)
|
||||
}
|
||||
pub unsafe fn dc_token_lookup(
|
||||
|
||||
pub fn dc_token_lookup(
|
||||
context: &Context,
|
||||
namespc: dc_tokennamespc_t,
|
||||
foreign_id: uint32_t,
|
||||
foreign_id: u32,
|
||||
) -> *mut libc::c_char {
|
||||
let token: *mut libc::c_char;
|
||||
let stmt: *mut sqlite3_stmt;
|
||||
stmt = dc_sqlite3_prepare(
|
||||
if let Some(token) = dc_sqlite3_query_row::<_, String>(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1i32, namespc as libc::c_int);
|
||||
sqlite3_bind_int(stmt, 2i32, foreign_id as libc::c_int);
|
||||
sqlite3_step(stmt);
|
||||
token = dc_strdup_keep_null(sqlite3_column_text(stmt, 0i32) as *mut libc::c_char);
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
token
|
||||
"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;",
|
||||
params![namespc as i32, foreign_id as i32],
|
||||
0,
|
||||
) {
|
||||
unsafe { strdup(to_cstring(token).as_ptr()) }
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_token_exists(
|
||||
pub fn dc_token_exists(
|
||||
context: &Context,
|
||||
namespc: dc_tokennamespc_t,
|
||||
token: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut exists: libc::c_int = 0i32;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !token.is_null() {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql,
|
||||
b"SELECT id FROM tokens WHERE namespc=? AND token=?;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_int(stmt, 1i32, namespc as libc::c_int);
|
||||
sqlite3_bind_text(stmt, 2i32, token, -1i32, None);
|
||||
exists = (sqlite3_step(stmt) != 0i32) as libc::c_int
|
||||
) -> bool {
|
||||
if token.is_null() {
|
||||
return false;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
return exists;
|
||||
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"SELECT id FROM tokens WHERE namespc=? AND token=?;",
|
||||
)
|
||||
.and_then(|mut stmt| stmt.exists(params![namespc as i32, as_str(token)]).ok())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
197
src/dc_tools.rs
197
src/dc_tools.rs
@@ -1,3 +1,4 @@
|
||||
use std::borrow::Cow;
|
||||
use std::fs;
|
||||
use std::time::SystemTime;
|
||||
|
||||
@@ -343,25 +344,13 @@ pub unsafe fn dc_utf8_strlen(s: *const libc::c_char) -> size_t {
|
||||
j
|
||||
}
|
||||
|
||||
pub unsafe fn dc_truncate_str(buf: *mut libc::c_char, approx_chars: libc::c_int) {
|
||||
if approx_chars > 0
|
||||
&& strlen(buf)
|
||||
> approx_chars.wrapping_add(
|
||||
strlen(b"[...]\x00" as *const u8 as *const libc::c_char) as libc::c_int
|
||||
) as usize
|
||||
{
|
||||
let mut p: *mut libc::c_char = &mut *buf.offset(approx_chars as isize) as *mut libc::c_char;
|
||||
*p = 0i32 as libc::c_char;
|
||||
if !strchr(buf, ' ' as i32).is_null() {
|
||||
while *p.offset(-1i32 as isize) as libc::c_int != ' ' as i32
|
||||
&& *p.offset(-1i32 as isize) as libc::c_int != '\n' as i32
|
||||
{
|
||||
p = p.offset(-1isize);
|
||||
*p = 0i32 as libc::c_char
|
||||
}
|
||||
}
|
||||
strcat(p, b"[...]\x00" as *const u8 as *const libc::c_char);
|
||||
};
|
||||
pub fn dc_truncate_str(buf: &str, approx_chars: usize) -> Cow<str> {
|
||||
let appendix = "[...]";
|
||||
if approx_chars > 0 && buf.len() > approx_chars + appendix.len() {
|
||||
Cow::Owned(format!("{}{}", &buf[..approx_chars], appendix))
|
||||
} else {
|
||||
Cow::Borrowed(buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_truncate_n_unwrap_str(
|
||||
@@ -675,12 +664,15 @@ pub unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
|
||||
|
||||
/* the return value must be free()'d */
|
||||
pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char {
|
||||
let ts = chrono::Utc.timestamp(wanted, 0);
|
||||
let res = ts.format("%Y.%m.%d %H:%M:%S").to_string();
|
||||
|
||||
let res = dc_timestamp_to_str_safe(wanted);
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
}
|
||||
|
||||
pub fn dc_timestamp_to_str_safe(wanted: i64) -> String {
|
||||
let ts = chrono::Utc.timestamp(wanted, 0);
|
||||
ts.format("%Y.%m.%d %H:%M:%S").to_string()
|
||||
}
|
||||
|
||||
pub fn dc_gm2local_offset() -> i64 {
|
||||
let lt = Local::now();
|
||||
((lt.offset().local_minus_utc() / (60 * 60)) * 100) as i64
|
||||
@@ -905,16 +897,23 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut
|
||||
|
||||
/* file tools */
|
||||
pub unsafe fn dc_ensure_no_slash(pathNfilename: *mut libc::c_char) {
|
||||
let path_len: libc::c_int = strlen(pathNfilename) as libc::c_int;
|
||||
if path_len > 0i32 {
|
||||
if *pathNfilename.offset((path_len - 1i32) as isize) as libc::c_int == '/' as i32
|
||||
|| *pathNfilename.offset((path_len - 1i32) as isize) as libc::c_int == '\\' as i32
|
||||
let path_len = strlen(pathNfilename);
|
||||
if path_len > 0 {
|
||||
if *pathNfilename.offset((path_len - 1) as isize) as libc::c_int == '/' as i32
|
||||
|| *pathNfilename.offset((path_len - 1) as isize) as libc::c_int == '\\' as i32
|
||||
{
|
||||
*pathNfilename.offset((path_len - 1i32) as isize) = 0i32 as libc::c_char
|
||||
*pathNfilename.offset((path_len - 1) as isize) = 0 as libc::c_char
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn dc_ensure_no_slash_safe(path: &str) -> &str {
|
||||
if path.ends_with('/') || path.ends_with('\\') {
|
||||
return &path[..path.len() - 1];
|
||||
}
|
||||
path
|
||||
}
|
||||
|
||||
pub unsafe fn dc_validate_filename(filename: *mut libc::c_char) {
|
||||
/* function modifies the given buffer and replaces all characters not valid in filenames by a "-" */
|
||||
let mut p1: *mut libc::c_char = filename;
|
||||
@@ -1256,37 +1255,34 @@ pub unsafe fn dc_write_file(
|
||||
buf: *const libc::c_void,
|
||||
buf_bytes: size_t,
|
||||
) -> libc::c_int {
|
||||
let mut success = 0;
|
||||
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
|
||||
|
||||
if pathNfilename_abs.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let p = std::ffi::CStr::from_ptr(pathNfilename_abs)
|
||||
.to_str()
|
||||
.unwrap();
|
||||
|
||||
let bytes = std::slice::from_raw_parts(buf as *const u8, buf_bytes);
|
||||
|
||||
match fs::write(p, bytes) {
|
||||
Ok(_) => {
|
||||
info!(context, 0, "wrote file {}", as_str(pathNfilename));
|
||||
dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int
|
||||
}
|
||||
|
||||
success = 1;
|
||||
}
|
||||
Err(_err) => {
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
"Cannot write {} bytes to \"{}\".",
|
||||
buf_bytes,
|
||||
as_str(pathNfilename),
|
||||
);
|
||||
}
|
||||
pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef<str>, buf: &[u8]) -> bool {
|
||||
let pathNfilename_abs =
|
||||
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
|
||||
if pathNfilename_abs.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
free(pathNfilename_abs as *mut libc::c_void);
|
||||
let p = as_str(pathNfilename_abs);
|
||||
|
||||
let success = if let Err(_err) = fs::write(p, buf) {
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
"Cannot write {} bytes to \"{}\".",
|
||||
buf.len(),
|
||||
pathNfilename.as_ref(),
|
||||
);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
|
||||
success
|
||||
}
|
||||
|
||||
@@ -1296,44 +1292,43 @@ pub unsafe fn dc_read_file(
|
||||
buf: *mut *mut libc::c_void,
|
||||
buf_bytes: *mut size_t,
|
||||
) -> libc::c_int {
|
||||
let mut success = 0;
|
||||
|
||||
if pathNfilename.is_null() || buf.is_null() || buf_bytes.is_null() {
|
||||
if pathNfilename.is_null() {
|
||||
return 0;
|
||||
}
|
||||
if let Some(mut bytes) = dc_read_file_safe(context, as_str(pathNfilename)) {
|
||||
*buf = &mut bytes[..] as *mut _ as *mut libc::c_void;
|
||||
*buf_bytes = bytes.len();
|
||||
std::mem::forget(bytes);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
*buf = 0 as *mut libc::c_void;
|
||||
*buf_bytes = 0i32 as size_t;
|
||||
|
||||
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
|
||||
pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef<str>) -> Option<Vec<u8>> {
|
||||
let pathNfilename_abs =
|
||||
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
|
||||
if pathNfilename_abs.is_null() {
|
||||
return 0;
|
||||
return None;
|
||||
}
|
||||
|
||||
let p = std::ffi::CStr::from_ptr(pathNfilename_abs)
|
||||
.to_str()
|
||||
.unwrap();
|
||||
|
||||
match fs::read(p) {
|
||||
Ok(mut bytes) => {
|
||||
*buf = &mut bytes[..] as *mut _ as *mut libc::c_void;
|
||||
*buf_bytes = bytes.len();
|
||||
std::mem::forget(bytes);
|
||||
|
||||
success = 1;
|
||||
}
|
||||
let p = as_str(pathNfilename_abs);
|
||||
let res = match fs::read(p) {
|
||||
Ok(bytes) => Some(bytes),
|
||||
Err(_err) => {
|
||||
dc_log_warning(
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
b"Cannot read \"%s\" or file is empty.\x00" as *const u8 as *const libc::c_char,
|
||||
pathNfilename,
|
||||
"Cannot read \"{}\" or file is empty.",
|
||||
pathNfilename.as_ref(),
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
free(pathNfilename_abs as *mut libc::c_void);
|
||||
success
|
||||
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_fine_pathNfilename(
|
||||
@@ -1706,61 +1701,29 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_dc_str_truncate_1() {
|
||||
unsafe {
|
||||
let str: *mut libc::c_char =
|
||||
strdup(b"this is a little test string\x00" as *const u8 as *const libc::c_char);
|
||||
dc_truncate_str(str, 16);
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"this is a [...]"
|
||||
);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
let s = "this is a little test string";
|
||||
assert_eq!(dc_truncate_str(s, 16), "this is a [...]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_str_truncate_2() {
|
||||
unsafe {
|
||||
let str: *mut libc::c_char = strdup(b"1234\x00" as *const u8 as *const libc::c_char);
|
||||
dc_truncate_str(str, 2);
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"1234"
|
||||
);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
assert_eq!(dc_truncate_str("1234", 2), "1234");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_str_truncate_3() {
|
||||
unsafe {
|
||||
let str: *mut libc::c_char = strdup(b"1234567\x00" as *const u8 as *const libc::c_char);
|
||||
dc_truncate_str(str, 1);
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"1[...]"
|
||||
);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
assert_eq!(dc_truncate_str("1234567", 3), "1[...]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_str_truncate_4() {
|
||||
unsafe {
|
||||
let str: *mut libc::c_char = strdup(b"123456\x00" as *const u8 as *const libc::c_char);
|
||||
dc_truncate_str(str, 4);
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"123456"
|
||||
);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
assert_eq!(dc_truncate_str("123456", 4), "123456");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_insert_breaks_1() {
|
||||
unsafe {
|
||||
let str: *mut libc::c_char = dc_insert_breaks(
|
||||
let str = dc_insert_breaks(
|
||||
b"just1234test\x00" as *const u8 as *const libc::c_char,
|
||||
4,
|
||||
b" \x00" as *const u8 as *const libc::c_char,
|
||||
|
||||
74
src/imap.rs
74
src/imap.rs
@@ -7,7 +7,7 @@ use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_loginparam::*;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::dc_tools::{as_str, to_string};
|
||||
use crate::dc_tools::as_str;
|
||||
use crate::oauth2::dc_get_oauth2_access_token;
|
||||
use crate::types::*;
|
||||
|
||||
@@ -507,12 +507,8 @@ impl Imap {
|
||||
cfg.watch_folder = None;
|
||||
}
|
||||
|
||||
pub fn connect(&self, context: &Context, lp: *const dc_loginparam_t) -> libc::c_int {
|
||||
if lp.is_null() {
|
||||
return 0;
|
||||
}
|
||||
let lp = unsafe { *lp };
|
||||
if lp.mail_server.is_null() || lp.mail_user.is_null() || lp.mail_pw.is_null() {
|
||||
pub fn connect(&self, context: &Context, lp: &dc_loginparam_t) -> libc::c_int {
|
||||
if lp.mail_server.is_empty() || lp.mail_user.is_empty() || lp.mail_pw.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -521,19 +517,19 @@ impl Imap {
|
||||
}
|
||||
|
||||
{
|
||||
let addr = as_str(lp.addr);
|
||||
let imap_server = as_str(lp.mail_server);
|
||||
let addr = &lp.addr;
|
||||
let imap_server = &lp.mail_server;
|
||||
let imap_port = lp.mail_port as u16;
|
||||
let imap_user = as_str(lp.mail_user);
|
||||
let imap_pw = as_str(lp.mail_pw);
|
||||
let imap_user = &lp.mail_user;
|
||||
let imap_pw = &lp.mail_pw;
|
||||
let server_flags = lp.server_flags as usize;
|
||||
|
||||
let mut config = self.config.write().unwrap();
|
||||
config.addr = addr.into();
|
||||
config.imap_server = imap_server.into();
|
||||
config.addr = addr.to_string();
|
||||
config.imap_server = imap_server.to_string();
|
||||
config.imap_port = imap_port.into();
|
||||
config.imap_user = imap_user.into();
|
||||
config.imap_pw = imap_pw.into();
|
||||
config.imap_user = imap_user.to_string();
|
||||
config.imap_pw = imap_pw.to_string();
|
||||
config.server_flags = server_flags;
|
||||
}
|
||||
|
||||
@@ -591,8 +587,8 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_watch_folder(&self, watch_folder: *const libc::c_char) {
|
||||
self.config.write().unwrap().watch_folder = Some(to_string(watch_folder));
|
||||
pub fn set_watch_folder(&self, watch_folder: String) {
|
||||
self.config.write().unwrap().watch_folder = Some(watch_folder);
|
||||
}
|
||||
|
||||
pub fn fetch(&self, context: &Context) -> libc::c_int {
|
||||
@@ -838,9 +834,8 @@ impl Imap {
|
||||
.expect("missing message id");
|
||||
|
||||
let message_id_c = CString::new(message_id).unwrap();
|
||||
let folder_c = CString::new(folder.as_ref().to_owned()).unwrap();
|
||||
if 0 == unsafe {
|
||||
(self.precheck_imf)(context, message_id_c.as_ptr(), folder_c.as_ptr(), cur_uid)
|
||||
(self.precheck_imf)(context, message_id_c.as_ptr(), folder.as_ref(), cur_uid)
|
||||
} {
|
||||
// check passed, go fetch the rest
|
||||
if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
|
||||
@@ -993,12 +988,11 @@ impl Imap {
|
||||
|
||||
if !is_deleted && msg.body().is_some() {
|
||||
unsafe {
|
||||
let folder_c = CString::new(folder.as_ref().to_owned()).unwrap();
|
||||
(self.receive_imf)(
|
||||
context,
|
||||
msg.body().unwrap().as_ptr() as *const libc::c_char,
|
||||
msg.body().unwrap().len(),
|
||||
folder_c.as_ptr(),
|
||||
folder.as_ref(),
|
||||
server_uid,
|
||||
flags as u32,
|
||||
);
|
||||
@@ -1604,29 +1598,27 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
dc_sqlite3_set_config_int(
|
||||
dc_sqlite3_set_config_int(
|
||||
context,
|
||||
&context.sql.read().unwrap(),
|
||||
"folders_configured",
|
||||
3,
|
||||
);
|
||||
if let Some(ref mvbox_folder) = mvbox_folder {
|
||||
dc_sqlite3_set_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"folders_configured\x00" as *const u8 as *const libc::c_char,
|
||||
3,
|
||||
"configured_mvbox_folder",
|
||||
Some(mvbox_folder),
|
||||
);
|
||||
}
|
||||
if let Some(ref sentbox_folder) = sentbox_folder {
|
||||
dc_sqlite3_set_config(
|
||||
context,
|
||||
&context.sql,
|
||||
"configured_sentbox_folder",
|
||||
Some(sentbox_folder.name()),
|
||||
);
|
||||
if let Some(ref mvbox_folder) = mvbox_folder {
|
||||
dc_sqlite3_set_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char,
|
||||
CString::new(mvbox_folder.clone()).unwrap().as_ptr(),
|
||||
);
|
||||
}
|
||||
if let Some(ref sentbox_folder) = sentbox_folder {
|
||||
dc_sqlite3_set_config(
|
||||
context,
|
||||
&context.sql,
|
||||
b"configured_sentbox_folder\x00" as *const u8 as *const libc::c_char,
|
||||
CString::new(sentbox_folder.name()).unwrap().as_ptr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
130
src/key.rs
130
src/key.rs
@@ -113,19 +113,6 @@ impl Key {
|
||||
Self::from_slice(bytes, key_type)
|
||||
}
|
||||
|
||||
pub fn from_stmt(
|
||||
stmt: *mut sqlite3_stmt,
|
||||
index: libc::c_int,
|
||||
key_type: KeyType,
|
||||
) -> Option<Self> {
|
||||
assert!(!stmt.is_null(), "missing statement");
|
||||
|
||||
let data = unsafe { sqlite3_column_blob(stmt, index) as *const u8 };
|
||||
let len = unsafe { sqlite3_column_bytes(stmt, index) };
|
||||
|
||||
Self::from_binary(data, len, key_type)
|
||||
}
|
||||
|
||||
pub fn from_armored_string(
|
||||
data: &str,
|
||||
key_type: KeyType,
|
||||
@@ -158,61 +145,34 @@ impl Key {
|
||||
|
||||
pub fn from_self_public(
|
||||
context: &Context,
|
||||
self_addr: *const libc::c_char,
|
||||
self_addr: impl AsRef<str>,
|
||||
sql: &SQLite,
|
||||
) -> Option<Self> {
|
||||
if self_addr.is_null() {
|
||||
return None;
|
||||
}
|
||||
let addr = self_addr.as_ref();
|
||||
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) };
|
||||
|
||||
let key = if unsafe { sqlite3_step(stmt) } == 100 {
|
||||
Self::from_stmt(stmt, 0, KeyType::Public)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
|
||||
key
|
||||
dc_sqlite3_query_row(
|
||||
context,
|
||||
sql,
|
||||
"SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;",
|
||||
&[addr],
|
||||
0,
|
||||
)
|
||||
.and_then(|blob: Vec<u8>| Self::from_slice(&blob, KeyType::Public))
|
||||
}
|
||||
|
||||
pub fn from_self_private(
|
||||
context: &Context,
|
||||
self_addr: *const libc::c_char,
|
||||
self_addr: impl AsRef<str>,
|
||||
sql: &SQLite,
|
||||
) -> Option<Self> {
|
||||
if self_addr.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"SELECT private_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) };
|
||||
|
||||
let key = if unsafe { sqlite3_step(stmt) } == 100 {
|
||||
Self::from_stmt(stmt, 0, KeyType::Private)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
|
||||
key
|
||||
dc_sqlite3_query_row(
|
||||
context,
|
||||
sql,
|
||||
"SELECT private_key FROM keypairs WHERE addr=? AND is_default=1;",
|
||||
&[self_addr.as_ref()],
|
||||
0,
|
||||
)
|
||||
.and_then(|blob: Vec<u8>| Self::from_slice(&blob, KeyType::Private))
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
@@ -340,57 +300,16 @@ pub fn dc_key_save_self_keypair(
|
||||
context: &Context,
|
||||
public_key: &Key,
|
||||
private_key: &Key,
|
||||
addr: *const libc::c_char,
|
||||
addr: impl AsRef<str>,
|
||||
is_default: libc::c_int,
|
||||
sql: &SQLite,
|
||||
) -> bool {
|
||||
if addr.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
dc_sqlite3_execute(
|
||||
context,
|
||||
sql,
|
||||
b"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);\x00"
|
||||
as *const u8 as *const libc::c_char
|
||||
"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);",
|
||||
params![addr.as_ref(), is_default, public_key.to_bytes(), private_key.to_bytes(), time()],
|
||||
)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
sqlite3_bind_text(stmt, 1, addr, -1, None);
|
||||
sqlite3_bind_int(stmt, 2, is_default)
|
||||
};
|
||||
let pub_bytes = public_key.to_bytes();
|
||||
let sec_bytes = private_key.to_bytes();
|
||||
unsafe {
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
3,
|
||||
pub_bytes.as_ptr() as *const _,
|
||||
pub_bytes.len() as libc::c_int,
|
||||
None,
|
||||
)
|
||||
};
|
||||
unsafe {
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
4,
|
||||
sec_bytes.as_ptr() as *const _,
|
||||
sec_bytes.len() as libc::c_int,
|
||||
None,
|
||||
)
|
||||
};
|
||||
unsafe { sqlite3_bind_int64(stmt, 5, time() as sqlite3_int64) };
|
||||
let success = if unsafe { sqlite3_step(stmt) } == 101 {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
/// Make a fingerprint human-readable, in hex format.
|
||||
@@ -526,8 +445,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
|
||||
#[test]
|
||||
#[ignore] // is too expensive
|
||||
fn test_from_slice_roundtrip() {
|
||||
let (public_key, private_key) =
|
||||
crate::pgp::dc_pgp_create_keypair(CString::new("hello").unwrap().as_ptr()).unwrap();
|
||||
let (public_key, private_key) = crate::pgp::dc_pgp_create_keypair("hello").unwrap();
|
||||
|
||||
let binary = public_key.to_bytes();
|
||||
let public_key2 = Key::from_slice(&binary, KeyType::Public).expect("invalid public key");
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::key::*;
|
||||
use crate::types::*;
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct Keyring<'a> {
|
||||
@@ -31,29 +30,18 @@ impl<'a> Keyring<'a> {
|
||||
pub fn load_self_private_for_decrypting(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
self_addr: *const libc::c_char,
|
||||
self_addr: impl AsRef<str>,
|
||||
sql: &SQLite,
|
||||
) -> bool {
|
||||
// Can we prevent keyring and self_addr to be null?
|
||||
if self_addr.is_null() {
|
||||
return false;
|
||||
}
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) };
|
||||
while unsafe { sqlite3_step(stmt) == 100 } {
|
||||
if let Some(key) = Key::from_stmt(stmt, 0, KeyType::Private) {
|
||||
self.add_owned(key);
|
||||
}
|
||||
}
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
|
||||
true
|
||||
dc_sqlite3_query_row(
|
||||
context,
|
||||
sql,
|
||||
"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;",
|
||||
&[self_addr.as_ref()],
|
||||
0,
|
||||
)
|
||||
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Private))
|
||||
.map(|key| self.add_owned(key))
|
||||
.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ extern crate failure_derive;
|
||||
extern crate num_derive;
|
||||
#[macro_use]
|
||||
extern crate smallvec;
|
||||
#[macro_use]
|
||||
extern crate rusqlite;
|
||||
|
||||
#[macro_use]
|
||||
pub mod dc_log;
|
||||
|
||||
111
src/oauth2.rs
111
src/oauth2.rs
@@ -1,5 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CString;
|
||||
|
||||
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
|
||||
use serde::Deserialize;
|
||||
@@ -51,10 +50,11 @@ pub fn dc_get_oauth2_url(
|
||||
redirect_uri: impl AsRef<str>,
|
||||
) -> Option<String> {
|
||||
if let Some(oauth2) = Oauth2::from_address(addr) {
|
||||
set_config(
|
||||
dc_sqlite3_set_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_pending_redirect_uri",
|
||||
redirect_uri.as_ref(),
|
||||
Some(redirect_uri.as_ref()),
|
||||
);
|
||||
let oauth2_url = replace_in_uri(&oauth2.get_code, "$CLIENT_ID", &oauth2.client_id);
|
||||
let oauth2_url = replace_in_uri(&oauth2_url, "$REDIRECT_URI", redirect_uri.as_ref());
|
||||
@@ -79,16 +79,31 @@ pub fn dc_get_oauth2_access_token(
|
||||
|
||||
// read generated token
|
||||
if 0 == flags & 0x1 && !is_expired(context) {
|
||||
let access_token = get_config(context, "oauth2_access_token");
|
||||
let access_token = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_access_token",
|
||||
None,
|
||||
);
|
||||
if access_token.is_some() {
|
||||
// success
|
||||
return access_token;
|
||||
}
|
||||
}
|
||||
|
||||
let refresh_token = get_config(context, "oauth2_refresh_token");
|
||||
let refresh_token_for =
|
||||
get_config(context, "oauth2_refresh_token_for").unwrap_or_else(|| "unset".into());
|
||||
let refresh_token = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_refresh_token",
|
||||
None,
|
||||
);
|
||||
let refresh_token_for = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_refresh_token_for",
|
||||
None,
|
||||
)
|
||||
.unwrap_or_else(|| "unset".into());
|
||||
|
||||
let (redirect_uri, token_url, update_redirect_uri_on_success) =
|
||||
if refresh_token.is_none() || refresh_token_for != code.as_ref() {
|
||||
@@ -97,8 +112,13 @@ pub fn dc_get_oauth2_access_token(
|
||||
0, "Generate OAuth2 refresh_token and access_token...",
|
||||
);
|
||||
(
|
||||
get_config(context, "oauth2_pending_redirect_uri")
|
||||
.unwrap_or_else(|| "unset".into()),
|
||||
dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_pending_redirect_uri",
|
||||
None,
|
||||
)
|
||||
.unwrap_or_else(|| "unset".into()),
|
||||
oauth2.init_token,
|
||||
true,
|
||||
)
|
||||
@@ -108,7 +128,13 @@ pub fn dc_get_oauth2_access_token(
|
||||
0, "Regenerate OAuth2 access_token by refresh_token...",
|
||||
);
|
||||
(
|
||||
get_config(context, "oauth2_redirect_uri").unwrap_or_else(|| "unset".into()),
|
||||
dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_redirect_uri",
|
||||
None,
|
||||
)
|
||||
.unwrap_or_else(|| "unset".into()),
|
||||
oauth2.refresh_token,
|
||||
false,
|
||||
)
|
||||
@@ -151,23 +177,48 @@ pub fn dc_get_oauth2_access_token(
|
||||
println!("response: {:?}", &parsed);
|
||||
let response = parsed.unwrap();
|
||||
if let Some(ref token) = response.refresh_token {
|
||||
set_config(context, "oauth2_refresh_token", token);
|
||||
set_config(context, "oauth2_refresh_token_for", code.as_ref());
|
||||
dc_sqlite3_set_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_refresh_token",
|
||||
Some(token),
|
||||
);
|
||||
dc_sqlite3_set_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_refresh_token_for",
|
||||
Some(code.as_ref()),
|
||||
);
|
||||
}
|
||||
|
||||
// after that, save the access token.
|
||||
// if it's unset, we may get it in the next round as we have the refresh_token now.
|
||||
if let Some(ref token) = response.access_token {
|
||||
set_config(context, "oauth2_access_token", token);
|
||||
dc_sqlite3_set_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_access_token",
|
||||
Some(token),
|
||||
);
|
||||
let expires_in = response
|
||||
.expires_in
|
||||
// refresh a bet before
|
||||
.map(|t| time() + t as i64 - 5)
|
||||
.unwrap_or_else(|| 0);
|
||||
set_config_int64(context, "oauth2_timestamp_expires", expires_in);
|
||||
dc_sqlite3_set_config_int64(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_timestamp_expires",
|
||||
expires_in,
|
||||
);
|
||||
|
||||
if update_redirect_uri_on_success {
|
||||
set_config(context, "oauth2_redirect_uri", redirect_uri.as_ref());
|
||||
dc_sqlite3_set_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
"oauth2_redirect_uri",
|
||||
Some(redirect_uri.as_ref()),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
warn!(context, 0, "Failed to find OAuth2 access token");
|
||||
@@ -279,35 +330,9 @@ impl Oauth2 {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_config(context: &Context, key: &str) -> Option<String> {
|
||||
let key_c = CString::new(key).unwrap();
|
||||
let res =
|
||||
unsafe { dc_sqlite3_get_config(context, &context.sql, key_c.as_ptr(), std::ptr::null()) };
|
||||
if res.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(to_string(res))
|
||||
}
|
||||
|
||||
fn set_config(context: &Context, key: &str, value: &str) {
|
||||
let key_c = CString::new(key).unwrap();
|
||||
let value_c = CString::new(value).unwrap();
|
||||
unsafe { dc_sqlite3_set_config(context, &context.sql, key_c.as_ptr(), value_c.as_ptr()) };
|
||||
}
|
||||
|
||||
fn set_config_int64(context: &Context, key: &str, value: i64) {
|
||||
let key_c = CString::new(key).unwrap();
|
||||
unsafe { dc_sqlite3_set_config_int64(context, &context.sql, key_c.as_ptr(), value) };
|
||||
}
|
||||
|
||||
fn is_expired(context: &Context) -> bool {
|
||||
let expire_timestamp = dc_sqlite3_get_config_int64(
|
||||
context,
|
||||
&context.sql,
|
||||
b"oauth2_timestamp_expires\x00" as *const u8 as *const libc::c_char,
|
||||
0i32 as int64_t,
|
||||
);
|
||||
let expire_timestamp =
|
||||
dc_sqlite3_get_config_int64(context, &context.sql, "oauth2_timestamp_expires", Some(0));
|
||||
|
||||
if expire_timestamp <= 0 {
|
||||
return false;
|
||||
|
||||
340
src/peerstate.rs
340
src/peerstate.rs
@@ -1,5 +1,4 @@
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::CString;
|
||||
use std::fmt;
|
||||
|
||||
use num_traits::FromPrimitive;
|
||||
@@ -9,7 +8,6 @@ use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::dc_tools::{to_cstring, to_string};
|
||||
use crate::key::*;
|
||||
use crate::types::*;
|
||||
|
||||
@@ -17,13 +15,13 @@ use crate::types::*;
|
||||
pub struct Peerstate<'a> {
|
||||
pub context: &'a Context,
|
||||
pub addr: Option<String>,
|
||||
pub last_seen: u64,
|
||||
pub last_seen_autocrypt: u64,
|
||||
pub last_seen: i64,
|
||||
pub last_seen_autocrypt: i64,
|
||||
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_timestamp: i64,
|
||||
pub gossip_key_fingerprint: Option<String>,
|
||||
verified_key: VerifiedKey,
|
||||
pub verified_key_fingerprint: Option<String>,
|
||||
@@ -141,7 +139,7 @@ impl<'a> Peerstate<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_header(context: &'a Context, header: &Aheader, message_time: u64) -> Self {
|
||||
pub fn from_header(context: &'a Context, header: &Aheader, message_time: i64) -> Self {
|
||||
let mut res = Self::new(context);
|
||||
|
||||
res.addr = Some(header.addr.clone());
|
||||
@@ -155,7 +153,7 @@ impl<'a> Peerstate<'a> {
|
||||
res
|
||||
}
|
||||
|
||||
pub fn from_gossip(context: &'a Context, gossip_header: &Aheader, message_time: u64) -> Self {
|
||||
pub fn from_gossip(context: &'a Context, gossip_header: &Aheader, message_time: i64) -> Self {
|
||||
let mut res = Self::new(context);
|
||||
|
||||
res.addr = Some(gossip_header.addr.clone());
|
||||
@@ -167,88 +165,78 @@ impl<'a> Peerstate<'a> {
|
||||
res
|
||||
}
|
||||
|
||||
pub fn from_addr(context: &'a Context, sql: &SQLite, addr: &str) -> Option<Self> {
|
||||
let mut res = None;
|
||||
pub fn from_addr(context: &'a Context, _sql: &SQLite, addr: &str) -> Option<Self> {
|
||||
let query = "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;";
|
||||
|
||||
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
|
||||
Self::from_stmt(context, query, &[addr])
|
||||
}
|
||||
|
||||
pub fn from_fingerprint(context: &'a Context, sql: &SQLite, fingerprint: &str) -> Option<Self> {
|
||||
let mut res = None;
|
||||
pub fn from_fingerprint(
|
||||
context: &'a Context,
|
||||
_sql: &SQLite,
|
||||
fingerprint: &str,
|
||||
) -> Option<Self> {
|
||||
let query = "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;";
|
||||
|
||||
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
|
||||
let fp = fingerprint.as_bytes();
|
||||
Self::from_stmt(context, query, params![fp, fp, fp])
|
||||
}
|
||||
|
||||
fn from_stmt(context: &'a Context, stmt: *mut sqlite3_stmt) -> Self {
|
||||
fn from_stmt<P>(context: &'a Context, query: &str, params: P) -> Option<Self>
|
||||
where
|
||||
P: IntoIterator,
|
||||
P::Item: rusqlite::ToSql,
|
||||
{
|
||||
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;
|
||||
let pkf = to_string(unsafe { sqlite3_column_text(stmt, 7) as *const _ });
|
||||
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
|
||||
let gkf = to_string(unsafe { sqlite3_column_text(stmt, 8) as *const _ });
|
||||
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
|
||||
let vkf = to_string(unsafe { sqlite3_column_text(stmt, 10) as *const _ });
|
||||
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) };
|
||||
if let Some(mut stmt) =
|
||||
dc_sqlite3_prepare(context, &context.sql.clone().read().unwrap(), query)
|
||||
{
|
||||
stmt.query_row(params, |row| {
|
||||
res.addr = Some(row.get(0)?);
|
||||
res.last_seen = row.get(1)?;
|
||||
res.last_seen_autocrypt = row.get(2)?;
|
||||
res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
|
||||
res.gossip_timestamp = row.get(5)?;
|
||||
let pkf: String = row.get(7)?;
|
||||
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
|
||||
let gkf: String = row.get(8)?;
|
||||
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
|
||||
let vkf: String = row.get(10)?;
|
||||
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) };
|
||||
|
||||
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.public_key = row
|
||||
.get(4)
|
||||
.ok()
|
||||
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
||||
res.gossip_key = row
|
||||
.get(6)
|
||||
.ok()
|
||||
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
||||
let vk = row
|
||||
.get(9)
|
||||
.ok()
|
||||
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
||||
res.verified_key = if vk == res.gossip_key {
|
||||
VerifiedKey::Gossip
|
||||
} else if vk == res.public_key {
|
||||
VerifiedKey::Public
|
||||
} else {
|
||||
VerifiedKey::None
|
||||
};
|
||||
|
||||
res
|
||||
Ok(res)
|
||||
})
|
||||
.ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recalc_fingerprint(&mut self) {
|
||||
@@ -283,7 +271,7 @@ impl<'a> Peerstate<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn degrade_encryption(&mut self, message_time: u64) {
|
||||
pub fn degrade_encryption(&mut self, message_time: i64) {
|
||||
if self.prefer_encrypt == EncryptPreference::Mutual {
|
||||
self.degrade_event = Some(DegradeEvent::EncryptionPaused);
|
||||
}
|
||||
@@ -293,7 +281,7 @@ impl<'a> Peerstate<'a> {
|
||||
self.to_save = Some(ToSave::All);
|
||||
}
|
||||
|
||||
pub fn apply_header(&mut self, header: &Aheader, message_time: u64) {
|
||||
pub fn apply_header(&mut self, header: &Aheader, message_time: i64) {
|
||||
if self.addr.is_none()
|
||||
|| self.addr.as_ref().unwrap().to_lowercase() != header.addr.to_lowercase()
|
||||
{
|
||||
@@ -325,7 +313,7 @@ impl<'a> Peerstate<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_gossip(&mut self, gossip_header: &Aheader, message_time: u64) {
|
||||
pub fn apply_gossip(&mut self, gossip_header: &Aheader, message_time: i64) {
|
||||
if self.addr.is_none()
|
||||
|| self.addr.as_ref().unwrap().to_lowercase() != gossip_header.addr.to_lowercase()
|
||||
{
|
||||
@@ -408,158 +396,56 @@ impl<'a> Peerstate<'a> {
|
||||
}
|
||||
|
||||
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 = to_cstring(self.addr.as_ref().unwrap());
|
||||
unsafe {
|
||||
sqlite3_bind_text(stmt, 1, addr_c.as_ptr(), -1, None);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
if !dc_sqlite3_execute(
|
||||
self.context,
|
||||
sql,
|
||||
"INSERT INTO acpeerstates (addr) VALUES(?);",
|
||||
params![self.addr.as_ref().unwrap()],
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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) };
|
||||
unsafe { sqlite3_bind_int64(stmt, 2, self.last_seen_autocrypt as sqlite3_int64) };
|
||||
unsafe { sqlite3_bind_int64(stmt, 3, self.prefer_encrypt as sqlite3_int64) };
|
||||
|
||||
let pub_bytes = self
|
||||
.public_key
|
||||
.as_ref()
|
||||
.map(|k| k.to_bytes())
|
||||
.unwrap_or_default();
|
||||
let gossip_bytes = self
|
||||
.gossip_key
|
||||
.as_ref()
|
||||
.map(|k| k.to_bytes())
|
||||
.unwrap_or_default();
|
||||
let ver_bytes = self
|
||||
.verified_key()
|
||||
.as_ref()
|
||||
.map(|k| k.to_bytes())
|
||||
.unwrap_or_default();
|
||||
|
||||
let pkc = self
|
||||
.public_key_fingerprint
|
||||
.as_ref()
|
||||
.map(to_cstring)
|
||||
.unwrap_or_default();
|
||||
|
||||
let pkc_ptr = if self.public_key_fingerprint.is_some() {
|
||||
pkc.as_ptr()
|
||||
} else {
|
||||
std::ptr::null()
|
||||
};
|
||||
|
||||
let gkc = self
|
||||
.gossip_key_fingerprint
|
||||
.as_ref()
|
||||
.map(to_cstring)
|
||||
.unwrap_or_default();
|
||||
|
||||
let gkc_ptr = if self.gossip_key_fingerprint.is_some() {
|
||||
gkc.as_ptr()
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
};
|
||||
let vkc = self
|
||||
.verified_key_fingerprint
|
||||
.as_ref()
|
||||
.map(to_cstring)
|
||||
.unwrap_or_default();
|
||||
let vkc_ptr = if self.verified_key_fingerprint.is_some() {
|
||||
vkc.as_ptr()
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
};
|
||||
let addr: String = self.addr.clone().unwrap_or_default();
|
||||
let addr_c = to_cstring(addr);
|
||||
|
||||
unsafe {
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
4,
|
||||
pub_bytes.as_ptr() as *const _,
|
||||
pub_bytes.len() as libc::c_int,
|
||||
SQLITE_TRANSIENT(),
|
||||
)
|
||||
};
|
||||
unsafe { sqlite3_bind_int64(stmt, 5, self.gossip_timestamp as sqlite3_int64) };
|
||||
unsafe {
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
6,
|
||||
gossip_bytes.as_ptr() as *const _,
|
||||
gossip_bytes.len() as libc::c_int,
|
||||
SQLITE_TRANSIENT(),
|
||||
)
|
||||
};
|
||||
unsafe { sqlite3_bind_text(stmt, 7, pkc_ptr as *const _, -1, SQLITE_TRANSIENT()) };
|
||||
unsafe { sqlite3_bind_text(stmt, 8, gkc_ptr as *const _, -1, SQLITE_TRANSIENT()) };
|
||||
unsafe {
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
9,
|
||||
ver_bytes.as_ptr() as *const _,
|
||||
ver_bytes.len() as libc::c_int,
|
||||
SQLITE_TRANSIENT(),
|
||||
)
|
||||
};
|
||||
|
||||
unsafe { sqlite3_bind_text(stmt, 10, vkc_ptr as *const _, -1, SQLITE_TRANSIENT()) };
|
||||
unsafe { sqlite3_bind_text(stmt, 11, addr_c.as_ptr(), -1, SQLITE_TRANSIENT()) };
|
||||
|
||||
if unsafe { sqlite3_step(stmt) } == 101 {
|
||||
success = true;
|
||||
}
|
||||
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
success = dc_sqlite3_execute(
|
||||
self.context,
|
||||
sql,
|
||||
"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=?;",
|
||||
params![
|
||||
self.last_seen,
|
||||
self.last_seen_autocrypt,
|
||||
self.prefer_encrypt as i64,
|
||||
self.public_key.as_ref().map(|k| k.to_bytes()),
|
||||
self.gossip_timestamp,
|
||||
self.gossip_key.as_ref().map(|k| k.to_bytes()),
|
||||
&self.public_key_fingerprint,
|
||||
&self.gossip_key_fingerprint,
|
||||
self.verified_key().map(|k| k.to_bytes()),
|
||||
&self.verified_key_fingerprint,
|
||||
&self.addr,
|
||||
],
|
||||
);
|
||||
} 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 c_addr = self.addr.as_ref().map(to_cstring).unwrap_or_default();
|
||||
let addr_ptr = if self.addr.is_some() {
|
||||
c_addr.as_ptr()
|
||||
} else {
|
||||
std::ptr::null()
|
||||
};
|
||||
|
||||
unsafe { sqlite3_bind_int64(stmt, 1, self.last_seen as sqlite3_int64) };
|
||||
unsafe { sqlite3_bind_int64(stmt, 2, self.last_seen_autocrypt as sqlite3_int64) };
|
||||
unsafe { sqlite3_bind_int64(stmt, 3, self.gossip_timestamp as sqlite3_int64) };
|
||||
unsafe { sqlite3_bind_text(stmt, 4, addr_ptr, -1, SQLITE_TRANSIENT()) };
|
||||
|
||||
if unsafe { sqlite3_step(stmt) } == 101 {
|
||||
success = true;
|
||||
}
|
||||
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
success = dc_sqlite3_execute(
|
||||
self.context,
|
||||
sql,
|
||||
"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? \
|
||||
WHERE addr=?;",
|
||||
params![
|
||||
self.last_seen,
|
||||
self.last_seen_autocrypt,
|
||||
self.gossip_timestamp,
|
||||
&self.addr
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
if self.to_save == Some(ToSave::All) || create {
|
||||
unsafe { dc_reset_gossiped_timestamp(self.context, 0 as uint32_t) };
|
||||
dc_reset_gossiped_timestamp(self.context, 0);
|
||||
}
|
||||
|
||||
success
|
||||
@@ -582,7 +468,7 @@ mod tests {
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::ffi::{CStr, CString};
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
use crate::context::*;
|
||||
|
||||
@@ -137,8 +137,8 @@ pub unsafe fn dc_split_armored_data(
|
||||
}
|
||||
|
||||
/// Create a new key pair.
|
||||
pub fn dc_pgp_create_keypair(addr: *const libc::c_char) -> Option<(Key, Key)> {
|
||||
let user_id = format!("<{}>", unsafe { CStr::from_ptr(addr).to_str().unwrap() });
|
||||
pub fn dc_pgp_create_keypair(addr: impl AsRef<str>) -> Option<(Key, Key)> {
|
||||
let user_id = format!("<{}>", addr.as_ref());
|
||||
|
||||
let key_params = SecretKeyParamsBuilder::default()
|
||||
.key_type(PgpKeyType::Rsa(2048))
|
||||
|
||||
42
src/smtp.rs
42
src/smtp.rs
@@ -1,5 +1,3 @@
|
||||
use std::ffi::CStr;
|
||||
|
||||
use lettre::smtp::client::net::*;
|
||||
use lettre::*;
|
||||
|
||||
@@ -7,7 +5,6 @@ use crate::constants::Event;
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_loginparam::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::oauth2::*;
|
||||
use crate::types::*;
|
||||
|
||||
@@ -47,30 +44,17 @@ impl Smtp {
|
||||
}
|
||||
|
||||
/// Connect using the provided login params
|
||||
pub fn connect(&mut self, context: &Context, lp: *const dc_loginparam_t) -> usize {
|
||||
if lp.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn connect(&mut self, context: &Context, lp: &dc_loginparam_t) -> usize {
|
||||
if self.is_connected() {
|
||||
warn!(context, 0, "SMTP already connected.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Safe because we checked for null pointer above.
|
||||
let lp = unsafe { *lp };
|
||||
|
||||
if lp.addr.is_null() || lp.send_server.is_null() || lp.send_port == 0 {
|
||||
if lp.send_server.is_empty() || lp.send_port == 0 {
|
||||
log_event!(context, Event::ERROR_NETWORK, 0, "SMTP bad parameters.",);
|
||||
}
|
||||
|
||||
let raw_addr = unsafe {
|
||||
CStr::from_ptr(lp.addr)
|
||||
.to_str()
|
||||
.expect("invalid from address")
|
||||
.to_string()
|
||||
};
|
||||
self.from = if let Ok(addr) = EmailAddress::new(raw_addr) {
|
||||
self.from = if let Ok(addr) = EmailAddress::new(lp.addr.clone()) {
|
||||
Some(addr)
|
||||
} else {
|
||||
None
|
||||
@@ -81,11 +65,7 @@ impl Smtp {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let domain = unsafe {
|
||||
CStr::from_ptr(lp.send_server)
|
||||
.to_str()
|
||||
.expect("invalid send server")
|
||||
};
|
||||
let domain = &lp.send_server;
|
||||
let port = lp.send_port as u16;
|
||||
|
||||
let tls = native_tls::TlsConnector::builder()
|
||||
@@ -99,19 +79,19 @@ impl Smtp {
|
||||
|
||||
let creds = if 0 != lp.server_flags & (DC_LP_AUTH_OAUTH2 as i32) {
|
||||
// oauth2
|
||||
let addr = as_str(lp.addr);
|
||||
let send_pw = as_str(lp.send_pw);
|
||||
let addr = &lp.addr;
|
||||
let send_pw = &lp.send_pw;
|
||||
let access_token = dc_get_oauth2_access_token(context, addr, send_pw, 0);
|
||||
if access_token.is_none() {
|
||||
return 0;
|
||||
}
|
||||
let user = as_str(lp.send_user);
|
||||
let user = &lp.send_user;
|
||||
|
||||
lettre::smtp::authentication::Credentials::new(user.into(), access_token.unwrap())
|
||||
lettre::smtp::authentication::Credentials::new(user.to_string(), access_token.unwrap())
|
||||
} else {
|
||||
// plain
|
||||
let user = unsafe { CStr::from_ptr(lp.send_user).to_str().unwrap().to_string() };
|
||||
let pw = unsafe { CStr::from_ptr(lp.send_pw).to_str().unwrap().to_string() };
|
||||
let user = lp.send_user.clone();
|
||||
let pw = lp.send_pw.clone();
|
||||
lettre::smtp::authentication::Credentials::new(user, pw)
|
||||
};
|
||||
|
||||
@@ -123,7 +103,7 @@ impl Smtp {
|
||||
lettre::smtp::ClientSecurity::Wrapper(tls_parameters)
|
||||
};
|
||||
|
||||
match lettre::smtp::SmtpClient::new((domain, port), security) {
|
||||
match lettre::smtp::SmtpClient::new((domain.as_str(), port), security) {
|
||||
Ok(client) => {
|
||||
let client = client
|
||||
.smtp_utf8(true)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::constants::Event;
|
||||
use crate::context::Context;
|
||||
|
||||
pub use libsqlite3_sys::*;
|
||||
pub use mmime::carray::*;
|
||||
pub use mmime::clist::*;
|
||||
pub use rusqlite::ffi::*;
|
||||
|
||||
/// Callback function that should be given to dc_context_new().
|
||||
///
|
||||
@@ -22,7 +22,7 @@ pub type dc_receive_imf_t = unsafe fn(
|
||||
_: &Context,
|
||||
_: *const libc::c_char,
|
||||
_: size_t,
|
||||
_: *const libc::c_char,
|
||||
_: &str,
|
||||
_: uint32_t,
|
||||
_: uint32_t,
|
||||
) -> ();
|
||||
@@ -32,7 +32,7 @@ Context is only used for logging and to get information about
|
||||
the online state. */
|
||||
|
||||
pub type dc_precheck_imf_t =
|
||||
unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char, _: u32) -> libc::c_int;
|
||||
unsafe fn(_: &Context, _: *const libc::c_char, _: &str, _: u32) -> libc::c_int;
|
||||
pub type dc_set_config_t =
|
||||
unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char) -> ();
|
||||
pub type dc_get_config_t =
|
||||
|
||||
Reference in New Issue
Block a user