refactor: safe sql access

This commit is contained in:
dignifiedquire
2019-06-08 16:42:29 +02:00
parent 205493f89d
commit ab41679855
34 changed files with 6550 additions and 8249 deletions

View File

@@ -16,7 +16,6 @@ hex = "0.3.2"
sha2 = "0.8.0" sha2 = "0.8.0"
rand = "0.6.5" rand = "0.6.5"
smallvec = "0.6.9" smallvec = "0.6.9"
libsqlite3-sys = { version = "0.14.0", features = ["bundled", "min_sqlite_version_3_7_16"] }
reqwest = "0.9.15" reqwest = "0.9.15"
num-derive = "0.2.5" num-derive = "0.2.5"
num-traits = "0.2.6" num-traits = "0.2.6"
@@ -36,6 +35,8 @@ failure_derive = "0.1.5"
rustyline = "4.1.0" rustyline = "4.1.0"
lazy_static = "1.3.0" lazy_static = "1.3.0"
regex = "1.1.6" regex = "1.1.6"
rusqlite = { version = "0.18.0", features = ["bundled"] }
addr = "0.2.0"
[dev-dependencies] [dev-dependencies]
tempfile = "3.0" tempfile = "3.0"

View File

@@ -25,65 +25,58 @@ use num_traits::FromPrimitive;
pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 { pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
info!(context, 0, "Resetting tables ({})...", bits); info!(context, 0, "Resetting tables ({})...", bits);
if 0 != bits & 1 { if 0 != bits & 1 {
dc_sqlite3_execute( dc_sqlite3_execute(context, &context.sql, "DELETE FROM jobs;", params![]);
context,
&context.sql,
b"DELETE FROM jobs;\x00" as *const u8 as *const libc::c_char,
);
info!(context, 0, "(1) Jobs reset."); info!(context, 0, "(1) Jobs reset.");
} }
if 0 != bits & 2 { if 0 != bits & 2 {
dc_sqlite3_execute( dc_sqlite3_execute(
context, context,
&context.sql, &context.sql,
b"DELETE FROM acpeerstates;\x00" as *const u8 as *const libc::c_char, "DELETE FROM acpeerstates;",
params![],
); );
info!(context, 0, "(2) Peerstates reset."); info!(context, 0, "(2) Peerstates reset.");
} }
if 0 != bits & 4 { if 0 != bits & 4 {
dc_sqlite3_execute( dc_sqlite3_execute(context, &context.sql, "DELETE FROM keypairs;", params![]);
context,
&context.sql,
b"DELETE FROM keypairs;\x00" as *const u8 as *const libc::c_char,
);
info!(context, 0, "(4) Private keypairs reset."); info!(context, 0, "(4) Private keypairs reset.");
} }
if 0 != bits & 8 { if 0 != bits & 8 {
dc_sqlite3_execute( dc_sqlite3_execute(
context, context,
&context.sql, &context.sql,
b"DELETE FROM contacts WHERE id>9;\x00" as *const u8 as *const libc::c_char, "DELETE FROM contacts WHERE id>9;",
params![],
); );
dc_sqlite3_execute( dc_sqlite3_execute(
context, context,
&context.sql, &context.sql,
b"DELETE FROM chats WHERE id>9;\x00" as *const u8 as *const libc::c_char, "DELETE FROM chats WHERE id>9;",
params![],
); );
dc_sqlite3_execute( dc_sqlite3_execute(
context, context,
&context.sql, &context.sql,
b"DELETE FROM chats_contacts;\x00" as *const u8 as *const libc::c_char, "DELETE FROM chats_contacts;",
params![],
); );
dc_sqlite3_execute( dc_sqlite3_execute(
context, context,
&context.sql, &context.sql,
b"DELETE FROM msgs WHERE id>9;\x00" as *const u8 as *const libc::c_char, "DELETE FROM msgs WHERE id>9;",
params![],
); );
dc_sqlite3_execute( dc_sqlite3_execute(
context, context,
&context.sql, &context.sql,
b"DELETE FROM config WHERE keyname LIKE \'imap.%\' OR keyname LIKE \'configured%\';\x00" "DELETE FROM config WHERE keyname LIKE \'imap.%\' OR keyname LIKE \'configured%\';",
as *const u8 as *const libc::c_char, params![],
);
dc_sqlite3_execute(
context,
&context.sql,
b"DELETE FROM leftgrps;\x00" as *const u8 as *const libc::c_char,
); );
dc_sqlite3_execute(context, &context.sql, "DELETE FROM leftgrps;", params![]);
info!(context, 0, "(8) Rest but server config reset."); info!(context, 0, "(8) Rest but server config reset.");
} }
context.call_cb(Event::MSGS_CHANGED, 0 as uintptr_t, 0 as uintptr_t); context.call_cb(Event::MSGS_CHANGED, 0, 0);
1 1
} }
@@ -100,14 +93,7 @@ unsafe fn dc_poke_eml_file(context: &Context, filename: *const libc::c_char) ->
&mut data_bytes, &mut data_bytes,
) == 0i32) ) == 0i32)
{ {
dc_receive_imf( dc_receive_imf(context, data, data_bytes, "import", 0, 0);
context,
data,
data_bytes,
b"import\x00" as *const u8 as *const libc::c_char,
0i32 as uint32_t,
0i32 as uint32_t,
);
success = 1; success = 1;
} }
free(data as *mut libc::c_void); free(data as *mut libc::c_void);
@@ -141,23 +127,19 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
dc_sqlite3_set_config( dc_sqlite3_set_config(
context, context,
&context.sql, &context.sql,
b"import_spec\x00" as *const u8 as *const libc::c_char, "import_spec",
real_spec, Some(as_str(real_spec)),
); );
current_block = 7149356873433890176; current_block = 7149356873433890176;
} else { } else {
real_spec = dc_sqlite3_get_config( let rs = dc_sqlite3_get_config(context, &context.sql, "import_spec", None);
context, if rs.is_none() {
&context.sql,
b"import_spec\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
if real_spec.is_null() {
error!(context, 0, "Import: No file or folder given."); error!(context, 0, "Import: No file or folder given.");
current_block = 8522321847195001863; current_block = 8522321847195001863;
} else { } else {
current_block = 7149356873433890176; current_block = 7149356873433890176;
} }
real_spec = strdup(to_cstring(rs.unwrap_or_default()).as_ptr());
} }
match current_block { match current_block {
8522321847195001863 => {} 8522321847195001863 => {}
@@ -499,9 +481,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}, },
"auth" => { "auth" => {
if 0 == S_IS_AUTH { if 0 == S_IS_AUTH {
let is_pw = let is_pw = dc_get_config(context, "mail_pw");
dc_get_config(context, b"mail_pw\x00" as *const u8 as *const libc::c_char); if arg1 == is_pw {
if arg1 == as_str(is_pw) {
S_IS_AUTH = 1; S_IS_AUTH = 1;
} else { } else {
println!("Bad password."); println!("Bad password.");
@@ -537,8 +518,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(!arg1.is_empty(), "Argument <msg-id> missing."); ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
let msg_id: u32 = arg1.parse().unwrap(); let msg_id: u32 = arg1.parse().unwrap();
let msg: *mut dc_msg_t = dc_get_msg(context, msg_id); let msg: *mut dc_msg_t = dc_get_msg(context, msg_id);
if 0 != dc_msg_is_setupmessage(msg) { if dc_msg_is_setupmessage(msg) {
let setupcodebegin: *mut libc::c_char = dc_msg_get_setupcodebegin(msg); let setupcodebegin = dc_msg_get_setupcodebegin(msg);
println!( println!(
"The setup code for setup message Msg#{} starts with: {}", "The setup code for setup message Msg#{} starts with: {}",
msg_id, msg_id,
@@ -621,15 +602,14 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
"set" => { "set" => {
ensure!(!arg1.is_empty(), "Argument <key> missing."); ensure!(!arg1.is_empty(), "Argument <key> missing.");
ensure!( ensure!(
0 != dc_set_config(context, arg1_c_ptr, arg2_c_ptr), 0 != dc_set_config(context, &arg1, Some(&arg2)),
"Set config failed" "Set config failed"
); );
} }
"get" => { "get" => {
ensure!(!arg1.is_empty(), "Argument <key> missing."); ensure!(!arg1.is_empty(), "Argument <key> missing.");
let val = dc_get_config(context, arg1_c_ptr); let val = dc_get_config(context, &arg1);
println!("{}={}", arg1, to_string(val)); println!("{}={}", arg1, val);
free(val as *mut libc::c_void);
} }
"info" => { "info" => {
println!("{}", to_string(dc_get_info(context))); println!("{}", to_string(dc_get_info(context)));
@@ -714,7 +694,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
i -= 1 i -= 1
} }
} }
if 0 != dc_is_sending_locations_to_chat(context, 0 as uint32_t) { if dc_is_sending_locations_to_chat(context, 0 as uint32_t) {
info!(context, 0, "Location streaming enabled."); info!(context, 0, "Location streaming enabled.");
} }
println!("{} chats", cnt); println!("{} chats", cnt);

View File

@@ -10,6 +10,8 @@ extern crate deltachat;
extern crate failure; extern crate failure;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[macro_use]
extern crate rusqlite;
use std::borrow::Cow::{self, Borrowed, Owned}; use std::borrow::Cow::{self, Borrowed, Owned};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@@ -512,25 +514,21 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
dc_configure(&ctx.read().unwrap()); dc_configure(&ctx.read().unwrap());
} }
"oauth2" => { "oauth2" => {
let addr = dc_get_config( let addr = dc_get_config(&ctx.read().unwrap(), "addr");
&ctx.read().unwrap(), if addr.is_empty() {
b"addr\x00" as *const u8 as *const libc::c_char,
);
if addr.is_null() || *addr.offset(0isize) as libc::c_int == 0i32 {
println!("oauth2: set addr first."); println!("oauth2: set addr first.");
} else { } else {
let oauth2_url = dc_get_oauth2_url( let oauth2_url = dc_get_oauth2_url(
&ctx.read().unwrap(), &ctx.read().unwrap(),
as_str(addr), &addr,
"chat.delta:/com.b44t.messenger", "chat.delta:/com.b44t.messenger",
); );
if oauth2_url.is_none() { if oauth2_url.is_none() {
println!("OAuth2 not available for {}.", to_string(addr)); println!("OAuth2 not available for {}.", &addr);
} else { } else {
println!("Open the following url, set mail_pw to the generated token and server_flags to 2:\n{}", oauth2_url.unwrap()); println!("Open the following url, set mail_pw to the generated token and server_flags to 2:\n{}", oauth2_url.unwrap());
} }
} }
free(addr as *mut libc::c_void);
} }
"clear" => { "clear" => {
println!("\n\n\n"); println!("\n\n\n");

View File

@@ -83,16 +83,8 @@ fn main() {
println!("configuring"); println!("configuring");
let pw = std::env::args().collect::<Vec<String>>()[1].clone(); let pw = std::env::args().collect::<Vec<String>>()[1].clone();
dc_set_config( dc_set_config(&ctx, "addr", Some("d@testrun.org"));
&ctx, dc_set_config(&ctx, "mail_pw", Some(&pw));
CString::new("addr").unwrap().as_ptr(),
CString::new("d@testrun.org").unwrap().as_ptr(),
);
dc_set_config(
&ctx,
CString::new("mail_pw").unwrap().as_ptr(),
CString::new(pw).unwrap().as_ptr(),
);
dc_configure(&ctx); dc_configure(&ctx);
thread::sleep(duration); thread::sleep(duration);

View File

@@ -1,5 +1,5 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::ffi::{CStr, CString}; use std::ffi::CStr;
use std::str::FromStr; use std::str::FromStr;
use std::{fmt, str}; use std::{fmt, str};
@@ -7,6 +7,7 @@ use mmime::mailimf_types::*;
use crate::constants::*; use crate::constants::*;
use crate::dc_contact::*; use crate::dc_contact::*;
use crate::dc_tools::as_str;
use crate::key::*; use crate::key::*;
/// Possible values for encryption preference /// Possible values for encryption preference
@@ -93,9 +94,7 @@ impl Aheader {
match Self::from_str(value) { match Self::from_str(value) {
Ok(test) => { Ok(test) => {
// TODO: implement rust-safe version of dc_addr_cmp if dc_addr_cmp(&test.addr, as_str(wanted_from)) {
let addr = CString::new(test.addr.clone()).unwrap();
if unsafe { dc_addr_cmp(addr.as_ptr(), wanted_from) } == 0 {
if fine_header.is_none() { if fine_header.is_none() {
fine_header = Some(test); fine_header = Some(test);
} else { } else {

View File

@@ -21,6 +21,49 @@ use crate::smtp::*;
use crate::types::*; use crate::types::*;
use crate::x::*; 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)] #[repr(C)]
pub struct Context { pub struct Context {
pub userdata: *mut libc::c_void, pub userdata: *mut libc::c_void,
@@ -186,7 +229,7 @@ unsafe fn cb_receive_imf(
context: &Context, context: &Context,
imf_raw_not_terminated: *const libc::c_char, imf_raw_not_terminated: *const libc::c_char,
imf_raw_bytes: size_t, imf_raw_bytes: size_t,
server_folder: *const libc::c_char, server_folder: &str,
server_uid: uint32_t, server_uid: uint32_t,
flags: uint32_t, flags: uint32_t,
) { ) {
@@ -203,7 +246,7 @@ unsafe fn cb_receive_imf(
unsafe fn cb_precheck_imf( unsafe fn cb_precheck_imf(
context: &Context, context: &Context,
rfc724_mid: *const libc::c_char, rfc724_mid: *const libc::c_char,
server_folder: *const libc::c_char, server_folder: &str,
server_uid: uint32_t, server_uid: uint32_t,
) -> libc::c_int { ) -> libc::c_int {
let mut rfc724_mid_exists: libc::c_int = 0i32; let mut rfc724_mid_exists: libc::c_int = 0i32;
@@ -229,7 +272,7 @@ unsafe fn cb_precheck_imf(
rfc724_mid, rfc724_mid,
); );
mark_seen = 1i32 mark_seen = 1i32
} else if strcmp(old_server_folder, server_folder) != 0i32 { } else if as_str(old_server_folder) != server_folder {
dc_log_info( dc_log_info(
context, context,
0i32, 0i32,
@@ -238,7 +281,7 @@ unsafe fn cb_precheck_imf(
); );
dc_update_msg_move_state(context, rfc724_mid, DC_MOVE_STATE_STAY); 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_update_server_uid(context, rfc724_mid, server_folder, server_uid);
} }
dc_do_heuristics_moves(context, server_folder, msg_id); 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) { 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, key: *const libc::c_char,
def: *const libc::c_char, def: *const libc::c_char,
) -> *mut 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) { 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()) dc_strdup(*context.blobdir.clone().read().unwrap())
} }
pub unsafe fn dc_set_config( pub fn dc_set_config(context: &Context, key: impl AsRef<str>, value: Option<&str>) -> libc::c_int {
context: &Context,
key: *const libc::c_char,
value: *const libc::c_char,
) -> libc::c_int {
let mut ret = 0; 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; 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); match key.as_ref() {
if !(0 == dc_make_rel_and_copy(context, &mut rel_path)) { "selfavatar" if value.is_some() => {
ret = dc_sqlite3_set_config(context, &context.sql, key, rel_path) 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 { "inbox_watch" => {
ret = dc_sqlite3_set_config(context, &context.sql, key, value); ret = dc_sqlite3_set_config(context, &context.sql, key, value);
dc_interrupt_imap_idle(context); unsafe { dc_interrupt_imap_idle(context) };
} else if strcmp( }
key, "sentbox_watch" => {
b"sentbox_watch\x00" as *const u8 as *const libc::c_char, ret = dc_sqlite3_set_config(context, &context.sql, key, value);
) == 0 unsafe { dc_interrupt_sentbox_idle(context) };
{ }
ret = dc_sqlite3_set_config(context, &context.sql, key, value); "mvbox_watch" => {
dc_interrupt_sentbox_idle(context); ret = dc_sqlite3_set_config(context, &context.sql, key, value);
} else if strcmp(key, b"mvbox_watch\x00" as *const u8 as *const libc::c_char) == 0 { unsafe { dc_interrupt_mvbox_idle(context) };
ret = dc_sqlite3_set_config(context, &context.sql, key, value); }
dc_interrupt_mvbox_idle(context); "selfstatus" => {
} else if strcmp(key, b"selfstatus\x00" as *const u8 as *const libc::c_char) == 0 { let def = unsafe { dc_stock_str(context, 13) };
let def = dc_stock_str(context, 13); let val = if value.is_none() || value.unwrap() == as_str(def) {
ret = dc_sqlite3_set_config( None
context,
&context.sql,
key,
if value.is_null() || strcmp(value, def) == 0 {
0 as *const libc::c_char
} else { } else {
value value
}, };
);
free(def as *mut libc::c_void); ret = dc_sqlite3_set_config(context, &context.sql, key, val);
} else { unsafe { free(def as *mut libc::c_void) };
ret = dc_sqlite3_set_config(context, &context.sql, key, value); }
_ => {
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
}
} }
free(rel_path as *mut libc::c_void);
ret ret
} }
@@ -408,303 +462,136 @@ pub unsafe fn dc_set_config(
* INI-handling, Information * INI-handling, Information
******************************************************************************/ ******************************************************************************/
unsafe fn is_settable_config_key(key: *const libc::c_char) -> libc::c_int { fn is_settable_config_key(key: impl AsRef<str>) -> bool {
let mut i = 0; CONFIG_KEYS
while i .into_iter()
< (::std::mem::size_of::<[*const libc::c_char; 33]>()) .find(|c| **c == key.as_ref())
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>()) .is_some()
{
if strcmp(key, config_keys[i as usize]) == 0 {
return 1;
}
i += 1
}
0
} }
static mut config_keys: [*const libc::c_char; 33] = [ pub fn dc_get_config(context: &Context, key: impl AsRef<str>) -> String {
b"addr\x00" as *const u8 as *const libc::c_char, if key.as_ref().starts_with("sys") {
b"mail_server\x00" as *const u8 as *const libc::c_char, return get_sys_config_str(key.as_ref());
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);
} }
if key.is_null() || 0 == is_gettable_config_key(key) { if !is_gettable_config_key(key.as_ref()) {
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char); return "".into();
} }
if strcmp(key, b"selfavatar\x00" as *const u8 as *const libc::c_char) == 0 { let value = match key.as_ref() {
let rel_path: *mut libc::c_char = "selfavatar" => {
dc_sqlite3_get_config(context, &context.sql, key, 0 as *const libc::c_char); let rel_path = dc_sqlite3_get_config(context, &context.sql, key.as_ref(), None);
if !rel_path.is_null() { rel_path.map(|p| {
value = dc_get_abs_path(context, rel_path); let v = unsafe { dc_get_abs_path(context, to_cstring(p).as_ptr()) };
free(rel_path as *mut libc::c_void); let r = to_string(v);
unsafe { free(v as *mut _) };
r
})
} }
} else { _ => dc_sqlite3_get_config(context, &context.sql, key.as_ref(), None),
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);
}; };
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 { fn is_gettable_config_key(key: impl AsRef<str>) -> bool {
let mut ret = String::new(); SYS_CONFIG_KEYS
let mut i = 0; .into_iter()
while i .find(|c| **c == key.as_ref())
< (::std::mem::size_of::<[*const libc::c_char; 33]>()) .is_some()
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>()) || is_settable_config_key(key)
{ }
if !ret.is_empty() {
ret += " ";
}
ret += &to_string(config_keys[i as usize]);
i += 1
}
let mut i = 0; fn get_sys_config_str(key: impl AsRef<str>) -> String {
while i match key.as_ref() {
< (::std::mem::size_of::<[*const libc::c_char; 3]>()) "sys.version" => std::str::from_utf8(DC_VERSION_STR).unwrap().into(),
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>()) "sys.msgsize_max_recommended" => format!("{}", 24 * 1024 * 1024 / 4 * 3),
{ "sys.config_keys" => get_config_keys_str(),
if !ret.is_empty() { _ => "".into(),
ret += " ";
}
ret += &to_string(sys_config_keys[i as usize]);
i += 1
} }
}
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 { pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
let unset = "0"; let unset = "0";
let l = dc_loginparam_new(); let l = dc_loginparam_read(context, &context.sql, "");
let l2 = dc_loginparam_new(); let l2 = dc_loginparam_read(context, &context.sql, "configured_");
dc_loginparam_read( let displayname = dc_sqlite3_get_config(context, &context.sql, "displayname", None);
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 chats = dc_get_chat_cnt(context) as usize; let chats = dc_get_chat_cnt(context) as usize;
let real_msgs = dc_get_real_msg_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 deaddrop_msgs = dc_get_deaddrop_msg_cnt(context) as usize;
let contacts = dc_get_real_contact_cnt(context) as usize; let contacts = dc_get_real_contact_cnt(context) as usize;
let is_configured = dc_sqlite3_get_config_int( let is_configured = dc_sqlite3_get_config_int(context, &context.sql, "configured", 0);
context, let dbversion = dc_sqlite3_get_config_int(context, &context.sql, "dbversion", 0);
&context.sql, let e2ee_enabled = dc_sqlite3_get_config_int(context, &context.sql, "e2ee_enabled", 1);
b"configured\x00" as *const u8 as *const libc::c_char, let mdns_enabled = dc_sqlite3_get_config_int(context, &context.sql, "mdns_enabled", 1);
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 l_readable_str = dc_loginparam_get_readable(l); let prv_key_cnt: Option<isize> = dc_sqlite3_query_row(
let l2_readable_str = dc_loginparam_get_readable(l2);
let inbox_watch = dc_sqlite3_get_config_int(
context, context,
&context.sql, &context.sql,
b"inbox_watch\x00" as *const u8 as *const libc::c_char, "SELECT COUNT(*) FROM keypairs;",
1, rusqlite::NO_PARAMS,
);
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,
0, 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( let configured_sentbox_folder = dc_sqlite3_get_config(
context, context,
&context.sql, &context.sql,
b"configured_sentbox_folder\x00" as *const u8 as *const libc::c_char, "configured_sentbox_folder",
b"<unset>\x00" as *const u8 as *const libc::c_char, Some("<unset>"),
); );
let configured_mvbox_folder = dc_sqlite3_get_config( let configured_mvbox_folder = dc_sqlite3_get_config(
context, context,
&context.sql, &context.sql,
b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char, "configured_mvbox_folder",
b"<unset>\x00" as *const u8 as *const libc::c_char, Some("<unset>"),
); );
let res = format!( let res = format!(
@@ -737,7 +624,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
fingerprint={}\n\ fingerprint={}\n\
level=awesome\n", level=awesome\n",
as_str(DC_VERSION_STR as *const u8 as *const _), 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(), sqlite3_threadsafe(),
// arch // arch
(::std::mem::size_of::<*mut libc::c_void>()).wrapping_mul(8), (::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 { } else {
unset unset
}, },
if !displayname.is_null() { displayname.unwrap_or_else(|| unset.into()),
as_str(displayname)
} else {
unset
},
is_configured, is_configured,
as_str(l_readable_str), l_readable_str,
as_str(l2_readable_str), l2_readable_str,
inbox_watch, inbox_watch,
sentbox_watch, sentbox_watch,
mvbox_watch, mvbox_watch,
mvbox_move, mvbox_move,
folders_configured, folders_configured,
as_str(configured_sentbox_folder), configured_sentbox_folder.unwrap_or_default(),
as_str(configured_mvbox_folder), configured_mvbox_folder.unwrap_or_default(),
mdns_enabled, mdns_enabled,
e2ee_enabled, e2ee_enabled,
prv_key_cnt, prv_key_cnt.unwrap_or_default(),
pub_key_cnt, pub_key_cnt.unwrap_or_default(),
fingerprint_str, 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()) 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) 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 show_deaddrop = 0;
let ret = dc_array_new(128 as size_t); let ret = unsafe { dc_array_new(128 as size_t) };
let mut stmt = 0 as *mut sqlite3_stmt;
if !ret.is_null() { if !ret.is_null() {
stmt = dc_sqlite3_prepare( if let Some(ref mut stmt) = dc_sqlite3_prepare(
context, context,
&context.sql, &context.sql,
b"SELECT m.id FROM msgs m LEFT JOIN contacts ct \ "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=? \ 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.hidden=0 \
AND m.chat_id>? \ AND m.chat_id>? \
AND ct.blocked=0 \ AND ct.blocked=0 \
AND (c.blocked=0 OR c.blocked=?) ORDER BY m.timestamp DESC,m.id DESC;\x00" AND (c.blocked=0 OR c.blocked=?) ORDER BY m.timestamp DESC,m.id DESC;",
as *const u8 as *const libc::c_char, ) {
); match stmt.query_map(&[10, 9, if 0 != show_deaddrop { 2 } else { 0 }], |row| {
sqlite3_bind_int(stmt, 1, 10); row.get(0)
sqlite3_bind_int(stmt, 2, 9); }) {
sqlite3_bind_int(stmt, 3, if 0 != show_deaddrop { 2 } else { 0 }); Ok(rows) => {
while sqlite3_step(stmt) == 100 { for row in rows {
dc_array_add_id(ret, sqlite3_column_int(stmt, 0) as uint32_t); if let Ok(id) = row {
unsafe { dc_array_add_id(ret, id) };
}
}
}
Err(_err) => {}
}
} }
} }
sqlite3_finalize(stmt);
ret ret
} }
pub unsafe fn dc_search_msgs( pub fn dc_search_msgs(
context: &Context, context: &Context,
chat_id: uint32_t, chat_id: uint32_t,
query: *const libc::c_char, query: *const libc::c_char,
) -> *mut dc_array_t { ) -> *mut dc_array_t {
let mut success = 0; let mut success = false;
let ret = dc_array_new(100 as size_t); let ret = unsafe { 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;
if !(ret.is_null() || query.is_null()) { if !(ret.is_null() || query.is_null()) {
real_query = dc_strdup(query); let real_query = to_string(query).trim().to_string();
dc_trim(real_query); if real_query.is_empty() {
if *real_query.offset(0isize) as libc::c_int == 0 { success = true;
success = 1
} else { } else {
strLikeInText = dc_mprintf( let strLikeInText = format!("%{}%", &real_query);
b"%%%s%%\x00" as *const u8 as *const libc::c_char, let strLikeBeg = format!("{}%", &real_query);
real_query,
); let rows = if 0 != chat_id {
strLikeBeg = dc_mprintf(b"%s%%\x00" as *const u8 as *const libc::c_char, real_query); dc_sqlite3_prepare(
if 0 != chat_id {
stmt = dc_sqlite3_prepare(
context, context,
&context.sql, &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 m.hidden=0 \
AND ct.blocked=0 AND (txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp,m.id;\x00" AND ct.blocked=0 AND (txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp,m.id;"
as *const u8 as *const libc::c_char ).and_then(|mut stmt| stmt.query_map(
); params![chat_id as libc::c_int, &strLikeInText, &strLikeBeg],
sqlite3_bind_int(stmt, 1, chat_id as libc::c_int); |row| row.get::<_, i32>(0)
sqlite3_bind_text(stmt, 2, strLikeInText, -1, None); ).and_then(|res| res.collect::<rusqlite::Result<Vec<i32>>>()).ok())
sqlite3_bind_text(stmt, 3, strLikeBeg, -1, None);
} else { } else {
let show_deaddrop = 0; let show_deaddrop = 0;
stmt = dc_sqlite3_prepare( dc_sqlite3_prepare(
context, context,
&context.sql, &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 \ 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 (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" AND ct.blocked=0 AND (m.txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp DESC,m.id DESC;"
as *const u8 as *const libc::c_char ).and_then(|mut stmt|
); stmt.query_map(params![
sqlite3_bind_int(stmt, 1, if 0 != show_deaddrop { 2 } else { 0 }); if 0 != show_deaddrop { 2 } else { 0 },
sqlite3_bind_text(stmt, 2, strLikeInText, -1, None); strLikeInText, strLikeBeg,
sqlite3_bind_text(stmt, 3, strLikeBeg, -1, None); ], |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); if success {
free(strLikeBeg as *mut libc::c_void);
free(real_query as *mut libc::c_void);
sqlite3_finalize(stmt);
if 0 != success {
ret ret
} else { } else {
if !ret.is_null() { if !ret.is_null() {
dc_array_unref(ret); unsafe { dc_array_unref(ret) };
} }
0 as *mut dc_array_t 0 as *mut dc_array_t
} }
} }
pub unsafe fn dc_is_inbox(_context: &Context, folder_name: *const libc::c_char) -> libc::c_int { pub fn dc_is_inbox(_context: &Context, folder_name: impl AsRef<str>) -> bool {
let mut is_inbox = 0; folder_name.as_ref() == "INBOX"
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 unsafe fn dc_is_sentbox(context: &Context, folder_name: *const libc::c_char) -> libc::c_int { pub fn dc_is_sentbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
let sentbox_name = dc_sqlite3_get_config( let sentbox_name =
context, dc_sqlite3_get_config(context, &context.sql, "configured_sentbox_folder", None);
&context.sql, if let Some(name) = sentbox_name {
b"configured_sentbox_folder\x00" as *const u8 as *const libc::c_char, name == folder_name.as_ref()
0 as *const libc::c_char, } else {
); false
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
}
} }
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 { pub fn dc_is_mvbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
let mvbox_name = dc_sqlite3_get_config( let mvbox_name = dc_sqlite3_get_config(context, &context.sql, "configured_mvbox_folder", None);
context,
&context.sql, if let Some(name) = mvbox_name {
b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char, name == folder_name.as_ref()
0 as *const libc::c_char, } else {
); false
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
}
} }
free(mvbox_name as *mut libc::c_void);
is_mvbox
} }

File diff suppressed because it is too large Load Diff

View File

@@ -120,146 +120,163 @@ unsafe fn dc_chatlist_load_from_db(
mut chatlist: *mut dc_chatlist_t, mut chatlist: *mut dc_chatlist_t,
listflags: libc::c_int, listflags: libc::c_int,
query__: *const libc::c_char, query__: *const libc::c_char,
query_contact_id: uint32_t, query_contact_id: u32,
) -> libc::c_int { ) -> libc::c_int {
let current_block: u64;
//clock_t start = clock(); //clock_t start = clock();
let mut success: libc::c_int = 0i32;
let mut add_archived_link_item: libc::c_int = 0i32; if chatlist.is_null() || (*chatlist).magic != 0xc4a71157u32 {
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; return 0;
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
}
}
} }
sqlite3_finalize(stmt); dc_chatlist_empty(chatlist);
free(query as *mut libc::c_void);
free(strLikeCmd as *mut libc::c_void); let mut add_archived_link_item = 0;
success
// 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 // Context functions to work with chatlist
pub unsafe fn dc_get_archived_cnt(context: &Context) -> libc::c_int { pub fn dc_get_archived_cnt(context: &Context) -> libc::c_int {
let mut ret: libc::c_int = 0i32; dc_sqlite3_query_row(
let stmt: *mut sqlite3_stmt = dc_sqlite3_prepare(
context, context,
&context.sql, &context.sql,
b"SELECT COUNT(*) FROM chats WHERE blocked=0 AND archived=1;\x00" as *const u8 "SELECT COUNT(*) FROM chats WHERE blocked=0 AND archived=1;",
as *const libc::c_char, params![],
); 0,
if sqlite3_step(stmt) == 100i32 { )
ret = sqlite3_column_int(stmt, 0i32) .unwrap_or_default()
}
sqlite3_finalize(stmt);
ret
} }
unsafe fn get_last_deaddrop_fresh_msg(context: &Context) -> uint32_t { fn get_last_deaddrop_fresh_msg(context: &Context) -> u32 {
let mut ret: uint32_t = 0i32 as uint32_t; // we have an index over the state-column, this should be sufficient as there are typically only few fresh messages
let stmt: *mut sqlite3_stmt; dc_sqlite3_query_row(
stmt = context,
dc_sqlite3_prepare( &context.sql,
context, "SELECT m.id FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id \
&context.sql, WHERE m.state=10 \
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" AND m.hidden=0 \
as *const u8 as *const libc::c_char); AND c.blocked=2 \
/* we have an index over the state-column, this should be sufficient as there are typically only few fresh messages */ ORDER BY m.timestamp DESC, m.id DESC;",
if !(sqlite3_step(stmt) != 100i32) { params![],
ret = sqlite3_column_int(stmt, 0i32) as uint32_t 0,
} )
sqlite3_finalize(stmt); .unwrap_or_default()
ret
} }
pub unsafe fn dc_chatlist_get_cnt(chatlist: *const dc_chatlist_t) -> size_t { pub unsafe fn dc_chatlist_get_cnt(chatlist: *const dc_chatlist_t) -> size_t {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -82,28 +82,18 @@ pub unsafe fn dc_e2ee_encrypt(
|| plain.is_null()) || 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. */ /* 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 let prefer_encrypt =
!= dc_sqlite3_get_config_int( if 0 != dc_sqlite3_get_config_int(context, &context.sql, "e2ee_enabled", 1) {
context, EncryptPreference::Mutual
&context.sql, } else {
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char, EncryptPreference::NoPreference
1, };
) {
EncryptPreference::Mutual
} else {
EncryptPreference::NoPreference
};
let addr = dc_sqlite3_get_config( let addr = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None);
context,
&context.sql,
b"configured_addr\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
if !addr.is_null() { if let Some(addr) = addr {
if let Some(public_key) = 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*/ /*only for random-seed*/
if prefer_encrypt == EncryptPreference::Mutual || 0 != e2ee_guaranteed { if prefer_encrypt == EncryptPreference::Mutual || 0 != e2ee_guaranteed {
@@ -111,15 +101,10 @@ pub unsafe fn dc_e2ee_encrypt(
let mut iter1: *mut clistiter; let mut iter1: *mut clistiter;
iter1 = (*recipients_addr).first; iter1 = (*recipients_addr).first;
while !iter1.is_null() { while !iter1.is_null() {
let recipient_addr: *const libc::c_char = (if !iter1.is_null() { let recipient_addr = to_string((*iter1).data as *const libc::c_char);
(*iter1).data if recipient_addr != addr {
} else {
0 as *mut libc::c_void
})
as *const libc::c_char;
if strcasecmp(recipient_addr, addr) != 0 {
let peerstate = let peerstate =
Peerstate::from_addr(context, &context.sql, as_str(recipient_addr)); Peerstate::from_addr(context, &context.sql, &recipient_addr);
if peerstate.is_some() if peerstate.is_some()
&& (peerstate.as_ref().unwrap().prefer_encrypt && (peerstate.as_ref().unwrap().prefer_encrypt
== EncryptPreference::Mutual == EncryptPreference::Mutual
@@ -366,8 +351,7 @@ pub unsafe fn dc_e2ee_encrypt(
match current_block { match current_block {
14181132614457621749 => {} 14181132614457621749 => {}
_ => { _ => {
let addr = CStr::from_ptr(addr).to_str().unwrap(); let aheader = Aheader::new(addr, public_key, prefer_encrypt);
let aheader = Aheader::new(addr.into(), public_key, prefer_encrypt);
let rendered = CString::new(aheader.to_string()).unwrap(); let rendered = CString::new(aheader.to_string()).unwrap();
mailimf_fields_add( mailimf_fields_add(
@@ -503,13 +487,13 @@ unsafe fn new_data_part(
******************************************************************************/ ******************************************************************************/
unsafe fn load_or_generate_self_public_key( unsafe fn load_or_generate_self_public_key(
context: &Context, context: &Context,
self_addr: *const libc::c_char, self_addr: impl AsRef<str>,
_random_data_mime: *mut mailmime, _random_data_mime: *mut mailmime,
) -> Option<Key> { ) -> Option<Key> {
/* avoid double creation (we unlock the database during creation) */ /* 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() { if key.is_some() {
return key; return key;
} }
@@ -521,36 +505,33 @@ unsafe fn load_or_generate_self_public_key(
let key_creation_here = 1; let key_creation_here = 1;
s_in_key_creation = 1; s_in_key_creation = 1;
let start: libc::clock_t = clock(); let start = clock();
dc_log_info( info!(
context, context,
0i32, 0, "Generating keypair with {} bits, e={} ...", 2048, 65537,
b"Generating keypair with %i bits, e=%i ...\x00" as *const u8 as *const libc::c_char,
2048i32,
65537i32,
); );
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( if !dc_key_save_self_keypair(
context, context,
&public_key, &public_key,
&private_key, &private_key,
self_addr, &self_addr,
1i32, 1i32,
&context.sql, &context.sql,
) { ) {
/*set default*/ /*set default*/
dc_log_warning( dc_log_warning(
context, context,
0i32, 0,
b"Cannot save keypair.\x00" as *const u8 as *const libc::c_char, b"Cannot save keypair.\x00" as *const u8 as *const libc::c_char,
); );
} else { } else {
dc_log_info( dc_log_info(
context, context,
0i32, 0,
b"Keypair generated in %.3f s.\x00" as *const u8 as *const libc::c_char, 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 { } else {
dc_log_warning( dc_log_warning(
context, context,
0i32, 0,
b"Cannot create keypair.\x00" as *const u8 as *const libc::c_char, 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 imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
let mut message_time = 0; let mut message_time = 0;
let mut from: *mut libc::c_char = 0 as *mut libc::c_char; let mut from: *mut libc::c_char = 0 as *mut libc::c_char;
let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
let mut private_keyring = Keyring::default(); let mut private_keyring = Keyring::default();
let mut public_keyring_for_validate = Keyring::default(); let mut public_keyring_for_validate = Keyring::default();
let mut gossip_headers: *mut mailimf_fields = 0 as *mut mailimf_fields; 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 mut peerstate) = peerstate {
if let Some(ref header) = autocryptheader { 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); 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) && 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); peerstate.save_to_db(&context.sql, false);
} }
} else if let Some(ref header) = autocryptheader { } 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); p.save_to_db(&context.sql, true);
peerstate = Some(p); peerstate = Some(p);
} }
} }
/* load private key for decryption */ /* load private key for decryption */
self_addr = dc_sqlite3_get_config( let self_addr = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None);
context, if let Some(self_addr) = self_addr {
&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() {
if private_keyring.load_self_private_for_decrypting(context, self_addr, &context.sql) { 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 { if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
peerstate = Peerstate::from_addr(&context, &context.sql, as_str(from)); 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(from as *mut libc::c_void);
free(self_addr as *mut libc::c_void);
} }
unsafe fn update_gossip_peerstates( unsafe fn update_gossip_peerstates(
@@ -722,10 +696,10 @@ unsafe fn update_gossip_peerstates(
let mut peerstate = let mut peerstate =
Peerstate::from_addr(context, &context.sql, &header.addr); Peerstate::from_addr(context, &context.sql, &header.addr);
if let Some(ref mut peerstate) = peerstate { 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); peerstate.save_to_db(&context.sql, false);
} else { } 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); p.save_to_db(&context.sql, true);
peerstate = Some(p); 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) */ (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 mut success: libc::c_int = 0i32;
let self_addr = dc_sqlite3_get_config( let self_addr = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None);
context, if self_addr.is_none() {
&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_warning( dc_log_warning(
context, context,
0i32, 0i32,
b"Cannot ensure secret key if context is not configured.\x00" as *const u8 b"Cannot ensure secret key if context is not configured.\x00" as *const u8
as *const libc::c_char, 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*/ /*no random text data for seeding available*/
success = 1i32 success = 1i32
} }
free(self_addr as *mut libc::c_void);
success success
} }

View File

@@ -236,7 +236,6 @@ pub unsafe extern "C" fn dc_render_setup_file(
passphrase: *const libc::c_char, passphrase: *const libc::c_char,
) -> *mut libc::c_char { ) -> *mut libc::c_char {
let stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; 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 passphrase_begin: [libc::c_char; 8] = [0; 8];
let mut ret_setupfilecontent: *mut libc::c_char = 0 as *mut libc::c_char; 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; passphrase_begin[2usize] = 0i32 as libc::c_char;
/* create the payload */ /* create the payload */
if !(0 == dc_ensure_secret_key_exists(context)) { if !(0 == dc_ensure_secret_key_exists(context)) {
self_addr = dc_sqlite3_get_config( let self_addr = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None)
context, .unwrap_or_default();
&context.sql, let curr_private_key =
b"configured_addr\x00" as *const u8 as *const libc::c_char, Key::from_self_private(context, self_addr, &context.sql.clone().read().unwrap());
0 as *const libc::c_char, let e2ee_enabled = dc_sqlite3_get_config_int(context, &context.sql, "e2ee_enabled", 1);
);
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 headers = if 0 != e2ee_enabled { let headers = if 0 != e2ee_enabled {
Some(("Autocrypt-Prefer-Encrypt", "mutual")) Some(("Autocrypt-Prefer-Encrypt", "mutual"))
@@ -311,8 +302,6 @@ pub unsafe extern "C" fn dc_render_setup_file(
} }
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
free(self_addr as *mut libc::c_void);
ret_setupfilecontent 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()) { if !(msg_id <= 9i32 as libc::c_uint || setup_code.is_null()) {
msg = dc_get_msg(context, msg_id); msg = dc_get_msg(context, msg_id);
if msg.is_null() if msg.is_null()
|| 0 == dc_msg_is_setupmessage(msg) || !dc_msg_is_setupmessage(msg)
|| { || {
filename = dc_msg_get_file(msg); filename = dc_msg_get_file(msg);
filename.is_null() filename.is_null()
@@ -400,7 +389,7 @@ pub unsafe fn dc_continue_key_transfer(
} }
// TODO should return bool /rtn // TODO should return bool /rtn
unsafe fn set_self_key( fn set_self_key(
context: &Context, context: &Context,
armored_c: *const libc::c_char, armored_c: *const libc::c_char,
set_default: libc::c_int, set_default: libc::c_int,
@@ -413,88 +402,80 @@ unsafe fn set_self_key(
assert!(!armored_c.is_null(), "invalid buffer"); assert!(!armored_c.is_null(), "invalid buffer");
let armored = as_str(armored_c); let armored = as_str(armored_c);
if let Some((private_key, public_key, header)) = let keys = Key::from_armored_string(armored, KeyType::Private)
Key::from_armored_string(armored, KeyType::Private) .and_then(|(k, h)| if k.verify() { Some((k, h)) } else { None })
.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)));
.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");
if let Some(prefer_encrypt) = prefer_encrypt { if keys.is_none() {
if prefer_encrypt == "nopreference" { error!(context, 0, "File does not contain a valid private key.",);
dc_sqlite3_set_config_int( return 0;
context, }
&context.sql,
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char, let (private_key, public_key, header) = keys.unwrap();
0i32, let preferencrypt = header.get("Autocrypt-Prefer-Encrypt");
);
} else if prefer_encrypt == "mutual" { if !dc_sqlite3_execute(
dc_sqlite3_set_config_int( context,
context, &context.sql,
&context.sql, "DELETE FROM keypairs WHERE public_key=? OR private_key=?;",
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char, params![public_key.to_bytes(), private_key.to_bytes()],
1i32, ) {
); return 0;
} }
}
success = 1; if 0 != set_default {
if !dc_sqlite3_execute(
context,
&context.sql,
"UPDATE keypairs SET is_default=0;",
params![],
) {
return 0;
} }
} else { } else {
error!(context, 0, "File does not contain a private key.",); error!(context, 0, "File does not contain a private key.",);
} }
sqlite3_finalize(stmt); let self_addr = dc_sqlite3_get_config(
free(self_addr as *mut libc::c_void); 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( 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 // TODO should return bool /rtn
unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char) -> libc::c_int { unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char) -> libc::c_int {
let current_block: u64; let mut success = 0;
let mut success: libc::c_int = 0i32; let mut processed_files_cnt = 0;
let mut processed_files_cnt: libc::c_int = 0i32;
let total_files_cnt: libc::c_int; let total_files_cnt: usize;
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
let mut pathNfilename: *mut libc::c_char = 0 as *mut libc::c_char; info!(
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(
context, context,
0i32, 0,
b"Import \"%s\" to \"%s\".\x00" as *const u8 as *const libc::c_char, "Import \"{}\" to \"{}\".",
backup_to_import, as_str(backup_to_import),
context.get_dbfile(), as_str(context.get_dbfile()),
); );
if 0 != dc_is_configured(context) { if 0 != dc_is_configured(context) {
dc_log_error( error!(context, 0, "Cannot import backups to accounts in use.");
context,
0i32,
b"Cannot import backups to accounts in use.\x00" as *const u8 as *const libc::c_char,
);
} else { } else {
&context.sql.close(&context); &context.sql.close(&context);
dc_delete_file(context, context.get_dbfile()); dc_delete_file(context, context.get_dbfile());
if 0 != dc_file_exist(context, context.get_dbfile()) { if 0 != dc_file_exist(context, context.get_dbfile()) {
dc_log_error( error!(
context, context,
0i32, 0, "Cannot import backups: Cannot delete the old file.",
b"Cannot import backups: Cannot delete the old file.\x00" as *const u8
as *const libc::c_char,
); );
} else if !(0 == dc_copy_file(context, backup_to_import, context.get_dbfile())) { } else if !(0 == dc_copy_file(context, backup_to_import, context.get_dbfile())) {
/* error already logged */ /* error already logged */
/* re-open copied database file */ /* re-open copied database file */
if context.sql.open(&context, as_path(context.get_dbfile()), 0) { 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,
&context.sql, &context.sql,
b"SELECT COUNT(*) FROM backup_blobs;\x00" as *const u8 as *const libc::c_char, "SELECT COUNT(*) FROM backup_blobs;",
); params![],
sqlite3_step(stmt); 0,
total_files_cnt = sqlite3_column_int(stmt, 0i32); )
.unwrap_or_default() as usize;
info!( info!(
context, 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,
&context.sql, &context.sql,
b"SELECT file_name, file_content FROM backup_blobs ORDER BY id;\x00" "SELECT file_name, file_content FROM backup_blobs ORDER BY id;",
as *const u8 as *const libc::c_char, ) {
); stmt.query_map(params![], |row| {
loop { let name: String = row.get(0)?;
if !(sqlite3_step(stmt) == 100i32) { let blob: Vec<u8> = row.get(1)?;
current_block = 10891380440665537214;
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; break;
} }
let (file_name, file_blob) = file.unwrap();
if context if context
.running_state .running_state
.clone() .clone()
@@ -908,82 +896,52 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
.unwrap() .unwrap()
.shall_stop_ongoing .shall_stop_ongoing
{ {
current_block = 8648553629232744886; loop_success = false;
break; break;
} }
processed_files_cnt += 1; processed_files_cnt += 1;
let mut permille: libc::c_int = processed_files_cnt * 1000i32 / total_files_cnt; let mut permille = processed_files_cnt * 1000 / total_files_cnt;
if permille < 10i32 { if permille < 10 {
permille = 10i32 permille = 10
} }
if permille > 990i32 { if permille > 990 {
permille = 990i32 permille = 990
} }
context.call_cb( context.call_cb(Event::IMEX_PROGRESS, permille as uintptr_t, 0);
Event::IMEX_PROGRESS, if file_blob.is_empty() {
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()) {
continue; continue;
} }
free(pathNfilename as *mut libc::c_void);
pathNfilename = dc_mprintf( let pathNfilename = format!("{}/{}", as_str(context.get_blobdir()), file_name);
b"%s/%s\x00" as *const u8 as *const libc::c_char, if dc_write_file_safe(context, &pathNfilename, &file_blob) {
context.get_blobdir(),
file_name,
);
if !(0
== dc_write_file(
context,
pathNfilename,
file_content,
file_bytes as size_t,
))
{
continue; continue;
} }
dc_log_error(
error!(
context, context,
0i32, 0,
b"Storage full? Cannot write file %s with %i bytes.\x00" as *const u8 "Storage full? Cannot write file {} with {} bytes.",
as *const libc::c_char, &pathNfilename,
pathNfilename, file_blob.len(),
file_bytes,
); );
/* otherwise the user may believe the stuff is imported correctly, but there are files missing ... */ // otherwise the user may believe the stuff is imported correctly, but there are files missing ...
current_block = 8648553629232744886; loop_success = false;
break; break;
} }
match current_block {
8648553629232744886 => {} if loop_success {
_ => { dc_sqlite3_execute(
sqlite3_finalize(stmt); context,
stmt = 0 as *mut sqlite3_stmt; &context.sql,
dc_sqlite3_execute( "DROP TABLE backup_blobs;",
context, params![],
&context.sql, );
b"DROP TABLE backup_blobs;\x00" as *const u8 as *const libc::c_char, dc_sqlite3_try_execute(context, &context.sql, "VACUUM;");
); success = 1;
dc_sqlite3_try_execute(
context,
&context.sql,
b"VACUUM;\x00" as *const u8 as *const libc::c_char,
);
success = 1i32
}
} }
} }
} }
} }
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 success
} }
@@ -996,15 +954,10 @@ The macro avoids weird values of 0% or 100% while still working. */
// TODO should return bool /rtn // TODO should return bool /rtn
unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_int { unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_int {
let mut current_block: u64; 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 closed: libc::c_int;
let mut curr_pathNfilename: *mut libc::c_char = 0 as *mut libc::c_char; let mut delete_dest_file: libc::c_int = 0;
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;
// get a fine backup file name (the name includes the date so that multiple backup instances are possible) // 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) // 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(); 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() { if dest_pathNfilename.is_null() {
dc_log_error( dc_log_error(
context, context,
0i32, 0,
b"Cannot get backup file name.\x00" as *const u8 as *const libc::c_char, 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_housekeeping(context);
dc_sqlite3_try_execute(
context, dc_sqlite3_try_execute(context, &context.sql, "VACUUM;");
&context.sql, dc_sqlite3_close(context, &mut context.sql);
b"VACUUM;\x00" as *const u8 as *const libc::c_char, closed = 1;
); dc_log_info(
context.sql.close(&context);
closed = 1i32;
info!(
context, context,
0, 0,
"Backup \"{}\" to \"{}\".", b"Backup \"%s\" to \"%s\".\x00" as *const u8 as *const libc::c_char,
as_str(context.get_dbfile()), context.get_dbfile(),
as_str(dest_pathNfilename), dest_pathNfilename,
); );
if !(0 == dc_copy_file(context, 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); 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) */ /* 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*/ /*for logging only*/
let sql = SQLite::new(); let sql = SQLite::new();
if sql.open(context, as_path(dest_pathNfilename), 0) { if sql.open(context, as_path(dest_pathNfilename), 0) {
if 0 == dc_sqlite3_table_exists( if 0 == dc_sqlite3_table_exists(context, &sql, "backup_blobs") {
context, if !dc_sqlite3_execute(
&sql, context,
b"backup_blobs\x00" as *const u8 as *const libc::c_char, &sql,
) { "CREATE TABLE backup_blobs (id INTEGER PRIMARY KEY, file_name, file_content);",
if 0 == params![],
dc_sqlite3_execute(context, &sql, ) {
b"CREATE TABLE backup_blobs (id INTEGER PRIMARY KEY, file_name, file_content);\x00" /* error already logged */
as *const u8 as current_block = 11487273724841241105;
*const libc::c_char) { } else {
/* error already logged */ current_block = 14648156034262866959;
current_block = 11487273724841241105; }
} else { current_block = 14648156034262866959; }
} else { } else {
current_block = 14648156034262866959; 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() { if dir_handle.is_err() {
dc_log_error( dc_log_error(
context, context,
0i32, 0,
b"Backup: Cannot get info for blob-directory \"%s\".\x00" as *const u8 b"Backup: Cannot get info for blob-directory \"%s\".\x00" as *const u8
as *const libc::c_char, as *const libc::c_char,
context.get_blobdir(), context.get_blobdir(),
@@ -1088,17 +1037,15 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
context, context,
0, 0,
"Backup: Cannot copy from blob-directory \"{}\".", "Backup: Cannot copy from blob-directory \"{}\".",
as_str(context.get_blobdir()), context.get_blobdir(),
); );
} else { } else {
let dir_handle = dir_handle.unwrap(); let dir_handle = dir_handle.unwrap();
stmt = dc_sqlite3_prepare( let mut stmt = dc_sqlite3_prepare(
context, context,
&sql, &sql,
b"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);\x00" "INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);"
as *const u8 as ).expect("bad sql state");
*const libc::c_char
);
let mut processed_files_cnt = 0; let mut processed_files_cnt = 0;
for entry in dir_handle { 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( context.call_cb(
Event::IMEX_PROGRESS, Event::IMEX_PROGRESS,
permille as uintptr_t, permille as uintptr_t,
0i32 as uintptr_t, 0 as uintptr_t,
); );
let name_f = entry.file_name(); let name_f = entry.file_name();
let name = name_f.to_string_lossy(); 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; continue;
} else { } else {
info!(context, 0, "EXPORTing filename={}", name); info!(context, 0, "EXPORTing filename={}", name);
free(curr_pathNfilename as *mut libc::c_void); let curr_pathNfilename = format!(
let name_c = to_cstring(name); "{}/{}",
curr_pathNfilename = dc_mprintf( as_str(context.get_blobdir()),
b"%s/%s\x00" as *const u8 as *const libc::c_char, name
context.get_blobdir(),
name_c.as_ptr(),
); );
free(buf);
if 0 == dc_read_file( if let Some(buf) =
context, dc_read_file_safe(context, &curr_pathNfilename)
curr_pathNfilename,
&mut buf,
&mut buf_bytes,
) || buf.is_null()
|| buf_bytes <= 0
{ {
continue; if buf.is_empty() {
} continue;
sqlite3_bind_text( }
stmt, if stmt.execute(params![name, buf]).is_err() {
1i32, error!(
name_c.as_ptr(), context,
-1i32, 0,
None, "Disk full? Cannot add file \"{}\" to backup.",
); &curr_pathNfilename,
sqlite3_bind_blob( );
stmt, /* this is not recoverable! writing to the sqlite database should work! */
2i32, current_block = 11487273724841241105;
buf, break;
buf_bytes as libc::c_int, }
None, // TODO: do we need to reset the stmt?
);
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;
} else { } else {
sqlite3_reset(stmt); continue;
} }
} }
} }
} }
} }
} else { } else {
info!(context, 0, "Backup: No files to copy."); info!(context, 0, "Backup: No files to copy.",);
current_block = 2631791190359682872; current_block = 2631791190359682872;
} }
match current_block { match current_block {
11487273724841241105 => {} 11487273724841241105 => {}
_ => { _ => {
dc_sqlite3_set_config_int( if 0 != dc_sqlite3_set_config_int(
context, context,
&sql, &sql,
b"backup_time\x00" as *const u8 as *const libc::c_char, "backup_time",
now as int32_t, now as i32,
); ) {
context.call_cb( context.call_cb(
Event::IMEX_FILE_WRITTEN, Event::IMEX_FILE_WRITTEN,
dest_pathNfilename as uintptr_t, dest_pathNfilename as uintptr_t,
0i32 as uintptr_t, 0,
); );
success = 1i32 success = 1;
}
} }
} }
} }
} }
} }
} }
dest_sql = Some(sql);
} }
if 0 != closed { if 0 != closed {
context.sql.open(&context, as_path(context.get_dbfile()), 0); 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); dc_delete_file(context, dest_pathNfilename);
} }
free(dest_pathNfilename as *mut libc::c_void); free(dest_pathNfilename as *mut libc::c_void);
free(curr_pathNfilename as *mut libc::c_void);
free(buf);
success 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 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) */ (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 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 path_plus_name: *mut libc::c_char = 0 as *mut libc::c_char;
let mut set_default: libc::c_int; let mut set_default: libc::c_int;
let mut buf: *mut libc::c_char = 0 as *mut libc::c_char; 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 // a pointer inside buf, MUST NOT be free()'d
let mut private_key: *const libc::c_char; let mut private_key: *const libc::c_char;
let mut buf2: *mut libc::c_char = 0 as *mut 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() { if dir_handle.is_err() {
dc_log_error( dc_log_error(
context, context,
0i32, 0,
b"Import: Cannot open directory \"%s\".\x00" as *const u8 as *const libc::c_char, b"Import: Cannot open directory \"%s\".\x00" as *const u8 as *const libc::c_char,
dir_name, 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()); let name_c = to_cstring(name_f.to_string_lossy());
suffix = dc_get_filesuffix_lc(name_c.as_ptr()); suffix = dc_get_filesuffix_lc(name_c.as_ptr());
if suffix.is_null() 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; continue;
} }
@@ -1289,7 +1215,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
); );
dc_log_info( dc_log_info(
context, context,
0i32, 0,
b"Checking: %s\x00" as *const u8 as *const libc::c_char, b"Checking: %s\x00" as *const u8 as *const libc::c_char,
path_plus_name, path_plus_name,
); );
@@ -1316,7 +1242,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
) && strcmp( ) && strcmp(
buf2_headerline, buf2_headerline,
b"-----BEGIN PGP PUBLIC KEY BLOCK-----\x00" as *const u8 as *const libc::c_char, b"-----BEGIN PGP PUBLIC KEY BLOCK-----\x00" as *const u8 as *const libc::c_char,
) == 0i32 ) == 0
{ {
private_key = strstr( private_key = strstr(
buf, buf,
@@ -1327,7 +1253,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
continue; continue;
} }
} }
set_default = 1i32; set_default = 1;
if !strstr( if !strstr(
name_c.as_ptr(), name_c.as_ptr(),
b"legacy\x00" as *const u8 as *const libc::c_char, 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 // TODO should return bool /rtn
unsafe fn export_self_keys(context: &Context, dir: *const libc::c_char) -> libc::c_int { 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 = 0;
let mut export_errors: libc::c_int = 0i32;
let mut id: libc::c_int; if let Some(mut stmt) = dc_sqlite3_prepare(
let mut is_default: libc::c_int;
let stmt = dc_sqlite3_prepare(
context, context,
&context.sql, &context.sql,
b"SELECT id, public_key, private_key, is_default FROM keypairs;\x00" as *const u8 "SELECT id, public_key, private_key, is_default FROM keypairs;",
as *const libc::c_char, ) {
); let rows = stmt.query_map(params![], |row| {
if !stmt.is_null() { let id = row.get(0)?;
while sqlite3_step(stmt) == 100i32 { let public_key_blob: Vec<u8> = row.get(1)?;
id = sqlite3_column_int(stmt, 0i32); let public_key = Key::from_slice(&public_key_blob, KeyType::Public);
let public_key = Key::from_stmt(stmt, 1, KeyType::Public); let private_key_blob: Vec<u8> = row.get(2)?;
let private_key = Key::from_stmt(stmt, 2, KeyType::Private); let private_key = Key::from_slice(&private_key_blob, KeyType::Private);
let is_default = row.get(3)?;
is_default = sqlite3_column_int(stmt, 3i32); Ok((id, public_key, private_key, is_default))
if let Some(key) = public_key { });
if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) {
export_errors += 1 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 { } else {
success = 1i32 return 1;
}
} }
sqlite3_finalize(stmt);
success if export_errors == 0 {
1
} else {
0
}
} }
/******************************************************************************* /*******************************************************************************

View File

@@ -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) { unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: libc::c_int) {
let mut select_stmt: *mut sqlite3_stmt; let process_row = |row: &rusqlite::Row| {
let mut job = dc_job_t { let job = dc_job_t {
job_id: 0, job_id: row.get(0)?,
action: 0, action: row.get(1)?,
foreign_id: 0, foreign_id: row.get(2)?,
desired_timestamp: 0, desired_timestamp: row.get(5)?,
added_timestamp: 0, added_timestamp: row.get(4)?,
tries: 0, tries: row.get(6)?,
param: 0 as *mut dc_param_t, param: dc_param_new(),
try_again: 0, try_again: 0,
pending_error: 0 as *mut libc::c_char, pending_error: 0 as *mut libc::c_char,
}; };
job.param = dc_param_new();
if probe_network == 0i32 { let packed: String = row.get(3)?;
select_stmt = dc_param_set_packed(job.param, to_cstring(packed).as_ptr());
dc_sqlite3_prepare( Ok(job)
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" let jobs = if probe_network == 0 {
as *const u8 as *const libc::c_char); if let Some(mut stmt) = dc_sqlite3_prepare(
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(
context, context,
0i32, &context.sql,
b"%s-job #%i, action %i started...\x00" as *const u8 as *const libc::c_char, "SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \
if thread == 100i32 { FROM jobs WHERE thread=? AND desired_timestamp<=? ORDER BY action DESC, added_timestamp;"
b"INBOX\x00" as *const u8 as *const libc::c_char ) {
} else { stmt.query_map(params![thread as i64, time()], process_row)
b"SMTP\x00" as *const u8 as *const libc::c_char .and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()).ok()
}, } else {
job.job_id as libc::c_int, None
job.action as libc::c_int, }
} 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); 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.sentbox_thread.clone().read().unwrap(), 1);
dc_jobthread_suspend(context, &context.mvbox_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; let mut tries = 0;
while tries <= 1i32 { while tries <= 1 {
job.try_again = 0i32; job.try_again = 0;
match job.action { match job.action {
5901 => { 5901 => {
dc_job_do_DC_JOB_SEND(context, &mut job); 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; break;
} }
tries += 1 tries += 1
} }
if 900i32 == job.action || 910i32 == job.action { if 900 == job.action || 910 == job.action {
dc_jobthread_suspend( dc_jobthread_suspend(
context, context,
&mut context.sentbox_thread.clone().read().unwrap(), &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(), &mut context.mvbox_thread.clone().read().unwrap(),
0, 0,
); );
dc_suspend_smtp_thread(context, 0i32); dc_suspend_smtp_thread(context, 0);
break; break;
} else if job.try_again == 2i32 { } else if job.try_again == 2 {
dc_log_info( info!(
context, context,
0i32, 0,
b"%s-job #%i not yet ready and will be delayed.\x00" as *const u8 "{}-job #{} not yet ready and will be delayed.",
as *const libc::c_char, if thread == 100 { "INBOX" } else { "SMTP" },
if thread == 100i32 { job.job_id
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,
); );
} else if job.try_again == -1i32 || job.try_again == 3i32 { } else if job.try_again == -1 || job.try_again == 3 {
let tries_0: libc::c_int = job.tries + 1i32; let tries = job.tries + 1;
if tries_0 < 17i32 { if tries < 17 {
job.tries = tries_0; job.tries = tries;
let time_offset = get_backoff_time_offset(tries_0); let time_offset = get_backoff_time_offset(tries);
job.desired_timestamp = job.added_timestamp + time_offset; job.desired_timestamp = job.added_timestamp + time_offset;
dc_job_update(context, &mut job); dc_job_update(context, &mut job);
dc_log_info(context, 0i32, info!(
b"%s-job #%i not succeeded on try #%i, retry in ADD_TIME+%i (in %i seconds).\x00" context,
as *const u8 as *const libc::c_char, 0,
if thread == 100i32 { "{}-job #{} not succeeded on try #{}, retry in ADD_TIME+{} (in {} seconds).",
b"INBOX\x00" as *const u8 as if thread == 100 { "INBOX" } else { "SMTP" },
*const libc::c_char job.job_id as libc::c_int,
} else { tries,
b"SMTP\x00" as *const u8 as time_offset,
*const libc::c_char job.added_timestamp + time_offset - time()
}, job.job_id as libc::c_int, tries_0, );
time_offset, if thread == 5000 && tries < 17 - 1 {
job.added_timestamp + time_offset -
time());
if thread == 5000i32 && tries_0 < 17i32 - 1i32 {
context context
.smtp_state .smtp_state
.clone() .clone()
.0 .0
.lock() .lock()
.unwrap() .unwrap()
.perform_jobs_needed = 2i32; .perform_jobs_needed = 2;
} }
} else { } else {
if job.action == 5901i32 { if job.action == 5901 {
dc_set_msg_failed(context, job.foreign_id, job.pending_error); dc_set_msg_failed(context, job.foreign_id, job.pending_error);
} }
dc_job_delete(context, &mut job); dc_job_delete(context, &mut job);
} }
if !(0 != probe_network) { if 0 == probe_network {
continue; continue;
} }
// on dc_maybe_network() we stop trying here; // 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 { } else {
dc_job_delete(context, &mut job); 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) { fn dc_job_delete(context: &Context, job: &dc_job_t) -> bool {
let delete_stmt: *mut sqlite3_stmt = dc_sqlite3_prepare( dc_sqlite3_execute(
context, context,
&context.sql, &context.sql,
b"DELETE FROM jobs WHERE id=?;\x00" as *const u8 as *const libc::c_char, "DELETE FROM jobs WHERE id=?;",
); params![job.job_id as i32],
sqlite3_bind_int(delete_stmt, 1i32, job.job_id as libc::c_int); )
sqlite3_step(delete_stmt);
sqlite3_finalize(delete_stmt);
} }
/* ****************************************************************************** /* ******************************************************************************
@@ -279,20 +270,20 @@ unsafe fn get_backoff_time_offset(c_tries: libc::c_int) -> i64 {
seconds as i64 seconds as i64
} }
unsafe fn dc_job_update(context: &Context, job: &dc_job_t) { fn dc_job_update(context: &Context, job: &dc_job_t) -> bool {
let stmt: *mut sqlite3_stmt = dc_sqlite3_prepare( dc_sqlite3_execute(
context, context,
&context.sql, &context.sql,
b"UPDATE jobs SET desired_timestamp=?, tries=?, param=? WHERE id=?;\x00" as *const u8 "UPDATE jobs SET desired_timestamp=?, tries=?, param=? WHERE id=?;",
as *const libc::c_char, params![
); job.desired_timestamp,
sqlite3_bind_int64(stmt, 1i32, job.desired_timestamp as sqlite3_int64); job.tries as i64,
sqlite3_bind_int64(stmt, 2i32, job.tries as sqlite3_int64); as_str(unsafe { (*job.param).packed }),
sqlite3_bind_text(stmt, 3i32, (*job.param).packed, -1i32, None); job.job_id as i32,
sqlite3_bind_int(stmt, 4i32, job.job_id as libc::c_int); ],
sqlite3_step(stmt); )
sqlite3_finalize(stmt);
} }
unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: libc::c_int) { unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: libc::c_int) {
context.smtp_state.0.lock().unwrap().suspended = suspend; context.smtp_state.0.lock().unwrap().suspended = suspend;
if 0 != 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: *mut libc::c_void = 0 as *mut libc::c_void;
let mut buf_bytes: size_t = 0i32 as size_t; 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 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 */ /* connect to SMTP server, if not yet done */
if !context.smtp.lock().unwrap().is_connected() { if !context.smtp.lock().unwrap().is_connected() {
let loginparam: *mut dc_loginparam_t = dc_loginparam_new(); let loginparam = dc_loginparam_read(context, &context.sql, "configured_");
dc_loginparam_read( let connected = context.smtp.lock().unwrap().connect(context, &loginparam);
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);
if 0 == connected { if 0 == connected {
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char); dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
current_block = 14216916617354591294; 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); dc_delete_file(context, filename);
if 0 != job.foreign_id { if 0 != job.foreign_id {
dc_update_msg_state(context, job.foreign_id, 26i32); dc_update_msg_state(context, job.foreign_id, 26i32);
stmt = dc_sqlite3_prepare( let chat_id: i32 = dc_sqlite3_query_row(
context, context,
&context.sql, &context.sql,
b"SELECT chat_id FROM msgs WHERE id=?\x00" as *const u8 "SELECT chat_id FROM msgs WHERE id=?",
as *const libc::c_char, params![job.foreign_id as i32],
); 0,
sqlite3_bind_int(stmt, 1i32, job.foreign_id as libc::c_int); )
let chat_id: libc::c_int = if sqlite3_step(stmt) == 100i32 { .unwrap_or_default();
sqlite3_column_int(stmt, 0i32)
} else {
0i32
};
context.call_cb( context.call_cb(
Event::MSG_DELIVERED, Event::MSG_DELIVERED,
chat_id as uintptr_t, 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(recipients as *mut libc::c_void);
free(buf); free(buf);
free(filename as *mut libc::c_void); free(filename as *mut libc::c_void);
} }
// this value does not increase the number of tries // this value does not increase the number of tries
pub unsafe fn dc_job_try_again_later( pub unsafe fn dc_job_try_again_later(
job: &mut dc_job_t, 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) { unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
let mut current_block: u64; let mut current_block: u64;
let msg: *mut dc_msg_t = dc_msg_new_untyped(context); let msg = dc_msg_new_untyped(context);
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 mut dest_uid: uint32_t = 0i32 as uint32_t;
let inbox = context.inbox.read().unwrap(); 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 { match current_block {
2473556513754201174 => { 2473556513754201174 => {
if dc_msg_load_from_db(msg, context, job.foreign_id) { if dc_msg_load_from_db(msg, context, job.foreign_id) {
if dc_sqlite3_get_config_int( if dc_sqlite3_get_config_int(context, &context.sql, "folders_configured", 0) < 3 {
context,
&context.sql,
b"folders_configured\x00" as *const u8 as *const libc::c_char,
0i32,
) < 3i32
{
inbox.configure_folders(context, 0x1i32); inbox.configure_folders(context, 0x1i32);
} }
dest_folder = dc_sqlite3_get_config( let dest_folder =
context, dc_sqlite3_get_config(context, &context.sql, "configured_mvbox_folder", None);
&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() { if let Some(dest_folder) = dest_folder {
let server_folder = as_str((*msg).server_folder); let server_folder = as_str((*msg).server_folder);
match inbox.mv( match inbox.mv(
context, context,
server_folder, server_folder,
(*msg).server_uid, (*msg).server_uid,
as_str(dest_folder), &dest_folder,
&mut dest_uid, &mut dest_uid,
) as libc::c_uint ) 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( dc_update_server_uid(
context, context,
(*msg).rfc724_mid, (*msg).rfc724_mid,
dest_folder, &dest_folder,
dest_uid, 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( dc_update_server_uid(
context, context,
(*msg).rfc724_mid, (*msg).rfc724_mid,
dest_folder, &dest_folder,
dest_uid, 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); dc_msg_unref(msg);
} }
/* ****************************************************************************** /* ******************************************************************************
* IMAP-jobs * IMAP-jobs
******************************************************************************/ ******************************************************************************/
fn connect_to_inbox(context: &Context, inbox: &Imap) -> libc::c_int { fn connect_to_inbox(context: &Context, inbox: &Imap) -> libc::c_int {
let ret_connected: libc::c_int; let ret_connected = unsafe { dc_connect_to_configured_imap(context, inbox) };
if 0 != ret_connected {
ret_connected = unsafe { dc_connect_to_configured_imap(context, inbox) }; inbox.set_watch_folder("INBOX".into());
if !(0 == ret_connected) {
inbox.set_watch_folder(b"INBOX\x00" as *const u8 as *const libc::c_char);
} }
ret_connected 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 current_block: u64;
let folder: *mut libc::c_char = dc_param_get(job.param, 'Z' as i32, 0 as *const libc::c_char); 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 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 mut dest_uid: uint32_t = 0i32 as uint32_t;
let inbox = context.inbox.read().unwrap(); 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); 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 0 != dc_param_get_int(job.param, 'M' as i32, 0i32) {
if dc_sqlite3_get_config_int( if dc_sqlite3_get_config_int(context, &context.sql, "folders_configured", 0) < 3 {
context,
&context.sql,
b"folders_configured\x00" as *const u8 as *const libc::c_char,
0i32,
) < 3i32
{
inbox.configure_folders(context, 0x1i32); inbox.configure_folders(context, 0x1i32);
} }
dest_folder = dc_sqlite3_get_config( let dest_folder =
context, dc_sqlite3_get_config(context, &context.sql, "configured_mvbox_folder", None);
&context.sql, if let Some(dest_folder) = dest_folder {
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);
if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid) if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid)
as libc::c_uint 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(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) { unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_job_t) {
let mut current_block: u64; let mut current_block: u64;
let msg: *mut dc_msg_t = dc_msg_new_untyped(context); 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( && 0 != dc_sqlite3_get_config_int(
context, context,
&context.sql, &context.sql,
b"mdns_enabled\x00" as *const u8 as *const libc::c_char, "mdns_enabled",
1i32, 1,
) )
{ {
let folder = 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( && 0 != dc_sqlite3_get_config_int(
context, context,
&context.sql, &context.sql,
b"mdns_enabled\x00" as *const u8 as *const libc::c_char, "mdns_enabled",
1i32, 1,
) )
{ {
let folder = let folder =
@@ -862,49 +819,39 @@ pub unsafe fn dc_job_add(
delay_seconds: libc::c_int, delay_seconds: libc::c_int,
) { ) {
let timestamp = time(); let timestamp = time();
let stmt: *mut sqlite3_stmt; let thread = if action >= 100 && action < 100 + 1000 {
let thread: libc::c_int; 100
if action >= 100i32 && action < 100i32 + 1000i32 { } else if action >= 5000 && action < 5000 + 1000 {
thread = 100i32 5000
} else if action >= 5000i32 && action < 5000i32 + 1000i32 {
thread = 5000i32
} else { } else {
return; return;
} };
stmt =
dc_sqlite3_prepare( dc_sqlite3_execute(
context, context,
&context.sql, &context.sql,
b"INSERT INTO jobs (added_timestamp, thread, action, foreign_id, param, desired_timestamp) VALUES (?,?,?,?,?,?);\x00" "INSERT INTO jobs (added_timestamp, thread, action, foreign_id, param, desired_timestamp) VALUES (?,?,?,?,?,?);",
as *const u8 as *const libc::c_char); params![
sqlite3_bind_int64(stmt, 1i32, timestamp as sqlite3_int64); timestamp,
sqlite3_bind_int(stmt, 2i32, thread); thread,
sqlite3_bind_int(stmt, 3i32, action); action,
sqlite3_bind_int(stmt, 4i32, foreign_id); foreign_id,
sqlite3_bind_text( if !param.is_null() {
stmt, as_str(param)
5i32, } else {
if !param.is_null() { ""
param },
} else { (timestamp + delay_seconds as i64)
b"\x00" as *const u8 as *const libc::c_char ]
},
-1i32,
None,
); );
sqlite3_bind_int64(
stmt, if thread == 100 {
6i32,
(timestamp + delay_seconds as i64) as sqlite3_int64,
);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
if thread == 100i32 {
dc_interrupt_imap_idle(context); dc_interrupt_imap_idle(context);
} else { } else {
dc_interrupt_smtp_idle(context); dc_interrupt_smtp_idle(context);
}; }
} }
pub unsafe fn dc_interrupt_smtp_idle(context: &Context) { pub unsafe fn dc_interrupt_smtp_idle(context: &Context) {
dc_log_info( dc_log_info(
context, 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 */ /* delete all pending jobs with the given action */
pub unsafe fn dc_job_kill_action(context: &Context, action: libc::c_int) { pub fn dc_job_kill_action(context: &Context, action: libc::c_int) -> bool {
let stmt = dc_sqlite3_prepare( dc_sqlite3_execute(
context, context,
&context.sql, &context.sql,
b"DELETE FROM jobs WHERE action=?;\x00" as *const u8 as *const libc::c_char, "DELETE FROM jobs WHERE action=?;",
); params![action],
sqlite3_bind_int(stmt, 1i32, action); )
sqlite3_step(stmt);
sqlite3_finalize(stmt);
} }
pub unsafe fn dc_perform_imap_fetch(context: &Context) { pub unsafe fn dc_perform_imap_fetch(context: &Context) {
let inbox = context.inbox.read().unwrap(); let inbox = context.inbox.read().unwrap();
let start = clock();
let start: libc::clock_t = clock();
if 0 == connect_to_inbox(context, &inbox) { if 0 == connect_to_inbox(context, &inbox) {
return; return;
} }
if dc_sqlite3_get_config_int( if dc_sqlite3_get_config_int(context, &context.sql, "inbox_watch", 1) == 0 {
context,
&context.sql,
b"inbox_watch\x00" as *const u8 as *const libc::c_char,
1i32,
) == 0i32
{
dc_log_info( dc_log_info(
context, context,
0i32, 0,
b"INBOX-watch disabled.\x00" as *const u8 as *const libc::c_char, b"INBOX-watch disabled.\x00" as *const u8 as *const libc::c_char,
); );
return; return;
} }
dc_log_info( dc_log_info(
context, context,
0i32, 0,
b"INBOX-fetch started...\x00" as *const u8 as *const libc::c_char, b"INBOX-fetch started...\x00" as *const u8 as *const libc::c_char,
); );
inbox.fetch(context); inbox.fetch(context);
if inbox.should_reconnect() { if inbox.should_reconnect() {
dc_log_info( dc_log_info(
context, context,
0i32, 0,
b"INBOX-fetch aborted, starting over...\x00" as *const u8 as *const libc::c_char, b"INBOX-fetch aborted, starting over...\x00" as *const u8 as *const libc::c_char,
); );
inbox.fetch(context); inbox.fetch(context);
} }
dc_log_info( dc_log_info(
context, context,
0i32, 0,
b"INBOX-fetch done in %.0f ms.\x00" as *const u8 as *const libc::c_char, 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) { pub unsafe fn dc_perform_mvbox_fetch(context: &Context) {
let use_network: libc::c_int = dc_sqlite3_get_config_int( let use_network = dc_sqlite3_get_config_int(context, &context.sql, "mvbox_watch", 1);
context,
&context.sql,
b"mvbox_watch\x00" as *const u8 as *const libc::c_char,
1i32,
);
dc_jobthread_fetch( dc_jobthread_fetch(
context, context,
&mut context.mvbox_thread.clone().write().unwrap(), &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) { pub unsafe fn dc_perform_mvbox_idle(context: &Context) {
let use_network: libc::c_int = dc_sqlite3_get_config_int( let use_network = dc_sqlite3_get_config_int(context, &context.sql, "mvbox_watch", 1);
context,
&context.sql,
b"mvbox_watch\x00" as *const u8 as *const libc::c_char,
1i32,
);
dc_jobthread_idle( dc_jobthread_idle(
context, context,
&context.mvbox_thread.clone().read().unwrap(), &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) { pub unsafe fn dc_perform_sentbox_fetch(context: &Context) {
let use_network: libc::c_int = dc_sqlite3_get_config_int( let use_network = dc_sqlite3_get_config_int(context, &context.sql, "sentbox_watch", 1);
context,
&context.sql,
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
1i32,
);
dc_jobthread_fetch( dc_jobthread_fetch(
context, context,
&mut context.sentbox_thread.clone().write().unwrap(), &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) { pub unsafe fn dc_perform_sentbox_idle(context: &Context) {
let use_network: libc::c_int = dc_sqlite3_get_config_int( let use_network = dc_sqlite3_get_config_int(context, &context.sql, "sentbox_watch", 1);
context,
&context.sql,
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
1i32,
);
dc_jobthread_idle( dc_jobthread_idle(
context, context,
&context.sentbox_thread.clone().read().unwrap(), &context.sentbox_thread.clone().read().unwrap(),
@@ -1138,7 +1058,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) {
if 0 != state.suspended { if 0 != state.suspended {
dc_log_info( dc_log_info(
context, context,
0i32, 0,
b"SMTP-jobs suspended.\x00" as *const u8 as *const libc::c_char, b"SMTP-jobs suspended.\x00" as *const u8 as *const libc::c_char,
); );
return; return;
@@ -1155,7 +1075,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) {
dc_job_perform(context, 5000, probe_smtp_network); dc_job_perform(context, 5000, probe_smtp_network);
dc_log_info( dc_log_info(
context, context,
0i32, 0,
b"SMTP-jobs ended.\x00" as *const u8 as *const libc::c_char, 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) { pub unsafe fn dc_perform_smtp_idle(context: &Context) {
dc_log_info( dc_log_info(
context, context,
0i32, 0,
b"SMTP-idle started...\x00" as *const u8 as *const libc::c_char, 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( dc_log_info(
context, context,
0i32, 0,
b"SMTP-idle ended.\x00" as *const u8 as *const libc::c_char, 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 { 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,
&context.sql, &context.sql,
b"SELECT MIN(desired_timestamp) FROM jobs WHERE thread=?;\x00" as *const u8 "SELECT MIN(desired_timestamp) FROM jobs WHERE thread=?;",
as *const libc::c_char, params![thread],
); 0,
sqlite3_bind_int(stmt, 1, thread); )
.unwrap_or_default();
let mut wakeup_time = Duration::new(10 * 60, 0); let mut wakeup_time = Duration::new(10 * 60, 0);
let now = time();
if sqlite3_step(stmt) == 100 { if t > 0 {
let t = sqlite3_column_int(stmt, 0) as i64; if t > now {
let now = time(); wakeup_time = Duration::new((t - now) as u64, 0);
if t > 0 { } else {
if t > now { wakeup_time = Duration::new(0, 0);
wakeup_time = Duration::new((t - now) as u64, 0);
} else {
wakeup_time = Duration::new(0, 0);
}
} }
} }
sqlite3_finalize(stmt);
wakeup_time wakeup_time
} }
@@ -1249,19 +1165,12 @@ pub unsafe fn dc_maybe_network(context: &Context) {
dc_interrupt_sentbox_idle(context); dc_interrupt_sentbox_idle(context);
} }
pub unsafe fn dc_job_action_exists(context: &Context, action: libc::c_int) -> libc::c_int { pub fn dc_job_action_exists(context: &Context, action: libc::c_int) -> bool {
let job_exists: libc::c_int; dc_sqlite3_prepare(context, &context.sql, "SELECT id FROM jobs WHERE action=?;")
let stmt; .and_then(|mut stmt| stmt.exists(params![action]).ok())
stmt = dc_sqlite3_prepare( .unwrap_or_default()
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;
} }
/* special case for DC_JOB_SEND_MSG_TO_SMTP */ /* 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 { pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
let mut success: libc::c_int = 0i32; let mut success: libc::c_int = 0i32;

View File

@@ -133,39 +133,29 @@ pub unsafe fn dc_jobthread_fetch(
unsafe fn connect_to_imap(context: &Context, jobthread: &dc_jobthread_t) -> libc::c_int { unsafe fn connect_to_imap(context: &Context, jobthread: &dc_jobthread_t) -> libc::c_int {
let mut ret_connected: 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() { if jobthread.imap.is_connected() {
ret_connected = 1; ret_connected = 1;
} else { } else {
ret_connected = dc_connect_to_configured_imap(context, &jobthread.imap); ret_connected = dc_connect_to_configured_imap(context, &jobthread.imap);
if !(0 == ret_connected) { if !(0 == ret_connected) {
if dc_sqlite3_get_config_int( if dc_sqlite3_get_config_int(context, &context.sql, "folders_configured", 0) < 3 {
context,
&context.sql,
b"folders_configured\x00" as *const u8 as *const libc::c_char,
0,
) < 3
{
jobthread.imap.configure_folders(context, 0x1); jobthread.imap.configure_folders(context, 0x1);
} }
mvbox_name = dc_sqlite3_get_config( let mvbox_name = dc_sqlite3_get_config(
context, context,
&context.sql, &context.sql,
CString::new(&jobthread.folder_config_name[..]) as_str(&jobthread.folder_config_name[..]),
.unwrap() None,
.as_ptr(),
0 as *const libc::c_char,
); );
if mvbox_name.is_null() { if let Some(name) = mvbox_name {
jobthread.imap.set_watch_folder(name);
} else {
jobthread.imap.disconnect(context); jobthread.imap.disconnect(context);
ret_connected = 0; ret_connected = 0;
} else {
jobthread.imap.set_watch_folder(mvbox_name);
} }
} }
} }
free(mvbox_name as *mut libc::c_void);
ret_connected ret_connected
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,283 +1,167 @@
use std::borrow::Cow;
use crate::context::Context; use crate::context::Context;
use crate::dc_sqlite3::*; use crate::dc_sqlite3::*;
use crate::dc_tools::*;
use crate::types::*;
use crate::x::*;
#[derive(Copy, Clone)] #[derive(Default, Debug)]
#[repr(C)]
pub struct dc_loginparam_t { pub struct dc_loginparam_t {
pub addr: *mut libc::c_char, pub addr: String,
pub mail_server: *mut libc::c_char, pub mail_server: String,
pub mail_user: *mut libc::c_char, pub mail_user: String,
pub mail_pw: *mut libc::c_char, pub mail_pw: String,
pub mail_port: i32, pub mail_port: i32,
pub send_server: *mut libc::c_char, pub send_server: String,
pub send_user: *mut libc::c_char, pub send_user: String,
pub send_pw: *mut libc::c_char, pub send_pw: String,
pub send_port: i32, pub send_port: i32,
pub server_flags: i32, pub server_flags: i32,
} }
pub unsafe fn dc_loginparam_new() -> *mut dc_loginparam_t { impl dc_loginparam_t {
let loginparam: *mut dc_loginparam_t; pub fn addr_str(&self) -> &str {
loginparam = calloc(1, ::std::mem::size_of::<dc_loginparam_t>()) as *mut dc_loginparam_t; self.addr.as_str()
assert!(!loginparam.is_null());
loginparam
}
pub unsafe fn dc_loginparam_unref(loginparam: *mut dc_loginparam_t) {
if loginparam.is_null() {
return;
} }
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 fn dc_loginparam_new() -> dc_loginparam_t {
pub unsafe fn dc_loginparam_empty(mut loginparam: *mut dc_loginparam_t) { Default::default()
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 unsafe fn dc_loginparam_read( pub fn dc_loginparam_read(
context: &Context, context: &Context,
loginparam: *mut dc_loginparam_t,
sql: &SQLite, sql: &SQLite,
prefix: *const libc::c_char, prefix: impl AsRef<str>,
) { ) -> dc_loginparam_t {
let mut key: *mut libc::c_char = 0 as *mut libc::c_char; let prefix = prefix.as_ref();
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);
}
pub unsafe fn dc_loginparam_write( let key = format!("{}addr", prefix);
context: &Context, let addr = dc_sqlite3_get_config(context, sql, key, None)
loginparam: *const dc_loginparam_t, .unwrap_or_default()
sql: &SQLite, .trim()
prefix: *const libc::c_char, .to_string();
) {
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);
}
pub unsafe fn dc_loginparam_get_readable(loginparam: *const dc_loginparam_t) -> *mut libc::c_char { let key = format!("{}mail_server", prefix);
let unset: *const libc::c_char = b"0\x00" as *const u8 as *const libc::c_char; let mail_server = dc_sqlite3_get_config(context, sql, key, None).unwrap_or_default();
let pw: *const libc::c_char = b"***\x00" as *const u8 as *const libc::c_char;
if loginparam.is_null() { let key = format!("{}mail_port", prefix);
return dc_strdup(0 as *const libc::c_char); 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, pub fn dc_loginparam_write(
if !(*loginparam).addr.is_null() { context: &Context,
(*loginparam).addr loginparam: &dc_loginparam_t,
} else { sql: &SQLite,
unset prefix: impl AsRef<str>,
}, ) {
if !(*loginparam).mail_user.is_null() { let prefix = prefix.as_ref();
(*loginparam).mail_user
} else { let key = format!("{}addr", prefix);
unset dc_sqlite3_set_config(context, sql, key, Some(&loginparam.addr));
},
if !(*loginparam).mail_pw.is_null() { 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 pw
} else { } else {
unset unset
}, },
if !(*loginparam).mail_server.is_null() { unset_empty(&loginparam.mail_server),
(*loginparam).mail_server loginparam.mail_port,
} else { unset_empty(&loginparam.send_user),
unset if !loginparam.send_pw.is_empty() {
},
(*loginparam).mail_port,
if !(*loginparam).send_user.is_null() {
(*loginparam).send_user
} else {
unset
},
if !(*loginparam).send_pw.is_null() {
pw pw
} else { } else {
unset unset
}, },
if !(*loginparam).send_server.is_null() { unset_empty(&loginparam.send_server),
(*loginparam).send_server loginparam.send_port,
} else {
unset
},
(*loginparam).send_port,
flags_readable, 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(); let mut res = String::new();
for bit in 0..31 { for bit in 0..31 {
if 0 != flags & 1 << bit { if 0 != flags & 1 << bit {
let mut flag_added: libc::c_int = 0; let mut flag_added = 0;
if 1 << bit == 0x2 { if 1 << bit == 0x2 {
res += "OAUTH2 "; res += "OAUTH2 ";
flag_added = 1; flag_added = 1;
@@ -319,5 +203,5 @@ fn get_readable_flags(flags: libc::c_int) -> *mut libc::c_char {
res += "0"; res += "0";
} }
unsafe { strdup(to_cstring(res).as_ptr()) } res
} }

View File

@@ -100,7 +100,7 @@ pub unsafe fn dc_mimefactory_empty(mut factory: *mut dc_mimefactory_t) {
mmap_string_free((*factory).out); mmap_string_free((*factory).out);
(*factory).out = 0 as *mut MMAPString (*factory).out = 0 as *mut MMAPString
} }
(*factory).out_encrypted = 0i32; (*factory).out_encrypted = 0;
(*factory).loaded = DC_MF_NOTHING_LOADED; (*factory).loaded = DC_MF_NOTHING_LOADED;
free((*factory).error as *mut libc::c_void); free((*factory).error as *mut libc::c_void);
(*factory).error = 0 as *mut libc::c_char; (*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, mut factory: *mut dc_mimefactory_t,
msg_id: uint32_t, msg_id: uint32_t,
) -> libc::c_int { ) -> libc::c_int {
let mut success: libc::c_int = 0i32; if factory.is_null() || msg_id <= 9 || !(*factory).msg.is_null() {
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; return 0;
if !(factory.is_null() || msg_id <= 9i32 as libc::c_uint || !(*factory).msg.is_null()) { }
/*call empty() before */
let context = (*factory).context; let mut success = 0;
(*factory).recipients_names = clist_new();
(*factory).recipients_addr = clist_new(); /*call empty() before */
(*factory).msg = dc_msg_new_untyped(context); let context = (*factory).context;
(*factory).chat = dc_chat_new(context); (*factory).recipients_names = clist_new();
if dc_msg_load_from_db((*factory).msg, context, msg_id) (*factory).recipients_addr = clist_new();
&& dc_chat_load_from_db((*factory).chat, (*(*factory).msg).chat_id) (*factory).msg = dc_msg_new_untyped(context);
{ (*factory).chat = dc_chat_new(context);
load_from(factory); if dc_msg_load_from_db((*factory).msg, context, msg_id)
(*factory).req_mdn = 0i32; && dc_chat_load_from_db((*factory).chat, (*(*factory).msg).chat_id)
if 0 != dc_chat_is_self_talk((*factory).chat) { {
clist_insert_after( load_from(factory);
(*factory).recipients_names, (*factory).req_mdn = 0;
(*(*factory).recipients_names).last, if 0 != dc_chat_is_self_talk((*factory).chat) {
dc_strdup_keep_null((*factory).from_displayname) as *mut libc::c_void, clist_insert_after(
); (*factory).recipients_names,
clist_insert_after( (*(*factory).recipients_names).last,
(*factory).recipients_addr, dc_strdup_keep_null((*factory).from_displayname) as *mut libc::c_void,
(*(*factory).recipients_addr).last, );
dc_strdup((*factory).from_addr) 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 { } else {
stmt = None
dc_sqlite3_prepare( };
context,
&context.sql, if let Some(rows) = rows {
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" for (authname, addr) in rows {
as *const u8 as let addr_c = to_cstring(addr);
*const libc::c_char); if clist_search_string_nocase((*factory).recipients_addr, addr_c.as_ptr()) == 0
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 {
clist_insert_after( clist_insert_after(
(*factory).recipients_names, (*factory).recipients_names,
(*(*factory).recipients_names).last, (*(*factory).recipients_names).last,
(if !authname.is_null() && 0 != *authname.offset(0isize) as libc::c_int if !authname.is_empty() {
{ dc_strdup(to_cstring(authname).as_ptr())
dc_strdup(authname)
} else { } else {
0 as *mut libc::c_char 0 as *mut libc::c_char
}) as *mut libc::c_void, } as *mut libc::c_void,
); );
clist_insert_after( clist_insert_after(
(*factory).recipients_addr, (*factory).recipients_addr,
(*(*factory).recipients_addr).last, (*(*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); let command = dc_param_get_int((*(*factory).msg).param, 'S' as i32, 0);
if command == 5i32 { if command == 5 {
let email_to_remove: *mut libc::c_char = dc_param_get( let email_to_remove_c = dc_param_get(
(*(*factory).msg).param, (*(*factory).msg).param,
'E' as i32, 'E' as i32,
0 as *const libc::c_char, 0 as *const libc::c_char,
); );
let self_addr: *mut libc::c_char = dc_sqlite3_get_config( let email_to_remove = to_string(email_to_remove_c);
context, let self_addr =
&context.sql, dc_sqlite3_get_config(context, &context.sql, "configured_addr", Some(""))
b"configured_addr\x00" as *const u8 as *const libc::c_char, .unwrap_or_default();
b"\x00" as *const u8 as *const libc::c_char,
); if !email_to_remove.is_empty() && email_to_remove != self_addr {
if !email_to_remove.is_null() && strcasecmp(email_to_remove, self_addr) != 0i32 if clist_search_string_nocase((*factory).recipients_addr, email_to_remove_c)
== 0
{ {
if clist_search_string_nocase((*factory).recipients_addr, email_to_remove) clist_insert_after(
== 0i32 (*factory).recipients_names,
{ (*(*factory).recipients_names).last,
clist_insert_after( 0 as *mut libc::c_void,
(*factory).recipients_names, );
(*(*factory).recipients_names).last, clist_insert_after(
0 as *mut libc::c_void, (*factory).recipients_addr,
); (*(*factory).recipients_addr).last,
clist_insert_after( email_to_remove_c as *mut libc::c_void,
(*factory).recipients_addr, );
(*(*factory).recipients_addr).last,
email_to_remove 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( if command != 6
context, && command != 7
&context.sql, && 0 != dc_sqlite3_get_config_int(context, &context.sql, "mdns_enabled", 1)
b"SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?\x00" as *const u8 {
as *const libc::c_char, (*factory).req_mdn = 1
);
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)
} }
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); if 0 != success {
return success; (*factory).increation = dc_msg_is_increation((*factory).msg)
}
success
} }
unsafe fn load_from(mut factory: *mut dc_mimefactory_t) { unsafe fn load_from(mut factory: *mut dc_mimefactory_t) {
(*factory).from_addr = dc_sqlite3_get_config( (*factory).from_addr = strdup(
(*factory).context, to_cstring(
&(*factory).context.sql, dc_sqlite3_get_config(
b"configured_addr\x00" as *const u8 as *const libc::c_char, (*factory).context,
0 as *const libc::c_char, &mut (*factory).context.sql,
"configured_addr",
None,
)
.unwrap_or_default(),
)
.as_ptr(),
); );
(*factory).from_displayname = dc_sqlite3_get_config( (*factory).from_displayname = strdup(
(*factory).context, to_cstring(
&(*factory).context.sql, dc_sqlite3_get_config(
b"displayname\x00" as *const u8 as *const libc::c_char, (*factory).context,
0 as *const libc::c_char, &mut (*factory).context.sql,
"displayname",
None,
)
.unwrap_or_default(),
)
.as_ptr(),
); );
(*factory).selfstatus = dc_sqlite3_get_config( (*factory).selfstatus = strdup(
(*factory).context, to_cstring(
&(*factory).context.sql, dc_sqlite3_get_config(
b"selfstatus\x00" as *const u8 as *const libc::c_char, (*factory).context,
0 as *const libc::c_char, &mut (*factory).context.sql,
"selfstatus",
None,
)
.unwrap_or_default(),
)
.as_ptr(),
); );
if (*factory).selfstatus.is_null() { 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, mut factory: *mut dc_mimefactory_t,
msg_id: uint32_t, msg_id: uint32_t,
) -> libc::c_int { ) -> libc::c_int {
let mut success: libc::c_int = 0i32; if factory.is_null() {
let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t; return 0;
if !factory.is_null() { }
(*factory).recipients_names = clist_new();
(*factory).recipients_addr = clist_new(); let mut success = 0;
(*factory).msg = dc_msg_new_untyped((*factory).context); let mut contact = 0 as *mut dc_contact_t;
if !(0
== dc_sqlite3_get_config_int( (*factory).recipients_names = clist_new();
(*factory).context, (*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, &(*factory).context.sql,
b"mdns_enabled\x00" as *const u8 as *const libc::c_char, (*(*factory).msg).from_id,
1i32,
)) ))
{ {
/* MDNs not enabled - check this is late, in the job. the use may have changed its choice while offline ... */ if !(0 != (*contact).blocked || (*(*factory).msg).chat_id <= 9 as libc::c_uint) {
contact = dc_contact_new((*factory).context); // Do not send MDNs trash etc.; chats.blocked is already checked by the caller in dc_markseen_msgs()
if !(!dc_msg_load_from_db((*factory).msg, (*factory).context, msg_id) if !((*(*factory).msg).from_id <= 9 as libc::c_uint) {
|| !dc_contact_load_from_db( clist_insert_after(
contact, (*factory).recipients_names,
&(*factory).context.sql, (*(*factory).recipients_names).last,
(*(*factory).msg).from_id, (if !(*contact).authname.is_null()
)) && 0 != *(*contact).authname.offset(0isize) as libc::c_int
{ {
if !(0 != (*contact).blocked || (*(*factory).msg).chat_id <= 9i32 as libc::c_uint) { dc_strdup((*contact).authname)
/* Do not send MDNs trash etc.; chats.blocked is already checked by the caller in dc_markseen_msgs() */ } else {
if !((*(*factory).msg).from_id <= 9i32 as libc::c_uint) { 0 as *mut libc::c_char
clist_insert_after( }) as *mut libc::c_void,
(*factory).recipients_names, );
(*(*factory).recipients_names).last, clist_insert_after(
(if !(*contact).authname.is_null() (*factory).recipients_addr,
&& 0 != *(*contact).authname.offset(0isize) as libc::c_int (*(*factory).recipients_addr).last,
{ dc_strdup((*contact).addr) as *mut libc::c_void,
dc_strdup((*contact).authname) );
} else { load_from(factory);
0 as *mut libc::c_char (*factory).timestamp = dc_create_smeared_timestamp((*factory).context);
}) as *mut libc::c_void, (*factory).rfc724_mid = dc_create_outgoing_rfc724_mid(
); 0 as *const libc::c_char,
clist_insert_after( (*factory).from_addr,
(*factory).recipients_addr, );
(*(*factory).recipients_addr).last, success = 1;
dc_strdup((*contact).addr) as *mut libc::c_void, (*factory).loaded = DC_MF_MDN_LOADED
);
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
}
} }
} }
} }
} }
dc_contact_unref(contact); dc_contact_unref(contact);
success 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_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 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 subject_str: *mut libc::c_char = 0 as *mut libc::c_char;
let mut afwd_email: libc::c_int = 0i32; let mut afwd_email: libc::c_int = 0;
let mut col: libc::c_int = 0i32; let mut col: libc::c_int = 0;
let mut success: libc::c_int = 0i32; let mut success: libc::c_int = 0;
let mut parts: libc::c_int = 0i32; let mut parts: libc::c_int = 0;
let mut e2ee_guaranteed: libc::c_int = 0i32; let mut e2ee_guaranteed: libc::c_int = 0;
let mut min_verified: libc::c_int = 0i32; let mut min_verified: libc::c_int = 0;
// 1=add Autocrypt-header (needed eg. for handshaking), 2=no Autocrypte-header (used for MDN) // 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 force_plaintext: libc::c_int = 0;
let mut do_gossip: libc::c_int = 0i32; let mut do_gossip: libc::c_int = 0;
let mut grpimage: *mut libc::c_char = 0 as *mut libc::c_char; let mut grpimage: *mut libc::c_char = 0 as *mut libc::c_char;
let mut e2ee_helper = dc_e2ee_helper_t { let mut e2ee_helper = dc_e2ee_helper_t {
encryption_successfull: 0, 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; let mut to: *mut mailimf_address_list = 0 as *mut mailimf_address_list;
if !(*factory).recipients_names.is_null() if !(*factory).recipients_names.is_null()
&& !(*factory).recipients_addr.is_null() && !(*factory).recipients_addr.is_null()
&& (*(*factory).recipients_addr).count > 0i32 && (*(*factory).recipients_addr).count > 0
{ {
let mut iter1: *mut clistiter; let mut iter1: *mut clistiter;
let mut iter2: *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 msg: *mut dc_msg_t = (*factory).msg;
let mut meta_part: *mut mailmime = 0 as *mut mailmime; let mut meta_part: *mut mailmime = 0 as *mut mailmime;
let mut placeholdertext: *mut libc::c_char = 0 as *mut libc::c_char; 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( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( 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), strdup(b"1\x00" as *const u8 as *const libc::c_char),
), ),
); );
force_plaintext = 0i32; force_plaintext = 0;
e2ee_guaranteed = 1i32; e2ee_guaranteed = 1;
min_verified = 2i32 min_verified = 2
} else { } else {
force_plaintext = dc_param_get_int((*(*factory).msg).param, 'u' as i32, 0i32); force_plaintext = dc_param_get_int((*(*factory).msg).param, 'u' as i32, 0);
if force_plaintext == 0i32 { if force_plaintext == 0 {
e2ee_guaranteed = dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0i32) e2ee_guaranteed = dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0)
} }
} }
if (*chat).gossiped_timestamp == 0 if (*chat).gossiped_timestamp == 0
|| ((*chat).gossiped_timestamp + (2 * 24 * 60 * 60)) < time() || ((*chat).gossiped_timestamp + (2 * 24 * 60 * 60)) < time()
{ {
do_gossip = 1i32 do_gossip = 1
} }
/* build header etc. */ /* build header etc. */
let command: libc::c_int = dc_param_get_int((*msg).param, 'S' as i32, 0i32); let command: libc::c_int = dc_param_get_int((*msg).param, 'S' as i32, 0);
if (*chat).type_0 == 120i32 || (*chat).type_0 == 130i32 { if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( 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), dc_encode_header_words((*chat).name),
), ),
); );
if command == 5i32 { if command == 5 {
let email_to_remove: *mut libc::c_char = let email_to_remove: *mut libc::c_char =
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char); dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
if !email_to_remove.is_null() { 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 { } else if command == 4 {
do_gossip = 1i32; do_gossip = 1;
let email_to_add: *mut libc::c_char = let email_to_add: *mut libc::c_char =
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char); dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
if !email_to_add.is_null() { 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) 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( dc_log_info(
(*msg).context, (*msg).context,
0i32, 0,
b"sending secure-join message \'%s\' >>>>>>>>>>>>>>>>>>>>>>>>>\x00" b"sending secure-join message \'%s\' >>>>>>>>>>>>>>>>>>>>>>>>>\x00"
as *const u8 as *const libc::c_char, as *const u8 as *const libc::c_char,
b"vg-member-added\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( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( 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); grpimage = dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
if grpimage.is_null() { if grpimage.is_null() {
mailimf_fields_add( 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( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( 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( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( 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), 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 = let step: *mut libc::c_char =
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char); dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
if !step.is_null() { if !step.is_null() {
dc_log_info( dc_log_info(
(*msg).context, (*msg).context,
0i32, 0,
b"sending secure-join message \'%s\' >>>>>>>>>>>>>>>>>>>>>>>>>\x00" b"sending secure-join message \'%s\' >>>>>>>>>>>>>>>>>>>>>>>>>\x00"
as *const u8 as *const libc::c_char, as *const u8 as *const libc::c_char,
step, step,
@@ -667,12 +695,12 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
if strcmp( if strcmp(
step, step,
b"vg-request-with-auth\x00" as *const u8 as *const libc::c_char, b"vg-request-with-auth\x00" as *const u8 as *const libc::c_char,
) == 0i32 ) == 0
|| strcmp( || strcmp(
step, step,
b"vc-request-with-auth\x00" as *const u8 b"vc-request-with-auth\x00" as *const u8
as *const libc::c_char, as *const libc::c_char,
) == 0i32 ) == 0
{ {
strdup( strdup(
b"Secure-Join-Auth\x00" as *const u8 as *const libc::c_char, 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() { if !grpimage.is_null() {
let mut meta: *mut dc_msg_t = dc_msg_new_untyped((*factory).context); 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); dc_param_set((*meta).param, 'f' as i32, grpimage);
let mut filename_as_sent: *mut libc::c_char = 0 as *mut libc::c_char; let mut filename_as_sent: *mut libc::c_char = 0 as *mut libc::c_char;
meta_part = build_body_file( 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); dc_msg_unref(meta);
} }
if (*msg).type_0 == 41i32 || (*msg).type_0 == 40i32 || (*msg).type_0 == 50i32 { if (*msg).type_0 == 41 || (*msg).type_0 == 40 || (*msg).type_0 == 50 {
if (*msg).type_0 == 41i32 { if (*msg).type_0 == 41 {
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( 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); let duration_ms: libc::c_int = dc_param_get_int((*msg).param, 'd' as i32, 0);
if duration_ms > 0i32 { if duration_ms > 0 {
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( 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(fwdhint as *mut libc::c_void);
free(placeholdertext as *mut libc::c_void); free(placeholdertext as *mut libc::c_void);
/* add attachment part */ /* add attachment part */
if (*msg).type_0 == 20i32 if (*msg).type_0 == 20
|| (*msg).type_0 == 21i32 || (*msg).type_0 == 21
|| (*msg).type_0 == 40i32 || (*msg).type_0 == 40
|| (*msg).type_0 == 41i32 || (*msg).type_0 == 41
|| (*msg).type_0 == 50i32 || (*msg).type_0 == 50
|| (*msg).type_0 == 60i32 || (*msg).type_0 == 60
{ {
if 0 == is_file_size_okay(msg) { if 0 == is_file_size_okay(msg) {
let error: *mut libc::c_char = dc_mprintf( let error: *mut libc::c_char = dc_mprintf(
b"Message exceeds the recommended %i MB.\x00" as *const u8 b"Message exceeds the recommended %i MB.\x00" as *const u8
as *const libc::c_char, as *const libc::c_char,
24i32 * 1024i32 * 1024i32 / 4i32 * 3i32 / 1000i32 / 1000i32, 24 * 1024 * 1024 / 4 * 3 / 1000 / 1000,
); );
set_error(factory, error); set_error(factory, error);
free(error as *mut libc::c_void); 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 { match current_block {
11328123142868406523 => {} 11328123142868406523 => {}
_ => { _ => {
if parts == 0i32 { if parts == 0 {
set_error( set_error(
factory, factory,
b"Empty message.\x00" as *const u8 as *const libc::c_char, 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) { if dc_is_sending_locations_to_chat((*msg).context, (*msg).chat_id) {
let mut last_added_location_id: uint32_t = 0i32 as uint32_t; let mut last_added_location_id: uint32_t = 0 as uint32_t;
let kml_file: *mut libc::c_char = dc_get_location_kml( let kml_file: *mut libc::c_char = dc_get_location_kml(
(*msg).context, (*msg).context,
(*msg).chat_id, (*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); mailmime_add_part(message, multipart);
let p1: *mut libc::c_char; let p1: *mut libc::c_char;
let p2: *mut libc::c_char; let p2: *mut libc::c_char;
if 0 != dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0i32) { if 0 != dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0) {
p1 = dc_stock_str((*factory).context, 24i32) p1 = dc_stock_str((*factory).context, 24)
} else { } 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); 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(p2 as *mut libc::c_void);
free(p1 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); 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_set_body_text(mach_mime_part, message_text2, strlen(message_text2));
mailmime_add_part(multipart, mach_mime_part); mailmime_add_part(multipart, mach_mime_part);
force_plaintext = 2i32; force_plaintext = 2;
current_block = 9952640327414195044; current_block = 9952640327414195044;
} else { } else {
set_error( 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 if (*factory).loaded as libc::c_uint
== DC_MF_MDN_LOADED as libc::c_int 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 = subject_str =
dc_mprintf(b"Chat: %s\x00" as *const u8 as *const libc::c_char, e); dc_mprintf(b"Chat: %s\x00" as *const u8 as *const libc::c_char, e);
free(e as *mut libc::c_void); 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, 0 as *mut mailimf_optional_field,
), ),
); );
if force_plaintext != 2i32 { if force_plaintext != 2 {
dc_e2ee_encrypt( dc_e2ee_encrypt(
(*factory).context, (*factory).context,
(*factory).recipients_addr, (*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 { if 0 != e2ee_helper.encryption_successfull {
(*factory).out_encrypted = 1i32; (*factory).out_encrypted = 1;
if 0 != do_gossip { 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); (*factory).out = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
mailmime_write_mem((*factory).out, &mut col, message); 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 context = (*chat).context;
let ret: *mut libc::c_char; let ret: *mut libc::c_char;
let raw_subject: *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 { let fwd: *const libc::c_char = if 0 != afwd_email {
b"Fwd: \x00" as *const u8 as *const libc::c_char b"Fwd: \x00" as *const u8 as *const libc::c_char
} else { } else {
b"\x00" as *const u8 as *const libc::c_char b"\x00" as *const u8 as *const libc::c_char
}; };
if dc_param_get_int((*msg).param, 'S' as i32, 0i32) == 6i32 { if dc_param_get_int((*msg).param, 'S' as i32, 0) == 6 {
ret = dc_stock_str(context, 42i32) ret = dc_stock_str(context, 42)
} else if (*chat).type_0 == 120i32 || (*chat).type_0 == 130i32 { } else if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
ret = dc_mprintf( ret = dc_mprintf(
b"Chat: %s: %s%s\x00" as *const u8 as *const libc::c_char, b"Chat: %s: %s%s\x00" as *const u8 as *const libc::c_char,
(*chat).name, (*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_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; let mut filename_encoded: *mut libc::c_char = 0 as *mut libc::c_char;
if !pathNfilename.is_null() { 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 ts = chrono::Utc.timestamp((*msg).timestamp_sort as i64, 0);
let suffix = if !suffix.is_null() { 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)) .format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
.to_string(); .to_string();
filename_to_send = strdup(to_cstring(res).as_ptr()); 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) 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() { if base_name.is_null() {
base_name = b"image\x00" as *const u8 as *const libc::c_char 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 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( filename_to_send = dc_mprintf(
b"video.%s\x00" as *const u8 as *const libc::c_char, b"video.%s\x00" as *const u8 as *const libc::c_char,
if !suffix.is_null() { if !suffix.is_null() {
@@ -1178,14 +1206,14 @@ unsafe fn build_body_file(
if suffix.is_null() { if suffix.is_null() {
mimetype = mimetype =
dc_strdup(b"application/octet-stream\x00" as *const u8 as *const libc::c_char) 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) 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 } 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) == 0i32 || 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) == 0i32 || 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) 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) mimetype = dc_strdup(b"image/gif\x00" as *const u8 as *const libc::c_char)
} else { } else {
mimetype = 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, 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( mailmime_parameter_new(
strdup( strdup(
b"filename*\x00" as *const u8 as *const libc::c_char, 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 { 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 = let pathNfilename: *mut libc::c_char =
dc_param_get((*msg).param, 'f' as i32, 0 as *const 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); let bytes: uint64_t = dc_get_filebytes((*msg).context, pathNfilename);
if bytes > (49i32 * 1024i32 * 1024i32 / 4i32 * 3i32) as libc::c_ulonglong { if bytes > (49 * 1024 * 1024 / 4 * 3) as libc::c_ulonglong {
file_size_okay = 0i32 file_size_okay = 0;
} }
free(pathNfilename as *mut libc::c_void); free(pathNfilename as *mut libc::c_void);

View File

@@ -3,43 +3,39 @@ use crate::context::*;
use crate::dc_job::*; use crate::dc_job::*;
use crate::dc_msg::*; use crate::dc_msg::*;
use crate::dc_sqlite3::*; use crate::dc_sqlite3::*;
use crate::types::*;
pub unsafe fn dc_do_heuristics_moves( pub unsafe fn dc_do_heuristics_moves(context: &Context, folder: &str, msg_id: u32) {
context: &Context, if dc_sqlite3_get_config_int(context, &context.sql, "mvbox_move", 1) == 0 {
folder: *const libc::c_char, return;
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);
}
}
}
} }
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); dc_msg_unref(msg);
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
use mmime::mailimf_types::*; use mmime::mailimf_types::*;
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use crate::aheader::EncryptPreference; use crate::aheader::EncryptPreference;
use crate::constants::Event; use crate::constants::Event;
@@ -28,22 +29,18 @@ pub unsafe fn dc_get_securejoin_qr(
context: &Context, context: &Context,
group_chat_id: uint32_t, group_chat_id: uint32_t,
) -> *mut libc::c_char { ) -> *mut libc::c_char {
let current_block: u64;
/* ========================================================= /* =========================================================
==== Alice - the inviter side ==== ==== Alice - the inviter side ====
==== Step 1 in "Setup verified contact" protocol ==== ==== 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 fingerprint = 0 as *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 invitenumber: *mut libc::c_char; let mut invitenumber: *mut libc::c_char;
let mut auth: *mut libc::c_char; let mut auth: *mut libc::c_char;
let mut chat: *mut Chat = 0 as *mut Chat; let mut chat = 0 as *mut Chat;
let mut group_name: *mut libc::c_char = 0 as *mut libc::c_char; let mut group_name = 0 as *mut libc::c_char;
let mut group_name_urlencoded: *mut libc::c_char = 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); dc_ensure_secret_key_exists(context);
invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id); 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(); auth = dc_create_id();
dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth); dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth);
} }
self_addr = dc_sqlite3_get_config( let self_addr = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None);
context,
&context.sql, let cleanup = |fingerprint, chat, group_name, group_name_urlencoded| {
b"configured_addr\x00" as *const u8 as *const libc::c_char, free(fingerprint as *mut libc::c_void);
0 as *const libc::c_char, free(invitenumber as *mut libc::c_void);
); free(auth as *mut libc::c_void);
if self_addr.is_null() { dc_chat_unref(chat);
dc_log_error( free(group_name as *mut libc::c_void);
context, free(group_name_urlencoded as *mut libc::c_void);
0i32,
b"Not configured, cannot generate QR code.\x00" as *const u8 as *const libc::c_char, if let Some(qr) = qr {
); strdup(to_cstring(qr).as_ptr())
} else { } else {
self_name = dc_sqlite3_get_config( std::ptr::null_mut()
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,
);
}
}
} }
};
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); let self_addr = self_addr.unwrap();
free(self_addr as *mut libc::c_void); let self_name = dc_sqlite3_get_config(
free(self_name as *mut libc::c_void); context,
free(self_name_urlencoded as *mut libc::c_void); &context.sql.clone().read().unwrap(),
free(fingerprint as *mut libc::c_void); "displayname",
free(invitenumber as *mut libc::c_void); Some(""),
free(auth as *mut libc::c_void); )
dc_chat_unref(chat); .unwrap();
free(group_name as *mut libc::c_void); fingerprint = get_self_fingerprint(context);
free(group_name_urlencoded as *mut libc::c_void);
return if !qr.is_null() { if fingerprint.is_null() {
qr 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 { } 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 { fn get_self_fingerprint(context: &Context) -> *mut libc::c_char {
let self_addr = dc_sqlite3_get_config( if let Some(self_addr) = dc_sqlite3_get_config(context, &context.sql, "configured_addr", None) {
context, if let Some(key) = Key::from_self_public(context, self_addr, &context.sql) {
&context.sql, return key.fingerprint_c();
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();
} }
std::ptr::null_mut() 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, b"Secure-Join-Invitenumber\x00" as *const u8 as *const libc::c_char,
); );
if invitenumber.is_null() { if invitenumber.is_null() {
dc_log_warning( warn!(context, 0, "Secure-join denied (invitenumber missing).",);
context,
0i32,
b"Secure-join denied (invitenumber missing).\x00" as *const u8
as *const libc::c_char,
);
current_block = 4378276786830486580; current_block = 4378276786830486580;
} else if dc_token_exists(context, DC_TOKEN_INVITENUMBER, invitenumber) == 0i32 { } else if !dc_token_exists(context, DC_TOKEN_INVITENUMBER, invitenumber) {
dc_log_warning( warn!(context, 0, "Secure-join denied (bad invitenumber).",);
context,
0i32,
b"Secure-join denied (bad invitenumber).\x00" as *const u8
as *const libc::c_char,
);
current_block = 4378276786830486580; current_block = 4378276786830486580;
} else { } else {
dc_log_info( info!(context, 0, "Secure-join requested.",);
context,
0i32,
b"Secure-join requested.\x00" as *const u8 as *const libc::c_char,
);
context.call_cb( context.call_cb(
Event::SECUREJOIN_INVITER_PROGRESS, Event::SECUREJOIN_INVITER_PROGRESS,
contact_id as uintptr_t, 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, b"Auth not provided.\x00" as *const u8 as *const libc::c_char,
); );
current_block = 4378276786830486580; 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( could_not_establish_secure_connection(
context, context,
contact_chat_id, contact_chat_id,
@@ -1047,9 +1009,7 @@ unsafe fn encrypted_and_signed(
} }
pub unsafe fn dc_handle_degrade_event(context: &Context, peerstate: &Peerstate) { pub unsafe fn dc_handle_degrade_event(context: &Context, peerstate: &Peerstate) {
let stmt; let mut contact_chat_id = 0;
let contact_id: uint32_t;
let mut contact_chat_id: uint32_t = 0i32 as uint32_t;
// - we do not issue an warning for DC_DE_ENCRYPTION_PAUSED as this is quite normal // - 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 // - 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 // with things they cannot fix, so the user is just kicked from the verified group
// (and he will know this and can fix this) // (and he will know this and can fix this)
if Some(DegradeEvent::FingerprintChanged) == peerstate.degrade_event { if Some(DegradeEvent::FingerprintChanged) == peerstate.degrade_event {
stmt = dc_sqlite3_prepare( let contact_id: i32 = dc_sqlite3_query_row(
context, context,
&context.sql, &context.sql,
b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char, "SELECT id FROM contacts WHERE addr=?;",
); params![&peerstate.addr],
let c_addr = peerstate.addr.as_ref().map(to_cstring).unwrap_or_default(); 0,
)
let c_addr_ptr = if peerstate.addr.is_some() { .unwrap_or_default();
c_addr.as_ptr() if contact_id > 0 {
} 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) {
dc_create_or_lookup_nchat_by_contact_id( dc_create_or_lookup_nchat_by_contact_id(
context, context,
contact_id, contact_id as u32,
2i32, 2,
&mut contact_chat_id, &mut contact_chat_id,
0 as *mut libc::c_int, 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); dc_add_device_msg(context, contact_chat_id, msg);
free(msg as *mut libc::c_void); free(msg as *mut libc::c_void);
context.call_cb( context.call_cb(
Event::CHAT_MODIFIED, Event::CHAT_MODIFIED,
contact_chat_id as uintptr_t, contact_chat_id as uintptr_t,
0i32 as uintptr_t, 0 as uintptr_t,
); );
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,76 +1,65 @@
use crate::context::Context; use crate::context::Context;
use crate::dc_sqlite3::*; use crate::dc_sqlite3::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::types::*; use crate::x::strdup;
// Token namespaces // 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_AUTH: dc_tokennamespc_t = 110;
pub const DC_TOKEN_INVITENUMBER: dc_tokennamespc_t = 100; 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. // 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, context: &Context,
namespc: dc_tokennamespc_t, namespc: dc_tokennamespc_t,
foreign_id: uint32_t, foreign_id: u32,
token: *const libc::c_char, token: *const libc::c_char,
) { ) -> bool {
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; if token.is_null() {
if !token.is_null() { return false;
// 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);
} }
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, context: &Context,
namespc: dc_tokennamespc_t, namespc: dc_tokennamespc_t,
foreign_id: uint32_t, foreign_id: u32,
) -> *mut libc::c_char { ) -> *mut libc::c_char {
let token: *mut libc::c_char; if let Some(token) = dc_sqlite3_query_row::<_, String>(
let stmt: *mut sqlite3_stmt;
stmt = dc_sqlite3_prepare(
context, context,
&context.sql, &context.sql,
b"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;\x00" as *const u8 "SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;",
as *const libc::c_char, params![namespc as i32, foreign_id as i32],
); 0,
sqlite3_bind_int(stmt, 1i32, namespc as libc::c_int); ) {
sqlite3_bind_int(stmt, 2i32, foreign_id as libc::c_int); unsafe { strdup(to_cstring(token).as_ptr()) }
sqlite3_step(stmt); } else {
token = dc_strdup_keep_null(sqlite3_column_text(stmt, 0i32) as *mut libc::c_char); std::ptr::null_mut()
}
sqlite3_finalize(stmt);
token
} }
pub unsafe fn dc_token_exists( pub fn dc_token_exists(
context: &Context, context: &Context,
namespc: dc_tokennamespc_t, namespc: dc_tokennamespc_t,
token: *const libc::c_char, token: *const libc::c_char,
) -> libc::c_int { ) -> bool {
let mut exists: libc::c_int = 0i32; if token.is_null() {
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; return false;
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
} }
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()
} }

View File

@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::fs; use std::fs;
use std::time::SystemTime; use std::time::SystemTime;
@@ -343,25 +344,13 @@ pub unsafe fn dc_utf8_strlen(s: *const libc::c_char) -> size_t {
j j
} }
pub unsafe fn dc_truncate_str(buf: *mut libc::c_char, approx_chars: libc::c_int) { pub fn dc_truncate_str(buf: &str, approx_chars: usize) -> Cow<str> {
if approx_chars > 0 let appendix = "[...]";
&& strlen(buf) if approx_chars > 0 && buf.len() > approx_chars + appendix.len() {
> approx_chars.wrapping_add( Cow::Owned(format!("{}{}", &buf[..approx_chars], appendix))
strlen(b"[...]\x00" as *const u8 as *const libc::c_char) as libc::c_int } else {
) as usize Cow::Borrowed(buf)
{ }
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 unsafe fn dc_truncate_n_unwrap_str( 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 */ /* the return value must be free()'d */
pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char { pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char {
let ts = chrono::Utc.timestamp(wanted, 0); let res = dc_timestamp_to_str_safe(wanted);
let res = ts.format("%Y.%m.%d %H:%M:%S").to_string();
strdup(to_cstring(res).as_ptr()) 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 { pub fn dc_gm2local_offset() -> i64 {
let lt = Local::now(); let lt = Local::now();
((lt.offset().local_minus_utc() / (60 * 60)) * 100) as i64 ((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 */ /* file tools */
pub unsafe fn dc_ensure_no_slash(pathNfilename: *mut libc::c_char) { pub unsafe fn dc_ensure_no_slash(pathNfilename: *mut libc::c_char) {
let path_len: libc::c_int = strlen(pathNfilename) as libc::c_int; let path_len = strlen(pathNfilename);
if path_len > 0i32 { if path_len > 0 {
if *pathNfilename.offset((path_len - 1i32) as isize) as libc::c_int == '/' as i32 if *pathNfilename.offset((path_len - 1) as isize) as libc::c_int == '/' as i32
|| *pathNfilename.offset((path_len - 1i32) 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) { 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 "-" */ /* function modifies the given buffer and replaces all characters not valid in filenames by a "-" */
let mut p1: *mut libc::c_char = filename; let mut p1: *mut libc::c_char = filename;
@@ -1256,37 +1255,34 @@ pub unsafe fn dc_write_file(
buf: *const libc::c_void, buf: *const libc::c_void,
buf_bytes: size_t, buf_bytes: size_t,
) -> libc::c_int { ) -> 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); let bytes = std::slice::from_raw_parts(buf as *const u8, buf_bytes);
match fs::write(p, bytes) { dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int
Ok(_) => { }
info!(context, 0, "wrote file {}", as_str(pathNfilename));
success = 1; pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef<str>, buf: &[u8]) -> bool {
} let pathNfilename_abs =
Err(_err) => { unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
warn!( if pathNfilename_abs.is_null() {
context, return false;
0,
"Cannot write {} bytes to \"{}\".",
buf_bytes,
as_str(pathNfilename),
);
}
} }
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 success
} }
@@ -1296,44 +1292,43 @@ pub unsafe fn dc_read_file(
buf: *mut *mut libc::c_void, buf: *mut *mut libc::c_void,
buf_bytes: *mut size_t, buf_bytes: *mut size_t,
) -> libc::c_int { ) -> libc::c_int {
let mut success = 0; if pathNfilename.is_null() {
if pathNfilename.is_null() || buf.is_null() || buf_bytes.is_null() {
return 0; 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; pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef<str>) -> Option<Vec<u8>> {
*buf_bytes = 0i32 as size_t; let pathNfilename_abs =
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
if pathNfilename_abs.is_null() { if pathNfilename_abs.is_null() {
return 0; return None;
} }
let p = std::ffi::CStr::from_ptr(pathNfilename_abs) let p = as_str(pathNfilename_abs);
.to_str() let res = match fs::read(p) {
.unwrap(); Ok(bytes) => Some(bytes),
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;
}
Err(_err) => { Err(_err) => {
dc_log_warning( warn!(
context, context,
0, 0,
b"Cannot read \"%s\" or file is empty.\x00" as *const u8 as *const libc::c_char, "Cannot read \"{}\" or file is empty.",
pathNfilename, pathNfilename.as_ref(),
); );
None
} }
} };
free(pathNfilename_abs as *mut libc::c_void); unsafe { free(pathNfilename_abs as *mut libc::c_void) };
success
res
} }
pub unsafe fn dc_get_fine_pathNfilename( pub unsafe fn dc_get_fine_pathNfilename(
@@ -1706,61 +1701,29 @@ mod tests {
#[test] #[test]
fn test_dc_str_truncate_1() { fn test_dc_str_truncate_1() {
unsafe { let s = "this is a little test string";
let str: *mut libc::c_char = assert_eq!(dc_truncate_str(s, 16), "this is a [...]");
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);
}
} }
#[test] #[test]
fn test_dc_str_truncate_2() { fn test_dc_str_truncate_2() {
unsafe { assert_eq!(dc_truncate_str("1234", 2), "1234");
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);
}
} }
#[test] #[test]
fn test_dc_str_truncate_3() { fn test_dc_str_truncate_3() {
unsafe { assert_eq!(dc_truncate_str("1234567", 3), "1[...]");
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);
}
} }
#[test] #[test]
fn test_dc_str_truncate_4() { fn test_dc_str_truncate_4() {
unsafe { assert_eq!(dc_truncate_str("123456", 4), "123456");
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);
}
} }
#[test] #[test]
fn test_dc_insert_breaks_1() { fn test_dc_insert_breaks_1() {
unsafe { 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, b"just1234test\x00" as *const u8 as *const libc::c_char,
4, 4,
b" \x00" as *const u8 as *const libc::c_char, b" \x00" as *const u8 as *const libc::c_char,

View File

@@ -7,7 +7,7 @@ use crate::constants::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_loginparam::*; use crate::dc_loginparam::*;
use crate::dc_sqlite3::*; 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::oauth2::dc_get_oauth2_access_token;
use crate::types::*; use crate::types::*;
@@ -507,12 +507,8 @@ impl Imap {
cfg.watch_folder = None; cfg.watch_folder = None;
} }
pub fn connect(&self, context: &Context, lp: *const dc_loginparam_t) -> libc::c_int { pub fn connect(&self, context: &Context, lp: &dc_loginparam_t) -> libc::c_int {
if lp.is_null() { if lp.mail_server.is_empty() || lp.mail_user.is_empty() || lp.mail_pw.is_empty() {
return 0;
}
let lp = unsafe { *lp };
if lp.mail_server.is_null() || lp.mail_user.is_null() || lp.mail_pw.is_null() {
return 0; return 0;
} }
@@ -521,19 +517,19 @@ impl Imap {
} }
{ {
let addr = as_str(lp.addr); let addr = &lp.addr;
let imap_server = as_str(lp.mail_server); let imap_server = &lp.mail_server;
let imap_port = lp.mail_port as u16; let imap_port = lp.mail_port as u16;
let imap_user = as_str(lp.mail_user); let imap_user = &lp.mail_user;
let imap_pw = as_str(lp.mail_pw); let imap_pw = &lp.mail_pw;
let server_flags = lp.server_flags as usize; let server_flags = lp.server_flags as usize;
let mut config = self.config.write().unwrap(); let mut config = self.config.write().unwrap();
config.addr = addr.into(); config.addr = addr.to_string();
config.imap_server = imap_server.into(); config.imap_server = imap_server.to_string();
config.imap_port = imap_port.into(); config.imap_port = imap_port.into();
config.imap_user = imap_user.into(); config.imap_user = imap_user.to_string();
config.imap_pw = imap_pw.into(); config.imap_pw = imap_pw.to_string();
config.server_flags = server_flags; config.server_flags = server_flags;
} }
@@ -591,8 +587,8 @@ impl Imap {
} }
} }
pub fn set_watch_folder(&self, watch_folder: *const libc::c_char) { pub fn set_watch_folder(&self, watch_folder: String) {
self.config.write().unwrap().watch_folder = Some(to_string(watch_folder)); self.config.write().unwrap().watch_folder = Some(watch_folder);
} }
pub fn fetch(&self, context: &Context) -> libc::c_int { pub fn fetch(&self, context: &Context) -> libc::c_int {
@@ -838,9 +834,8 @@ impl Imap {
.expect("missing message id"); .expect("missing message id");
let message_id_c = CString::new(message_id).unwrap(); let message_id_c = CString::new(message_id).unwrap();
let folder_c = CString::new(folder.as_ref().to_owned()).unwrap();
if 0 == unsafe { 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 // check passed, go fetch the rest
if self.fetch_single_msg(context, &folder, cur_uid) == 0 { if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
@@ -993,12 +988,11 @@ impl Imap {
if !is_deleted && msg.body().is_some() { if !is_deleted && msg.body().is_some() {
unsafe { unsafe {
let folder_c = CString::new(folder.as_ref().to_owned()).unwrap();
(self.receive_imf)( (self.receive_imf)(
context, context,
msg.body().unwrap().as_ptr() as *const libc::c_char, msg.body().unwrap().as_ptr() as *const libc::c_char,
msg.body().unwrap().len(), msg.body().unwrap().len(),
folder_c.as_ptr(), folder.as_ref(),
server_uid, server_uid,
flags as u32, 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,
&context.sql, &context.sql,
b"folders_configured\x00" as *const u8 as *const libc::c_char, "configured_mvbox_folder",
3, 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(),
);
}
} }
} }

View File

@@ -113,19 +113,6 @@ impl Key {
Self::from_slice(bytes, key_type) 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( pub fn from_armored_string(
data: &str, data: &str,
key_type: KeyType, key_type: KeyType,
@@ -158,61 +145,34 @@ impl Key {
pub fn from_self_public( pub fn from_self_public(
context: &Context, context: &Context,
self_addr: *const libc::c_char, self_addr: impl AsRef<str>,
sql: &SQLite, sql: &SQLite,
) -> Option<Self> { ) -> Option<Self> {
if self_addr.is_null() { let addr = self_addr.as_ref();
return None;
}
let stmt = unsafe { dc_sqlite3_query_row(
dc_sqlite3_prepare( context,
context, sql,
sql, "SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;",
b"SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8 &[addr],
as *const libc::c_char, 0,
) )
}; .and_then(|blob: Vec<u8>| Self::from_slice(&blob, KeyType::Public))
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
} }
pub fn from_self_private( pub fn from_self_private(
context: &Context, context: &Context,
self_addr: *const libc::c_char, self_addr: impl AsRef<str>,
sql: &SQLite, sql: &SQLite,
) -> Option<Self> { ) -> Option<Self> {
if self_addr.is_null() { dc_sqlite3_query_row(
return None; context,
} sql,
"SELECT private_key FROM keypairs WHERE addr=? AND is_default=1;",
let stmt = unsafe { &[self_addr.as_ref()],
dc_sqlite3_prepare( 0,
context, )
sql, .and_then(|blob: Vec<u8>| Self::from_slice(&blob, KeyType::Private))
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
} }
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
@@ -340,57 +300,16 @@ pub fn dc_key_save_self_keypair(
context: &Context, context: &Context,
public_key: &Key, public_key: &Key,
private_key: &Key, private_key: &Key,
addr: *const libc::c_char, addr: impl AsRef<str>,
is_default: libc::c_int, is_default: libc::c_int,
sql: &SQLite, sql: &SQLite,
) -> bool { ) -> bool {
if addr.is_null() { dc_sqlite3_execute(
return false;
}
let stmt = unsafe {
dc_sqlite3_prepare(
context, context,
sql, sql,
b"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);\x00" "INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);",
as *const u8 as *const libc::c_char 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. /// Make a fingerprint human-readable, in hex format.
@@ -526,8 +445,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
#[test] #[test]
#[ignore] // is too expensive #[ignore] // is too expensive
fn test_from_slice_roundtrip() { fn test_from_slice_roundtrip() {
let (public_key, private_key) = let (public_key, private_key) = crate::pgp::dc_pgp_create_keypair("hello").unwrap();
crate::pgp::dc_pgp_create_keypair(CString::new("hello").unwrap().as_ptr()).unwrap();
let binary = public_key.to_bytes(); let binary = public_key.to_bytes();
let public_key2 = Key::from_slice(&binary, KeyType::Public).expect("invalid public key"); let public_key2 = Key::from_slice(&binary, KeyType::Public).expect("invalid public key");

View File

@@ -4,7 +4,6 @@ use crate::constants::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_sqlite3::*; use crate::dc_sqlite3::*;
use crate::key::*; use crate::key::*;
use crate::types::*;
#[derive(Default, Clone, Debug)] #[derive(Default, Clone, Debug)]
pub struct Keyring<'a> { pub struct Keyring<'a> {
@@ -31,29 +30,18 @@ impl<'a> Keyring<'a> {
pub fn load_self_private_for_decrypting( pub fn load_self_private_for_decrypting(
&mut self, &mut self,
context: &Context, context: &Context,
self_addr: *const libc::c_char, self_addr: impl AsRef<str>,
sql: &SQLite, sql: &SQLite,
) -> bool { ) -> bool {
// Can we prevent keyring and self_addr to be null? dc_sqlite3_query_row(
if self_addr.is_null() { context,
return false; sql,
} "SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;",
let stmt = unsafe { &[self_addr.as_ref()],
dc_sqlite3_prepare( 0,
context, )
sql, .and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Private))
b"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;\x00" .map(|key| self.add_owned(key))
as *const u8 as *const libc::c_char, .is_some()
)
};
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
} }
} }

View File

@@ -14,6 +14,8 @@ extern crate failure_derive;
extern crate num_derive; extern crate num_derive;
#[macro_use] #[macro_use]
extern crate smallvec; extern crate smallvec;
#[macro_use]
extern crate rusqlite;
#[macro_use] #[macro_use]
pub mod dc_log; pub mod dc_log;

View File

@@ -1,5 +1,4 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::CString;
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use serde::Deserialize; use serde::Deserialize;
@@ -51,10 +50,11 @@ pub fn dc_get_oauth2_url(
redirect_uri: impl AsRef<str>, redirect_uri: impl AsRef<str>,
) -> Option<String> { ) -> Option<String> {
if let Some(oauth2) = Oauth2::from_address(addr) { if let Some(oauth2) = Oauth2::from_address(addr) {
set_config( dc_sqlite3_set_config(
context, context,
&context.sql.clone().read().unwrap(),
"oauth2_pending_redirect_uri", "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.get_code, "$CLIENT_ID", &oauth2.client_id);
let oauth2_url = replace_in_uri(&oauth2_url, "$REDIRECT_URI", redirect_uri.as_ref()); 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 // read generated token
if 0 == flags & 0x1 && !is_expired(context) { 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() { if access_token.is_some() {
// success // success
return access_token; return access_token;
} }
} }
let refresh_token = get_config(context, "oauth2_refresh_token"); let refresh_token = dc_sqlite3_get_config(
let refresh_token_for = context,
get_config(context, "oauth2_refresh_token_for").unwrap_or_else(|| "unset".into()); &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) = let (redirect_uri, token_url, update_redirect_uri_on_success) =
if refresh_token.is_none() || refresh_token_for != code.as_ref() { 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...", 0, "Generate OAuth2 refresh_token and access_token...",
); );
( (
get_config(context, "oauth2_pending_redirect_uri") dc_sqlite3_get_config(
.unwrap_or_else(|| "unset".into()), context,
&context.sql.clone().read().unwrap(),
"oauth2_pending_redirect_uri",
None,
)
.unwrap_or_else(|| "unset".into()),
oauth2.init_token, oauth2.init_token,
true, true,
) )
@@ -108,7 +128,13 @@ pub fn dc_get_oauth2_access_token(
0, "Regenerate OAuth2 access_token by refresh_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, oauth2.refresh_token,
false, false,
) )
@@ -151,23 +177,48 @@ pub fn dc_get_oauth2_access_token(
println!("response: {:?}", &parsed); println!("response: {:?}", &parsed);
let response = parsed.unwrap(); let response = parsed.unwrap();
if let Some(ref token) = response.refresh_token { if let Some(ref token) = response.refresh_token {
set_config(context, "oauth2_refresh_token", token); dc_sqlite3_set_config(
set_config(context, "oauth2_refresh_token_for", code.as_ref()); 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. // 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 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 { 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 let expires_in = response
.expires_in .expires_in
// refresh a bet before // refresh a bet before
.map(|t| time() + t as i64 - 5) .map(|t| time() + t as i64 - 5)
.unwrap_or_else(|| 0); .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 { 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 { } else {
warn!(context, 0, "Failed to find OAuth2 access token"); 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 { fn is_expired(context: &Context) -> bool {
let expire_timestamp = dc_sqlite3_get_config_int64( let expire_timestamp =
context, dc_sqlite3_get_config_int64(context, &context.sql, "oauth2_timestamp_expires", Some(0));
&context.sql,
b"oauth2_timestamp_expires\x00" as *const u8 as *const libc::c_char,
0i32 as int64_t,
);
if expire_timestamp <= 0 { if expire_timestamp <= 0 {
return false; return false;

View File

@@ -1,5 +1,4 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::ffi::CString;
use std::fmt; use std::fmt;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
@@ -9,7 +8,6 @@ use crate::constants::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_sqlite3::*; use crate::dc_sqlite3::*;
use crate::dc_tools::{to_cstring, to_string};
use crate::key::*; use crate::key::*;
use crate::types::*; use crate::types::*;
@@ -17,13 +15,13 @@ use crate::types::*;
pub struct Peerstate<'a> { pub struct Peerstate<'a> {
pub context: &'a Context, pub context: &'a Context,
pub addr: Option<String>, pub addr: Option<String>,
pub last_seen: u64, pub last_seen: i64,
pub last_seen_autocrypt: u64, pub last_seen_autocrypt: i64,
pub prefer_encrypt: EncryptPreference, pub prefer_encrypt: EncryptPreference,
pub public_key: Option<Key>, pub public_key: Option<Key>,
pub public_key_fingerprint: Option<String>, pub public_key_fingerprint: Option<String>,
pub gossip_key: Option<Key>, pub gossip_key: Option<Key>,
pub gossip_timestamp: u64, pub gossip_timestamp: i64,
pub gossip_key_fingerprint: Option<String>, pub gossip_key_fingerprint: Option<String>,
verified_key: VerifiedKey, verified_key: VerifiedKey,
pub verified_key_fingerprint: Option<String>, 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); let mut res = Self::new(context);
res.addr = Some(header.addr.clone()); res.addr = Some(header.addr.clone());
@@ -155,7 +153,7 @@ impl<'a> Peerstate<'a> {
res 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); let mut res = Self::new(context);
res.addr = Some(gossip_header.addr.clone()); res.addr = Some(gossip_header.addr.clone());
@@ -167,88 +165,78 @@ impl<'a> Peerstate<'a> {
res res
} }
pub fn from_addr(context: &'a Context, sql: &SQLite, addr: &str) -> Option<Self> { pub fn from_addr(context: &'a Context, _sql: &SQLite, addr: &str) -> Option<Self> {
let mut res = None; 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 { Self::from_stmt(context, query, &[addr])
dc_sqlite3_prepare(
context,
sql,
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;\x00"
as *const u8 as *const libc::c_char)
};
let addr_c = CString::new(addr.as_bytes()).unwrap();
unsafe { sqlite3_bind_text(stmt, 1, addr_c.as_ptr(), -1, None) };
if unsafe { sqlite3_step(stmt) } == 100 {
res = Some(Self::from_stmt(context, stmt));
}
unsafe { sqlite3_finalize(stmt) };
res
} }
pub fn from_fingerprint(context: &'a Context, sql: &SQLite, fingerprint: &str) -> Option<Self> { pub fn from_fingerprint(
let mut res = None; 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 { let fp = fingerprint.as_bytes();
dc_sqlite3_prepare( Self::from_stmt(context, query, params![fp, fp, fp])
context,
sql,
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE public_key_fingerprint=? COLLATE NOCASE OR gossip_key_fingerprint=? COLLATE NOCASE ORDER BY public_key_fingerprint=? DESC;\x00"
as *const u8 as *const libc::c_char)
};
let fp_c = CString::new(fingerprint.as_bytes()).unwrap();
unsafe {
sqlite3_bind_text(stmt, 1, fp_c.as_ptr(), -1, None);
sqlite3_bind_text(stmt, 2, fp_c.as_ptr(), -1, None);
sqlite3_bind_text(stmt, 3, fp_c.as_ptr(), -1, None);
}
if unsafe { sqlite3_step(stmt) == 100 } {
res = Some(Self::from_stmt(context, stmt));
}
unsafe { sqlite3_finalize(stmt) };
res
} }
fn from_stmt(context: &'a 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); let mut res = Self::new(context);
res.addr = Some(to_string(unsafe { if let Some(mut stmt) =
sqlite3_column_text(stmt, 0) as *const _ dc_sqlite3_prepare(context, &context.sql.clone().read().unwrap(), query)
})); {
res.last_seen = unsafe { sqlite3_column_int64(stmt, 1) } as u64; stmt.query_row(params, |row| {
res.last_seen_autocrypt = unsafe { sqlite3_column_int64(stmt, 2) } as u64; res.addr = Some(row.get(0)?);
res.prefer_encrypt = res.last_seen = row.get(1)?;
EncryptPreference::from_i32(unsafe { sqlite3_column_int(stmt, 3) }).unwrap_or_default(); res.last_seen_autocrypt = row.get(2)?;
res.gossip_timestamp = unsafe { sqlite3_column_int(stmt, 5) } as u64; res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
let pkf = to_string(unsafe { sqlite3_column_text(stmt, 7) as *const _ }); res.gossip_timestamp = row.get(5)?;
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) }; let pkf: String = row.get(7)?;
let gkf = to_string(unsafe { sqlite3_column_text(stmt, 8) as *const _ }); res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) }; let gkf: String = row.get(8)?;
let vkf = to_string(unsafe { sqlite3_column_text(stmt, 10) as *const _ }); res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) }; 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 = row
res.public_key = Key::from_stmt(stmt, 4, KeyType::Public); .get(4)
} .ok()
if unsafe { sqlite3_column_type(stmt, 6) } != 5 { .and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
res.gossip_key = Key::from_stmt(stmt, 6, KeyType::Public); res.gossip_key = row
} .get(6)
if unsafe { sqlite3_column_type(stmt, 9) } != 5 { .ok()
let vk = Key::from_stmt(stmt, 9, KeyType::Public); .and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
res.verified_key = if vk == res.gossip_key { let vk = row
VerifiedKey::Gossip .get(9)
} else if vk == res.public_key { .ok()
VerifiedKey::Public .and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
} else { res.verified_key = if vk == res.gossip_key {
VerifiedKey::None 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) { 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 { if self.prefer_encrypt == EncryptPreference::Mutual {
self.degrade_event = Some(DegradeEvent::EncryptionPaused); self.degrade_event = Some(DegradeEvent::EncryptionPaused);
} }
@@ -293,7 +281,7 @@ impl<'a> Peerstate<'a> {
self.to_save = Some(ToSave::All); 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() if self.addr.is_none()
|| self.addr.as_ref().unwrap().to_lowercase() != header.addr.to_lowercase() || 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() if self.addr.is_none()
|| self.addr.as_ref().unwrap().to_lowercase() != gossip_header.addr.to_lowercase() || self.addr.as_ref().unwrap().to_lowercase() != gossip_header.addr.to_lowercase()
{ {
@@ -408,158 +396,56 @@ impl<'a> Peerstate<'a> {
} }
if create { if create {
let stmt = unsafe { if !dc_sqlite3_execute(
dc_sqlite3_prepare( self.context,
self.context, sql,
sql, "INSERT INTO acpeerstates (addr) VALUES(?);",
b"INSERT INTO acpeerstates (addr) VALUES(?);\x00" as *const u8 params![self.addr.as_ref().unwrap()],
as *const libc::c_char, ) {
) return false;
};
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 self.to_save == Some(ToSave::All) || create { if self.to_save == Some(ToSave::All) || create {
let stmt = unsafe { success = dc_sqlite3_execute(
dc_sqlite3_prepare( self.context,
self.context, sql, sql,
b"UPDATE acpeerstates \ "UPDATE acpeerstates \
SET last_seen=?, last_seen_autocrypt=?, prefer_encrypted=?, \ 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=? \ public_key=?, gossip_timestamp=?, gossip_key=?, public_key_fingerprint=?, gossip_key_fingerprint=?, \
WHERE addr=?;\x00" verified_key=?, verified_key_fingerprint=? \
as *const u8 as *const libc::c_char WHERE addr=?;",
) params![
}; self.last_seen,
self.last_seen_autocrypt,
unsafe { sqlite3_bind_int64(stmt, 1, self.last_seen as sqlite3_int64) }; self.prefer_encrypt as i64,
unsafe { sqlite3_bind_int64(stmt, 2, self.last_seen_autocrypt as sqlite3_int64) }; self.public_key.as_ref().map(|k| k.to_bytes()),
unsafe { sqlite3_bind_int64(stmt, 3, self.prefer_encrypt as sqlite3_int64) }; self.gossip_timestamp,
self.gossip_key.as_ref().map(|k| k.to_bytes()),
let pub_bytes = self &self.public_key_fingerprint,
.public_key &self.gossip_key_fingerprint,
.as_ref() self.verified_key().map(|k| k.to_bytes()),
.map(|k| k.to_bytes()) &self.verified_key_fingerprint,
.unwrap_or_default(); &self.addr,
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) };
} else if self.to_save == Some(ToSave::Timestamps) { } else if self.to_save == Some(ToSave::Timestamps) {
let stmt = unsafe { success = dc_sqlite3_execute(
dc_sqlite3_prepare( self.context,
&self.context,sql, sql,
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? WHERE addr=?;\x00" "UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? \
as *const u8 as *const libc::c_char) WHERE addr=?;",
}; params![
self.last_seen,
let c_addr = self.addr.as_ref().map(to_cstring).unwrap_or_default(); self.last_seen_autocrypt,
let addr_ptr = if self.addr.is_some() { self.gossip_timestamp,
c_addr.as_ptr() &self.addr
} 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) };
} }
if self.to_save == Some(ToSave::All) || create { 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 success
@@ -582,7 +468,7 @@ mod tests {
use super::*; use super::*;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use std::ffi::CStr; use std::ffi::{CStr, CString};
use tempfile::{tempdir, TempDir}; use tempfile::{tempdir, TempDir};
use crate::context::*; use crate::context::*;

View File

@@ -137,8 +137,8 @@ pub unsafe fn dc_split_armored_data(
} }
/// Create a new key pair. /// Create a new key pair.
pub fn dc_pgp_create_keypair(addr: *const libc::c_char) -> Option<(Key, Key)> { pub fn dc_pgp_create_keypair(addr: impl AsRef<str>) -> Option<(Key, Key)> {
let user_id = format!("<{}>", unsafe { CStr::from_ptr(addr).to_str().unwrap() }); let user_id = format!("<{}>", addr.as_ref());
let key_params = SecretKeyParamsBuilder::default() let key_params = SecretKeyParamsBuilder::default()
.key_type(PgpKeyType::Rsa(2048)) .key_type(PgpKeyType::Rsa(2048))

View File

@@ -1,5 +1,3 @@
use std::ffi::CStr;
use lettre::smtp::client::net::*; use lettre::smtp::client::net::*;
use lettre::*; use lettre::*;
@@ -7,7 +5,6 @@ use crate::constants::Event;
use crate::constants::*; use crate::constants::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_loginparam::*; use crate::dc_loginparam::*;
use crate::dc_tools::*;
use crate::oauth2::*; use crate::oauth2::*;
use crate::types::*; use crate::types::*;
@@ -47,30 +44,17 @@ impl Smtp {
} }
/// Connect using the provided login params /// Connect using the provided login params
pub fn connect(&mut self, context: &Context, lp: *const dc_loginparam_t) -> usize { pub fn connect(&mut self, context: &Context, lp: &dc_loginparam_t) -> usize {
if lp.is_null() {
return 0;
}
if self.is_connected() { if self.is_connected() {
warn!(context, 0, "SMTP already connected."); warn!(context, 0, "SMTP already connected.");
return 1; return 1;
} }
// Safe because we checked for null pointer above. if lp.send_server.is_empty() || lp.send_port == 0 {
let lp = unsafe { *lp };
if lp.addr.is_null() || lp.send_server.is_null() || lp.send_port == 0 {
log_event!(context, Event::ERROR_NETWORK, 0, "SMTP bad parameters.",); log_event!(context, Event::ERROR_NETWORK, 0, "SMTP bad parameters.",);
} }
let raw_addr = unsafe { self.from = if let Ok(addr) = EmailAddress::new(lp.addr.clone()) {
CStr::from_ptr(lp.addr)
.to_str()
.expect("invalid from address")
.to_string()
};
self.from = if let Ok(addr) = EmailAddress::new(raw_addr) {
Some(addr) Some(addr)
} else { } else {
None None
@@ -81,11 +65,7 @@ impl Smtp {
return 0; return 0;
} }
let domain = unsafe { let domain = &lp.send_server;
CStr::from_ptr(lp.send_server)
.to_str()
.expect("invalid send server")
};
let port = lp.send_port as u16; let port = lp.send_port as u16;
let tls = native_tls::TlsConnector::builder() 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) { let creds = if 0 != lp.server_flags & (DC_LP_AUTH_OAUTH2 as i32) {
// oauth2 // oauth2
let addr = as_str(lp.addr); let addr = &lp.addr;
let send_pw = as_str(lp.send_pw); let send_pw = &lp.send_pw;
let access_token = dc_get_oauth2_access_token(context, addr, send_pw, 0); let access_token = dc_get_oauth2_access_token(context, addr, send_pw, 0);
if access_token.is_none() { if access_token.is_none() {
return 0; 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 { } else {
// plain // plain
let user = unsafe { CStr::from_ptr(lp.send_user).to_str().unwrap().to_string() }; let user = lp.send_user.clone();
let pw = unsafe { CStr::from_ptr(lp.send_pw).to_str().unwrap().to_string() }; let pw = lp.send_pw.clone();
lettre::smtp::authentication::Credentials::new(user, pw) lettre::smtp::authentication::Credentials::new(user, pw)
}; };
@@ -123,7 +103,7 @@ impl Smtp {
lettre::smtp::ClientSecurity::Wrapper(tls_parameters) 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) => { Ok(client) => {
let client = client let client = client
.smtp_utf8(true) .smtp_utf8(true)

View File

@@ -1,9 +1,9 @@
use crate::constants::Event; use crate::constants::Event;
use crate::context::Context; use crate::context::Context;
pub use libsqlite3_sys::*;
pub use mmime::carray::*; pub use mmime::carray::*;
pub use mmime::clist::*; pub use mmime::clist::*;
pub use rusqlite::ffi::*;
/// Callback function that should be given to dc_context_new(). /// Callback function that should be given to dc_context_new().
/// ///
@@ -22,7 +22,7 @@ pub type dc_receive_imf_t = unsafe fn(
_: &Context, _: &Context,
_: *const libc::c_char, _: *const libc::c_char,
_: size_t, _: size_t,
_: *const libc::c_char, _: &str,
_: uint32_t, _: uint32_t,
_: uint32_t, _: uint32_t,
) -> (); ) -> ();
@@ -32,7 +32,7 @@ Context is only used for logging and to get information about
the online state. */ the online state. */
pub type dc_precheck_imf_t = 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 = pub type dc_set_config_t =
unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char) -> (); unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char) -> ();
pub type dc_get_config_t = pub type dc_get_config_t =

View File

@@ -244,15 +244,8 @@ unsafe fn stress_functions(context: &Context) {
free(fn0 as *mut libc::c_void); free(fn0 as *mut libc::c_void);
free(fn1 as *mut libc::c_void); free(fn1 as *mut libc::c_void);
} }
let keys = dc_get_config(
context,
b"sys.config_keys\x00" as *const u8 as *const libc::c_char,
);
assert!(!keys.is_null());
assert_ne!(0, *keys.offset(0isize) as libc::c_int);
let res = format!(" {} ", as_str(keys)); let res = dc_get_config(context, "sys.config_keys");
free(keys as *mut libc::c_void);
assert!(!res.contains(" probably_never_a_key ")); assert!(!res.contains(" probably_never_a_key "));
assert!(res.contains(" addr ")); assert!(res.contains(" addr "));
@@ -669,13 +662,11 @@ fn test_encryption_decryption() {
j += 1 j += 1
} }
let (public_key, private_key) = let (public_key, private_key) = dc_pgp_create_keypair("foo@bar.de").unwrap();
dc_pgp_create_keypair(b"foo@bar.de\x00" as *const u8 as *const libc::c_char).unwrap();
private_key.split_key().unwrap(); private_key.split_key().unwrap();
let (public_key2, private_key2) = let (public_key2, private_key2) = dc_pgp_create_keypair("two@zwo.de").unwrap();
dc_pgp_create_keypair(b"two@zwo.de\x00" as *const u8 as *const libc::c_char).unwrap();
assert_ne!(public_key, public_key2); assert_ne!(public_key, public_key2);