Compare commits

..

45 Commits

Author SHA1 Message Date
holger krekel
d7360064a0 Merge remote-tracking branch 'origin/imap-locks' into exp1 2019-07-16 13:45:45 +02:00
dignifiedquire
c8290de628 possible fix(imap): split connection and stream locks 2019-07-16 10:57:21 +02:00
dignifiedquire
cdfc8c6fa7 refactor: move more methods onto the sql struct 2019-07-15 00:33:02 +02:00
dignifiedquire
668c647fdd refactor: cleanup config values and move to their own file 2019-07-14 23:57:05 +02:00
dignifiedquire
6e73b3728d fix chat deletion 2019-07-14 16:42:27 +02:00
dignifiedquire
127e2193af Merge remote-tracking branch 'origin/master' into flub-sqlite 2019-07-14 16:15:50 +02:00
dignifiedquire
1bf1baa409 fix various bugs 2019-07-14 16:15:08 +02:00
dignifiedquire
03a9b62a8a fix and improve sql escaping 2019-07-13 22:46:36 +02:00
holga
0742bb222d try fix darwin 2019-07-13 21:49:59 +02:00
dignifiedquire
e700bc3a81 some cleanup work 2019-07-13 18:46:24 +02:00
dignifiedquire
ab48745cc9 chore(ci): appveyor 2019-07-13 11:41:05 +02:00
dignifiedquire
45a3bed3ad chore(ci): hardcode target 2019-07-13 11:39:02 +02:00
dignifiedquire
f3663aab1f try fixing appveyor build to 64bit 2019-07-13 11:31:23 +02:00
dignifiedquire
157c847c85 Merge remote-tracking branch 'origin/master' into flub-sqlite 2019-07-13 11:25:56 +02:00
dignifiedquire
c5252c9313 more string fixes 2019-07-12 23:22:03 +02:00
dignifiedquire
d19d3985e8 fix: safer string conversions 2019-07-12 22:50:56 +02:00
dignifiedquire
8714599655 refactor: rename dc_sqlite3 to sql 2019-07-12 21:57:34 +02:00
dignifiedquire
f3884e30ac undo 32bit tests 2019-07-12 21:39:07 +02:00
dignifiedquire
b5f4c263e5 ci: try running 32bit without cross 2019-07-12 21:30:17 +02:00
dignifiedquire
98fb79f172 test on 32bit linux 2019-07-12 21:24:04 +02:00
dignifiedquire
753cc4d6dc fix: contact creation 2019-07-12 20:58:42 +02:00
dignifiedquire
9d2ee5c0f7 fix: get_contacts logic was broken 2019-07-12 11:17:49 +02:00
dignifiedquire
08d8eebc37 fix: uses exists instead of execute where needed 2019-07-12 09:04:38 +02:00
dignifiedquire
ef31412d9e ignore expected errors 2019-07-12 08:51:05 +02:00
dignifiedquire
ecbd6fb154 No more vararg printing (drop dc_log_) 2019-07-11 22:09:58 +02:00
dignifiedquire
b6392ee582 try newer rust 2019-07-11 18:36:44 +02:00
dignifiedquire
3366eb147d fix dc_job sql call, to reduce contention 2019-07-11 10:58:58 +02:00
dignifiedquire
3b27dd28b6 use r2d2 pool 2019-07-11 00:17:06 +02:00
dignifiedquire
45f7eba1f4 fix segfaults and some queries 2019-07-10 22:41:20 +02:00
dignifiedquire
a0acfca255 fix last prepares 2019-07-10 18:31:41 +02:00
dignifiedquire
9dda90dd5d fix ffi 2019-07-10 17:38:54 +02:00
dignifiedquire
808a0f2890 fix tests 2019-07-10 16:45:50 +02:00
dignifiedquire
5b04dc8fa6 most prep done 2019-07-10 16:45:50 +02:00
dignifiedquire
8c14924964 more prepare conversions 2019-07-10 16:45:05 +02:00
dignifiedquire
39b92687d3 fix string truncation 2019-07-10 16:45:05 +02:00
dignifiedquire
0ff09e55c7 more improvements in sql code 2019-07-10 16:45:05 +02:00
dignifiedquire
180bc926b6 less preparation 2019-07-10 16:45:05 +02:00
dignifiedquire
8790a2dc52 add sql.query_map 2019-07-10 16:45:05 +02:00
dignifiedquire
d3e521ded0 rebase fixes 2019-07-10 16:45:05 +02:00
dignifiedquire
813aae08a3 example of how to prepare now 2019-07-10 16:45:05 +02:00
dignifiedquire
078c8859f4 cleanup from rebase 2019-07-10 16:45:05 +02:00
dignifiedquire
34414b6059 upgrade and compile again 2019-07-10 16:45:05 +02:00
Floris Bruynooghe
ceb2b49be5 Some more progress on the rebase fallout and this branch 2019-07-10 16:45:05 +02:00
Floris Bruynooghe
a791af2d90 Clean up the worst rebase mistakes 2019-07-10 16:45:05 +02:00
dignifiedquire
ab41679855 refactor: safe sql access 2019-07-10 16:45:05 +02:00
58 changed files with 1223 additions and 4577 deletions

2
.gitattributes vendored
View File

@@ -2,7 +2,7 @@
# ensures this even if the user has not set core.autocrlf.
* text=auto
# binary files should be detected by git, however, to be sure, you can add them here explicitly
# binary files should be detected by git, however, to be sure, you can add them here explictly
*.png binary
*.jpg binary
*.gif binary

3
.gitignore vendored
View File

@@ -1,5 +1,6 @@
/target
**/*.rs.bk
Cargo.lock
# ignore vi temporaries
*~
@@ -16,5 +17,3 @@ python/.tox
*.egg-info
__pycache__
python/src/deltachat/capi*.so
python/liveconfig*

2954
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat"
version = "1.0.0-alpha.3"
version = "1.0.0-alpha.2"
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
edition = "2018"
license = "MPL"
@@ -41,8 +41,6 @@ r2d2_sqlite = "0.11.0"
r2d2 = "0.8.5"
strum = "0.15.0"
strum_macros = "0.15.0"
thread-local-object = "0.1.0"
backtrace = "0.3.33"
[dev-dependencies]
tempfile = "3.0"
@@ -54,10 +52,6 @@ members = [
"deltachat-ffi"
]
[patch.crates-io]
rusqlite = { git = "http://github.com/dignifiedquire/rusqlite", branch = "fix/text", features = ["bundled"] }
[[example]]
name = "simple"
path = "examples/simple.rs"

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat_ffi"
version = "1.0.0-alpha.3"
version = "1.0.0-alpha.1"
description = "Deltachat FFI"
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
edition = "2018"
@@ -24,4 +24,3 @@ default = ["vendored", "nightly", "ringbuf"]
vendored = ["deltachat/vendored"]
nightly = ["deltachat/nightly"]
ringbuf = ["deltachat/ringbuf"]

View File

@@ -503,8 +503,8 @@ int dc_chat_is_sending_locations (const dc_chat_t*);
#define DC_STATE_OUT_MDN_RCVD 28
#define DC_MAX_GET_TEXT_LEN 30000 // approx. max. length returned by dc_msg_get_text()
#define DC_MAX_GET_INFO_LEN 100000 // approx. max. length returned by dc_get_msg_info()
#define DC_MAX_GET_TEXT_LEN 30000 // approx. max. lenght returned by dc_msg_get_text()
#define DC_MAX_GET_INFO_LEN 100000 // approx. max. lenght returned by dc_get_msg_info()
dc_msg_t* dc_msg_new (dc_context_t*, int viewtype);
@@ -667,7 +667,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t*);
* A voice message that was directly recorded by the user.
* For all other audio messages, the type #DC_MSG_AUDIO should be used.
* File and duration are set via dc_msg_set_file(), dc_msg_set_duration()
* and retrieved via dc_msg_get_file(), dc_msg_get_duration()
* and retieved via dc_msg_get_file(), dc_msg_get_duration()
*/
#define DC_MSG_VOICE 41
@@ -768,9 +768,9 @@ int64_t dc_lot_get_timestamp (const dc_lot_t*);
* @}
*/
#define DC_LP_AUTH_FLAGS (DC_LP_AUTH_OAUTH2|DC_LP_AUTH_NORMAL) // if none of these flags are set, the default is chosen
#define DC_LP_IMAP_SOCKET_FLAGS (DC_LP_IMAP_SOCKET_STARTTLS|DC_LP_IMAP_SOCKET_SSL|DC_LP_IMAP_SOCKET_PLAIN) // if none of these flags are set, the default is chosen
#define DC_LP_SMTP_SOCKET_FLAGS (DC_LP_SMTP_SOCKET_STARTTLS|DC_LP_SMTP_SOCKET_SSL|DC_LP_SMTP_SOCKET_PLAIN) // if none of these flags are set, the default is chosen
#define DC_LP_AUTH_FLAGS (DC_LP_AUTH_OAUTH2|DC_LP_AUTH_NORMAL) // if none of these flags are set, the default is choosen
#define DC_LP_IMAP_SOCKET_FLAGS (DC_LP_IMAP_SOCKET_STARTTLS|DC_LP_IMAP_SOCKET_SSL|DC_LP_IMAP_SOCKET_PLAIN) // if none of these flags are set, the default is choosen
#define DC_LP_SMTP_SOCKET_FLAGS (DC_LP_SMTP_SOCKET_STARTTLS|DC_LP_SMTP_SOCKET_SSL|DC_LP_SMTP_SOCKET_PLAIN) // if none of these flags are set, the default is choosen
@@ -851,7 +851,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t*);
* The library-user should report an error to the end-user.
* Passed to the callback given to dc_context_new().
*
* As most things are asynchronous, things may go wrong at any time and the user
* As most things are asynchrounous, things may go wrong at any time and the user
* should not be disturbed by a dialog or so. Instead, use a bubble or so.
*
* However, for ongoing processes (eg. dc_configure())
@@ -882,7 +882,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t*);
*
* Moreover, if the UI detects that the device is offline,
* it is probably more useful to report this to the user
* instead of the string from data2.
* instread of the string from data2.
*
* @param data1 (int) 1=first/new network error, should be reported the user;
* 0=subsequent network error, should be logged only

View File

@@ -10,8 +10,6 @@
#[macro_use]
extern crate human_panic;
use std::str::FromStr;
use deltachat::*;
// TODO: constants
@@ -93,10 +91,7 @@ pub unsafe extern "C" fn dc_set_config(
assert!(!key.is_null(), "invalid key");
let context = &*context;
match config::Config::from_str(dc_tools::as_str(key)) {
Ok(key) => context.set_config(key, as_opt_str(value)).is_ok() as libc::c_int,
Err(_) => 0,
}
config::set(context, dc_tools::as_str(key), as_opt_str(value))
}
#[no_mangle]
@@ -108,13 +103,7 @@ pub unsafe extern "C" fn dc_get_config(
assert!(!key.is_null(), "invalid key");
let context = &*context;
match config::Config::from_str(dc_tools::as_str(key)) {
Ok(key) => {
let value = context.get_config(key).unwrap_or_default();
dc_tools::to_cstring(value)
}
Err(_) => std::ptr::null_mut(),
}
into_cstring(config::get(context, dc_tools::as_str(key)))
}
#[no_mangle]
@@ -137,7 +126,7 @@ pub unsafe extern "C" fn dc_get_oauth2_url(
let addr = dc_tools::to_string(addr);
let redirect = dc_tools::to_string(redirect);
match oauth2::dc_get_oauth2_url(context, addr, redirect) {
Some(res) => dc_tools::to_cstring(res),
Some(res) => libc::strdup(dc_tools::to_cstring(res).as_ptr()),
None => std::ptr::null_mut(),
}
}
@@ -481,7 +470,7 @@ pub unsafe extern "C" fn dc_delete_chat(context: *mut dc_context_t, chat_id: u32
assert!(!context.is_null());
let context = &*context;
// TODO: update to indicate public api success/failure of deletion
// TODO: update to indiciate public api success/failure of deletion
dc_chat::dc_delete_chat(context, chat_id);
}
@@ -1546,3 +1535,7 @@ fn as_opt_str<'a>(s: *const libc::c_char) -> Option<&'a str> {
Some(dc_tools::as_str(s))
}
unsafe fn into_cstring(s: impl AsRef<str>) -> *mut libc::c_char {
dc_tools::dc_strdup(dc_tools::to_cstring(s).as_ptr())
}

View File

@@ -1,5 +1,3 @@
use std::str::FromStr;
use deltachat::config;
use deltachat::constants::*;
use deltachat::context::*;
@@ -72,7 +70,7 @@ pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
sql::execute(
context,
&context.sql,
"DELETE FROM config WHERE keyname LIKE 'imap.%' OR keyname LIKE 'configured%';",
"DELETE FROM config WHERE keyname LIKE \'imap.%\' OR keyname LIKE \'configured%\';",
params![],
);
sql::execute(context, &context.sql, "DELETE FROM leftgrps;", params![]);
@@ -132,14 +130,14 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
.set_config(context, "import_spec", Some(as_str(real_spec)));
current_block = 7149356873433890176;
} else {
let rs = context.sql.get_config(context, "import_spec");
let rs = context.sql.get_config(context, "import_spec", None);
if rs.is_none() {
error!(context, 0, "Import: No file or folder given.");
current_block = 8522321847195001863;
} else {
current_block = 7149356873433890176;
}
real_spec = to_cstring(rs.unwrap_or_default());
real_spec = strdup(to_cstring(rs.unwrap_or_default()).as_ptr());
}
match current_block {
8522321847195001863 => {}
@@ -177,10 +175,10 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
let path_plus_name = format!("{}/{}", as_str(real_spec), name);
info!(context, 0, "Import: {}", path_plus_name);
let path_plus_name_c = to_cstring(path_plus_name);
if 0 != dc_poke_eml_file(context, path_plus_name_c) {
if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
read_cnt += 1
}
free(path_plus_name_c as *mut _);
}
}
current_block = 1622411330066726685;
@@ -380,16 +378,18 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let mut args = line.splitn(3, ' ');
let arg0 = args.next().unwrap_or_default();
let arg1 = args.next().unwrap_or_default();
let arg1_c = if arg1.is_empty() {
let arg1_c = to_cstring(arg1);
let arg1_c_ptr = if arg1.is_empty() {
std::ptr::null()
} else {
to_cstring(arg1) as *const _
arg1_c.as_ptr()
};
let arg2 = args.next().unwrap_or_default();
let arg2_c = if arg2.is_empty() {
let arg2_c = to_cstring(arg2);
let arg2_c_ptr = if arg2.is_empty() {
std::ptr::null()
} else {
to_cstring(arg2) as *const _
arg2_c.as_ptr()
};
match arg0 {
@@ -479,9 +479,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
},
"auth" => {
if 0 == S_IS_AUTH {
let is_pw = context
.get_config(config::Config::MailPw)
.unwrap_or_default();
let is_pw = config::get(context, "mail_pw");
if arg1 == is_pw {
S_IS_AUTH = 1;
} else {
@@ -495,7 +493,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(!arg1.is_empty(), "Argument <file> missing");
dc_close(context);
ensure!(
0 != dc_open(context, arg1_c, 0 as *const libc::c_char),
0 != dc_open(context, arg1_c_ptr, 0 as *const libc::c_char),
"Open failed"
);
}
@@ -536,7 +534,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
!arg1.is_empty() && !arg2.is_empty(),
"Arguments <msg-id> <setup-code> expected"
);
if 0 == dc_continue_key_transfer(context, arg1.parse().unwrap(), arg2_c) {
if 0 == dc_continue_key_transfer(context, arg1.parse().unwrap(), arg2_c_ptr) {
bail!("Continue key transfer failed");
}
}
@@ -551,7 +549,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
"import-backup" => {
ensure!(!arg1.is_empty(), "Argument <backup-file> missing.");
dc_imex(context, 12, arg1_c, 0 as *const libc::c_char);
dc_imex(context, 12, arg1_c_ptr, 0 as *const libc::c_char);
}
"export-keys" => {
dc_imex(context, 1, context.get_blobdir(), 0 as *const libc::c_char);
@@ -588,7 +586,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
free(setup_code as *mut libc::c_void);
}
"poke" => {
ensure!(0 != poke_spec(context, arg1_c), "Poke failed");
ensure!(0 != poke_spec(context, arg1_c_ptr), "Poke failed");
}
"reset" => {
ensure!(!arg1.is_empty(), "Argument <bits> missing: 1=jobs, 2=peerstates, 4=private keys, 8=rest but server config");
@@ -601,15 +599,15 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
"set" => {
ensure!(!arg1.is_empty(), "Argument <key> missing.");
let key = config::Config::from_str(&arg1)?;
let value = if arg2.is_empty() { None } else { Some(arg2) };
context.set_config(key, value)?;
ensure!(
0 != config::set(context, &arg1, Some(&arg2)),
"Set config failed"
);
}
"get" => {
ensure!(!arg1.is_empty(), "Argument <key> missing.");
let key = config::Config::from_str(&arg1)?;
let val = context.get_config(key);
println!("{}={:?}", key, val);
let val = config::get(context, &arg1);
println!("{}={}", arg1, val);
}
"info" => {
println!("{}", to_string(dc_get_info(context)));
@@ -622,7 +620,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
"listchats" | "listarchived" | "chats" => {
let listflags = if arg0 == "listarchived" { 0x01 } else { 0 };
let chatlist = dc_get_chatlist(context, listflags, arg1_c, 0 as uint32_t);
let chatlist = dc_get_chatlist(context, listflags, arg1_c_ptr, 0 as uint32_t);
ensure!(!chatlist.is_null(), "Failed to retrieve chatlist");
let mut i: libc::c_int;
@@ -780,7 +778,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
"creategroup" => {
ensure!(!arg1.is_empty(), "Argument <name> missing.");
let chat_id_1: libc::c_int = dc_create_group_chat(context, 0, arg1_c) as libc::c_int;
let chat_id_1: libc::c_int =
dc_create_group_chat(context, 0, arg1_c_ptr) as libc::c_int;
if chat_id_1 != 0 {
println!("Group#{} created successfully.", chat_id_1,);
} else {
@@ -789,7 +788,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
"createverified" => {
ensure!(!arg1.is_empty(), "Argument <name> missing.");
let chat_id_2: libc::c_int = dc_create_group_chat(context, 1, arg1_c) as libc::c_int;
let chat_id_2: libc::c_int =
dc_create_group_chat(context, 1, arg1_c_ptr) as libc::c_int;
if chat_id_2 != 0 {
println!("VerifiedGroup#{} created successfully.", chat_id_2,);
} else {
@@ -828,7 +828,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
"groupname" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(!arg1.is_empty(), "Argument <name> missing.");
if 0 != dc_set_chat_name(context, dc_chat_get_id(sel_chat), arg1_c) {
if 0 != dc_set_chat_name(context, dc_chat_get_id(sel_chat), arg1_c_ptr) {
println!("Chat name set");
} else {
bail!("Failed to set chat name");
@@ -842,7 +842,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
context,
dc_chat_get_id(sel_chat),
if !arg1.is_empty() {
arg1_c
arg1_c_ptr
} else {
std::ptr::null_mut()
},
@@ -907,7 +907,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let seconds = arg1.parse().unwrap();
dc_send_locations_to_chat(context, dc_chat_get_id(sel_chat), seconds);
println!("Locations will be sent to Chat#{} for {} seconds. Use 'setlocation <lat> <lng>' to play around.", dc_chat_get_id(sel_chat), seconds);
println!("Locations will be sent to Chat#{} for {} seconds. Use \'setlocation <lat> <lng>\' to play around.", dc_chat_get_id(sel_chat), seconds);
}
"setlocation" => {
ensure!(
@@ -933,11 +933,9 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let msg = to_cstring(format!("{} {}", arg1, arg2));
if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg) {
if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg.as_ptr()) {
println!("Message sent.");
free(msg as *mut _);
} else {
free(msg as *mut _);
bail!("Sending failed.");
}
}
@@ -958,8 +956,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(!arg1.is_empty() && !arg2.is_empty(), "No file given.");
let msg_0 = dc_msg_new(context, if arg0 == "sendimage" { 20 } else { 60 });
dc_msg_set_file(msg_0, arg1_c, 0 as *const libc::c_char);
dc_msg_set_text(msg_0, arg2_c);
dc_msg_set_file(msg_0, arg1_c_ptr, 0 as *const libc::c_char);
dc_msg_set_text(msg_0, arg2_c_ptr);
dc_send_msg(context, dc_chat_get_id(sel_chat), msg_0);
dc_msg_unref(msg_0);
}
@@ -972,7 +970,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
0 as libc::c_uint
};
let msglist_0 = dc_search_msgs(context, chat, arg1_c);
let msglist_0 = dc_search_msgs(context, chat, arg1_c_ptr);
if !msglist_0.is_null() {
log_msglist(context, msglist_0);
@@ -985,7 +983,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
if !arg1.is_empty() {
let draft_0 = dc_msg_new(context, 10);
dc_msg_set_text(draft_0, arg1_c);
dc_msg_set_text(draft_0, arg1_c_ptr);
dc_set_draft(context, dc_chat_get_id(sel_chat), draft_0);
dc_msg_unref(draft_0);
println!("Draft saved.");
@@ -1077,7 +1075,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
} else {
0x2
},
arg1_c,
arg1_c_ptr,
);
if !contacts.is_null() {
log_contactlist(context, contacts);
@@ -1093,13 +1091,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
if !arg2.is_empty() {
let book = dc_mprintf(
b"%s\n%s\x00" as *const u8 as *const libc::c_char,
arg1_c,
arg2_c,
arg1_c_ptr,
arg2_c_ptr,
);
dc_add_address_book(context, book);
free(book as *mut libc::c_void);
} else {
if 0 == dc_create_contact(context, 0 as *const libc::c_char, arg1_c) {
if 0 == dc_create_contact(context, 0 as *const libc::c_char, arg1_c_ptr) {
bail!("Failed to create contact");
}
}
@@ -1146,7 +1144,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
"checkqr" => {
ensure!(!arg1.is_empty(), "Argument <qr-content> missing.");
let res = dc_check_qr(context, arg1_c);
let res = dc_check_qr(context, arg1_c_ptr);
println!(
"state={}, id={}, text1={}, text2={}",
(*res).state as libc::c_int,
@@ -1174,7 +1172,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
if 0 != dc_read_file(
context,
arg1_c,
arg1_c_ptr,
&mut buf as *mut *mut libc::c_uchar as *mut *mut libc::c_void,
&mut buf_bytes,
) {
@@ -1192,8 +1190,5 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
dc_chat_unref(sel_chat);
}
free(arg1_c as *mut _);
free(arg2_c as *mut _);
Ok(())
}

View File

@@ -398,10 +398,11 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
if args.len() == 2 {
if 0 == unsafe {
let a = to_cstring(&args[1]);
let res = dc_open(&mut context, a, 0 as *const _);
free(a as *mut _);
res
dc_open(
&mut context,
to_cstring(&args[1]).as_ptr(),
0 as *const libc::c_char,
)
} {
println!("Error: Cannot open {}.", args[0],);
}
@@ -481,10 +482,11 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
let mut args = line.splitn(2, ' ');
let arg0 = args.next().unwrap_or_default();
let arg1 = args.next().unwrap_or_default();
let arg1_c = if arg1.is_empty() {
let arg1_c = to_cstring(arg1);
let arg1_c_ptr = if arg1.is_empty() {
std::ptr::null()
} else {
to_cstring(arg1)
arg1_c.as_ptr()
};
match arg0 {
@@ -513,7 +515,10 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
dc_configure(&ctx.read().unwrap());
}
"oauth2" => {
if let Some(addr) = ctx.read().unwrap().get_config(config::Config::Addr) {
let addr = config::get(&ctx.read().unwrap(), "addr");
if addr.is_empty() {
println!("oauth2: set addr first.");
} else {
let oauth2_url = dc_get_oauth2_url(
&ctx.read().unwrap(),
&addr,
@@ -524,8 +529,6 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
} else {
println!("Open the following url, set mail_pw to the generated token and server_flags to 2:\n{}", oauth2_url.unwrap());
}
} else {
println!("oauth2: set addr first.");
}
}
"clear" => {
@@ -557,15 +560,13 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
"joinqr" => {
start_threads(ctx.clone());
if !arg0.is_empty() {
dc_join_securejoin(&ctx.read().unwrap(), arg1_c);
dc_join_securejoin(&ctx.read().unwrap(), arg1_c_ptr);
}
}
"exit" => return Ok(ExitResult::Exit),
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
}
free(arg1_c as *mut _);
Ok(ExitResult::Continue)
}

View File

@@ -86,8 +86,8 @@ fn main() {
let args = std::env::args().collect::<Vec<String>>();
assert_eq!(args.len(), 2, "missing password");
let pw = args[1].clone();
ctx.set_config(config::Config::Addr, Some("d@testrun.org"));
ctx.set_config(config::Config::MailPw, Some(&pw));
config::set(&ctx, "addr", Some("d@testrun.org"));
config::set(&ctx, "mail_pw", Some(&pw));
dc_configure(&ctx);
thread::sleep(duration);

View File

@@ -4,12 +4,6 @@
- introduce automatic versioning via setuptools_scm,
based on py-X.Y.Z tags
- integrate latest DCC core-rust with dc_close() fixes
- provide a account.shutdown() method and improve termination
logic also in tests. also fixes output-clubbering during
test runs.
0.600.0
---------

7
python/install_py_bindings.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -ex
cargo build -p deltachat_ffi --release
rm -rf build/ src/deltachat/*.so
DCC_RS_DEV=`pwd`/.. pip install -e .

View File

@@ -1,36 +0,0 @@
#!/usr/bin/env python
"""
setup a python binding development in-place install with cargo debug symbols.
"""
import os
import subprocess
if __name__ == "__main__":
os.environ["DCC_RS_TARGET"] = target = "release"
toml = os.path.join(os.getcwd(), "..", "Cargo.toml")
assert os.path.exists(toml)
with open(toml) as f:
s = orig = f.read()
s += "\n"
s += "[profile.release]\n"
s += "debug = true\n"
with open(toml, "w") as f:
f.write(s)
print("temporarily modifying Cargo.toml to provide release build with debug symbols ")
try:
subprocess.check_call([
"cargo", "build", "-p", "deltachat_ffi", "--" + target
])
finally:
with open(toml, "w") as f:
f.write(orig)
print("\nreseted Cargo.toml to previous original state")
subprocess.check_call("rm -rf build/ src/deltachat/*.so" , shell=True)
subprocess.check_call([
"pip", "install", "-e", "."
])

2
python/liveconfig3 Normal file
View File

@@ -0,0 +1,2 @@
addr=digtest1@testrun.org mail_pw=diggydug
addr=digtest2@testrun.org mail_pw=diggydug

View File

@@ -61,10 +61,7 @@ def set_context_callback(dc_context, func):
def clear_context_callback(dc_context):
try:
_DC_CALLBACK_MAP.pop(dc_context, None)
except AttributeError:
pass
_DC_CALLBACK_MAP.pop(dc_context, None)
def get_dc_event_name(integer, _DC_EVENTNAME_MAP={}):

View File

@@ -25,7 +25,6 @@ def ffibuilder():
else:
raise NotImplementedError("Compilation not supported yet on Windows, can you help?")
objs = [os.path.join(projdir, 'target', target, 'libdeltachat.a')]
assert os.path.exists(objs[0]), objs
incs = [os.path.join(projdir, 'deltachat-ffi')]
else:
libs = ['deltachat']

View File

@@ -36,17 +36,14 @@ class Account(object):
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
_destroy_dc_context,
)
if eventlogging:
self._evlogger = EventLogger(self._dc_context, logid)
deltachat.set_context_callback(self._dc_context, self._process_event)
self._threads = IOThreads(self._dc_context, self._evlogger._log_event)
else:
self._threads = IOThreads(self._dc_context)
if hasattr(db_path, "encode"):
db_path = db_path.encode("utf8")
if not lib.dc_open(self._dc_context, db_path, ffi.NULL):
raise ValueError("Could not dc_open: {}".format(db_path))
if eventlogging:
self._evlogger = EventLogger(self._dc_context, logid)
deltachat.set_context_callback(self._dc_context, self._process_event)
self._threads = IOThreads(self._dc_context)
self._configkeys = self.get_config("sys.config_keys").split()
self._imex_completed = threading.Event()
@@ -343,7 +340,7 @@ class Account(object):
def shutdown(self, wait=True):
""" stop threads and close and remove underlying dc_context and callbacks. """
if hasattr(self, "_dc_context") and hasattr(self, "_threads"):
if hasattr(self, "_dc_context"):
self.stop_threads(wait=False) # to interrupt idle and tell python threads to stop
lib.dc_close(self._dc_context)
self.stop_threads(wait=wait) # to wait for threads
@@ -365,11 +362,10 @@ class Account(object):
class IOThreads:
def __init__(self, dc_context, log_event=lambda *args: None):
def __init__(self, dc_context):
self._dc_context = dc_context
self._thread_quitflag = False
self._name2thread = {}
self._log_event = log_event
def is_started(self):
return len(self._name2thread) > 0
@@ -395,19 +391,21 @@ class IOThreads:
thread.join()
def imap_thread_run(self):
self._log_event("py-bindings-info", 0, "IMAP THREAD START")
while not self._thread_quitflag:
lib.dc_perform_imap_jobs(self._dc_context)
if self._thread_quitflag:
break
lib.dc_perform_imap_fetch(self._dc_context)
if self._thread_quitflag:
break
lib.dc_perform_imap_idle(self._dc_context)
self._log_event("py-bindings-info", 0, "IMAP THREAD FINISHED")
def smtp_thread_run(self):
self._log_event("py-bindings-info", 0, "SMTP THREAD START")
while not self._thread_quitflag:
lib.dc_perform_smtp_jobs(self._dc_context)
if self._thread_quitflag:
break
lib.dc_perform_smtp_idle(self._dc_context)
self._log_event("py-bindings-info", 0, "SMTP THREAD FINISHED")
class EventLogger:

View File

@@ -22,7 +22,6 @@ def pytest_runtest_call(item):
# output from concurrent threads printing between execution
# of the test function and the teardown phase of that test function
if "acfactory" in item.funcargs:
print("*"*30, "finalizing", "*"*30)
acfactory = item.funcargs["acfactory"]
acfactory.finalize()

View File

@@ -1,18 +1,12 @@
from __future__ import print_function
import pytest
import os
from deltachat import const, Account
from deltachat import const
from datetime import datetime, timedelta
from conftest import wait_configuration_progress, wait_successful_IMAP_SMTP_connection
class TestOfflineAccount:
def test_wrong_db(self, tmpdir):
p = tmpdir.join("hello.db")
p.write("123")
with pytest.raises(ValueError):
Account(p.strpath)
def test_getinfo(self, acfactory):
ac1 = acfactory.get_unconfigured_account()
d = ac1.get_info()

View File

@@ -32,11 +32,7 @@ class TestInCreation:
chat2.add_contact(c2)
wait_msgs_changed(ac1, 0, 0) # why not chat id?
ac1.forward_messages([prepared_original], chat2)
# XXX there might be two EVENT_MSGS_CHANGED and only one of them
# is the one caused by forwarding
forwarded_id = wait_msgs_changed(ac1, chat2.id)
if forwarded_id == 0:
forwarded_id = wait_msgs_changed(ac1, chat2.id)
forwarded_msg = ac1.get_message_by_id(forwarded_id)
assert forwarded_msg.get_state().is_out_preparing()

View File

@@ -1,7 +1,7 @@
from __future__ import print_function
from deltachat import capi, const, set_context_callback, clear_context_callback
import pytest
from deltachat import capi, Account, const, set_context_callback, clear_context_callback
from deltachat.capi import ffi
from deltachat.capi import lib
from deltachat.account import EventLogger
@@ -23,32 +23,17 @@ def test_dc_close_events():
evlog.set_timeout(5)
set_context_callback(ctx, lambda ctx, evt_name, data1, data2: evlog(evt_name, data1, data2))
capi.lib.dc_close(ctx)
def find(info_string):
while 1:
ev = evlog.get_matching("DC_EVENT_INFO", check_error=False)
data2 = ev[2]
if info_string in data2:
return
else:
print("skipping event", *ev)
find("disconnecting INBOX-watch")
find("disconnecting sentbox-thread")
find("disconnecting mvbox-thread")
find("disconnecting SMTP")
find("Database closed")
# test that we get events from dc_close
print(evlog.get_matching("DC_EVENT_INFO", check_error=False))
print(evlog.get_matching("DC_EVENT_INFO", check_error=False))
print(evlog.get_matching("DC_EVENT_INFO", check_error=False))
print(evlog.get_matching("DC_EVENT_INFO", check_error=False))
def test_wrong_db(tmpdir):
dc_context = ffi.gc(
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
lib.dc_context_unref,
)
p = tmpdir.join("hello.db")
# write an invalid database file
p.write("x123" * 10)
assert not lib.dc_open(dc_context, p.strpath.encode("ascii"), ffi.NULL)
tmpdir.join("hello.db").write("123")
with pytest.raises(ValueError):
Account(db_path=tmpdir.strpath)
def test_event_defines():

View File

@@ -1,3 +0,0 @@
pre-release-commit-message = "chore({{crate_name}}): release {{version}}"
pro-release-commit-message = "chore({{crate_name}}): starting development cycle for {{next_version}}"
no-dev-version = true

View File

@@ -1,3 +1,5 @@
use std::str::FromStr;
use strum::{EnumProperty, IntoEnumIterator};
use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
@@ -6,7 +8,6 @@ use crate::context::Context;
use crate::dc_job::*;
use crate::dc_stock::*;
use crate::dc_tools::*;
use crate::error::Error;
use crate::x::*;
/// The available configuration keys.
@@ -55,105 +56,133 @@ pub enum Config {
ConfiguredSendPort,
ConfiguredServerFlags,
Configured,
// Deprecated
}
// deprecated
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, EnumString, AsRefStr, EnumIter)]
pub enum SysConfig {
#[strum(serialize = "sys.version")]
SysVersion,
Version,
#[strum(serialize = "sys.msgsize_max_recommended")]
SysMsgsizeMaxRecommended,
MsgsizeMaxRecommended,
#[strum(serialize = "sys.config_keys")]
SysConfigKeys,
ConfigKeys,
}
impl Context {
/// Get a configuration key. Returns `None` if no value is set, and no default value found.
pub fn get_config(&self, key: Config) -> Option<String> {
let value = match key {
Config::Selfavatar => {
let rel_path = self.sql.get_config(self, key);
rel_path.map(|p| {
let v = unsafe {
let n = to_cstring(p);
let res = dc_get_abs_path(self, n);
free(n as *mut libc::c_void);
res
};
let r = to_string(v);
unsafe { free(v as *mut _) };
r
})
}
Config::SysVersion => Some(std::str::from_utf8(DC_VERSION_STR).unwrap().into()),
Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)),
Config::SysConfigKeys => Some(get_config_keys_string()),
_ => self.sql.get_config(self, key),
};
/// Get a configuration key.
/// Returns "" when the key is invalid, or no default was found.
pub fn get(context: &Context, key: impl AsRef<str>) -> String {
let key = key.as_ref();
if value.is_some() {
return value;
}
// Default values
match key {
Config::Selfstatus => {
let s = unsafe { dc_stock_str(self, 13) };
let res = to_string(s);
unsafe { free(s as *mut _) };
Some(res)
}
_ => key.get_str("default").map(|s| s.to_string()),
}
if key.starts_with("sys.") {
return get_sys_config_str(key);
}
/// Set the given config key.
/// If `None` is passed as a value the value is cleared and set to the default if there is one.
pub fn set_config(&self, key: Config, value: Option<&str>) -> Result<(), Error> {
match key {
Config::Selfavatar if value.is_some() => {
let rel_path = std::fs::canonicalize(value.unwrap())?;
self.sql
.set_config(self, key, Some(&rel_path.to_string_lossy()))
}
Config::InboxWatch => {
let ret = self.sql.set_config(self, key, value);
unsafe { dc_interrupt_imap_idle(self) };
ret
}
Config::SentboxWatch => {
let ret = self.sql.set_config(self, key, value);
unsafe { dc_interrupt_sentbox_idle(self) };
ret
}
Config::MvboxWatch => {
let ret = self.sql.set_config(self, key, value);
unsafe { dc_interrupt_mvbox_idle(self) };
ret
}
Config::Selfstatus => {
let def = unsafe { dc_stock_str(self, 13) };
let val = if value.is_none() || value.unwrap() == as_str(def) {
None
} else {
value
};
match Config::from_str(key) {
Ok(config_key) => {
let value = match config_key {
Config::Selfavatar => {
let rel_path = context.sql.get_config(context, key, None);
rel_path.map(|p| {
let v = unsafe { dc_get_abs_path(context, to_cstring(p).as_ptr()) };
let r = to_string(v);
unsafe { free(v as *mut _) };
r
})
}
_ => context.sql.get_config(context, key, None),
};
let ret = self.sql.set_config(self, key, val);
unsafe { free(def as *mut libc::c_void) };
ret
if value.is_some() {
return value.unwrap();
}
// Default values
match config_key {
Config::Selfstatus => {
let s = unsafe { dc_stock_str(context, 13) };
let res = to_string(s);
unsafe { free(s as *mut _) };
res
}
_ => config_key
.get_str("default")
.unwrap_or_default()
.to_string(),
}
_ => self.sql.set_config(self, key, value),
}
Err(_) => "".into(),
}
}
/// Returns all available configuration keys concated together.
fn get_config_keys_string() -> String {
fn get_sys_config_str(key: impl AsRef<str>) -> String {
match SysConfig::from_str(key.as_ref()) {
Ok(SysConfig::Version) => std::str::from_utf8(DC_VERSION_STR).unwrap().into(),
Ok(SysConfig::MsgsizeMaxRecommended) => format!("{}", 24 * 1024 * 1024 / 4 * 3),
Ok(SysConfig::ConfigKeys) => get_config_keys_str(),
Err(_) => "".into(),
}
}
fn get_config_keys_str() -> String {
let keys = Config::iter().fold(String::new(), |mut acc, key| {
acc += key.as_ref();
acc += " ";
acc
});
format!(" {} ", keys)
let sys_keys = SysConfig::iter().fold(String::new(), |mut acc, key| {
acc += key.as_ref();
acc += " ";
acc
});
format!(" {} {} ", keys, sys_keys)
}
/// Set the given config key.
/// Returns `1` on success and `0` on failure.
pub fn set(context: &Context, key: impl AsRef<str>, value: Option<&str>) -> libc::c_int {
let mut ret = 0;
// regular keys
match Config::from_str(key.as_ref()) {
Ok(Config::Selfavatar) if value.is_some() => {
let mut rel_path = unsafe { dc_strdup(to_cstring(value.unwrap()).as_ptr()) };
if 0 != unsafe { dc_make_rel_and_copy(context, &mut rel_path) } {
ret = context.sql.set_config(context, key, Some(as_str(rel_path)));
}
unsafe { free(rel_path as *mut libc::c_void) };
}
Ok(Config::InboxWatch) => {
ret = context.sql.set_config(context, key, value);
unsafe { dc_interrupt_imap_idle(context) };
}
Ok(Config::SentboxWatch) => {
ret = context.sql.set_config(context, key, value);
unsafe { dc_interrupt_sentbox_idle(context) };
}
Ok(Config::MvboxWatch) => {
ret = context.sql.set_config(context, key, value);
unsafe { dc_interrupt_mvbox_idle(context) };
}
Ok(Config::Selfstatus) => {
let def = unsafe { dc_stock_str(context, 13) };
let val = if value.is_none() || value.unwrap() == as_str(def) {
None
} else {
value
};
ret = context.sql.set_config(context, key, val);
unsafe { free(def as *mut libc::c_void) };
}
Ok(_) => {
ret = context.sql.set_config(context, key, value);
}
Err(_) => {}
}
ret
}
#[cfg(test)]
@@ -168,10 +197,10 @@ mod tests {
assert_eq!(Config::MailServer.to_string(), "mail_server");
assert_eq!(Config::from_str("mail_server"), Ok(Config::MailServer));
assert_eq!(Config::SysConfigKeys.to_string(), "sys.config_keys");
assert_eq!(SysConfig::ConfigKeys.to_string(), "sys.config_keys");
assert_eq!(
Config::from_str("sys.config_keys"),
Ok(Config::SysConfigKeys)
SysConfig::from_str("sys.config_keys"),
Ok(SysConfig::ConfigKeys)
);
}

View File

@@ -1,6 +1,6 @@
//! Constants
pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00";
pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.1\x00";
pub const DC_MOVE_STATE_MOVING: u32 = 3;
pub const DC_MOVE_STATE_STAY: u32 = 2;
@@ -80,9 +80,9 @@ pub const DC_STATE_OUT_FAILED: usize = 24;
pub const DC_STATE_OUT_DELIVERED: usize = 26;
pub const DC_STATE_OUT_MDN_RCVD: usize = 28;
/// approx. max. length returned by dc_msg_get_text()
/// approx. max. lenght returned by dc_msg_get_text()
pub const DC_MAX_GET_TEXT_LEN: usize = 30000;
/// approx. max. length returned by dc_get_msg_info()
/// approx. max. lenght returned by dc_get_msg_info()
pub const DC_MAX_GET_INFO_LEN: usize = 100000;
pub const DC_CONTACT_ID_SELF: usize = 1;
@@ -119,7 +119,7 @@ pub const DC_MSG_AUDIO: usize = 40;
/// A voice message that was directly recorded by the user.
/// For all other audio messages, the type #DC_MSG_AUDIO should be used.
/// File and duration are set via dc_msg_set_file(), dc_msg_set_duration()
/// and retrieved via dc_msg_get_file(), dc_msg_get_duration()
/// and retieved via dc_msg_get_file(), dc_msg_get_duration()
pub const DC_MSG_VOICE: usize = 41;
/// Video messages.
@@ -173,12 +173,12 @@ pub const DC_LP_SMTP_SOCKET_SSL: usize = 0x20000;
/// If this flag is set, automatic configuration is skipped.
pub const DC_LP_SMTP_SOCKET_PLAIN: usize = 0x40000;
/// if none of these flags are set, the default is chosen
/// if none of these flags are set, the default is choosen
pub const DC_LP_AUTH_FLAGS: usize = (DC_LP_AUTH_OAUTH2 | DC_LP_AUTH_NORMAL);
/// if none of these flags are set, the default is chosen
/// if none of these flags are set, the default is choosen
pub const DC_LP_IMAP_SOCKET_FLAGS: usize =
(DC_LP_IMAP_SOCKET_STARTTLS | DC_LP_IMAP_SOCKET_SSL | DC_LP_IMAP_SOCKET_PLAIN);
/// if none of these flags are set, the default is chosen
/// if none of these flags are set, the default is choosen
pub const DC_LP_SMTP_SOCKET_FLAGS: usize =
(DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN);
@@ -237,7 +237,7 @@ pub enum Event {
/// The library-user should report an error to the end-user.
/// Passed to the callback given to dc_context_new().
///
/// As most things are asynchronous, things may go wrong at any time and the user
/// As most things are asynchrounous, things may go wrong at any time and the user
/// should not be disturbed by a dialog or so. Instead, use a bubble or so.
///
/// However, for ongoing processes (eg. dc_configure())
@@ -265,7 +265,7 @@ pub enum Event {
///
/// Moreover, if the UI detects that the device is offline,
/// it is probably more useful to report this to the user
/// instead of the string from data2.
/// instread of the string from data2.
///
/// @param data1 (int) 1=first/new network error, should be reported the user;
/// 0=subsequent network error, should be logged only

View File

@@ -133,7 +133,7 @@ pub fn dc_context_new(
userdata: *mut libc::c_void,
os_name: *const libc::c_char,
) -> Context {
Context {
let context = Context {
blobdir: Arc::new(RwLock::new(std::ptr::null_mut())),
dbfile: Arc::new(RwLock::new(std::ptr::null_mut())),
inbox: Arc::new(RwLock::new({
@@ -177,7 +177,8 @@ pub fn dc_context_new(
))),
probe_imap_network: Arc::new(RwLock::new(0)),
perform_inbox_jobs_needed: Arc::new(RwLock::new(0)),
}
};
context
}
unsafe fn cb_receive_imf(
@@ -275,11 +276,17 @@ unsafe fn cb_get_config(
key: *const libc::c_char,
def: *const libc::c_char,
) -> *mut libc::c_char {
let res = context
.sql
.get_config(context, as_str(key))
.unwrap_or_else(|| to_string(def));
to_cstring(res)
let d = if def.is_null() {
None
} else {
Some(as_str(def))
};
let res = context.sql.get_config(context, 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) {
@@ -291,6 +298,7 @@ pub unsafe fn dc_context_unref(context: &mut Context) {
}
pub unsafe fn dc_close(context: &Context) {
println!("disconnecting inbox watch yooaa");
info!(context, 0, "disconnecting INBOX-watch",);
context.inbox.read().unwrap().disconnect(context);
info!(context, 0, "disconnecting sentbox-thread",);
@@ -374,27 +382,15 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
let unset = "0";
let l = dc_loginparam_read(context, &context.sql, "");
let l2 = dc_loginparam_read(context, &context.sql, "configured_");
let displayname = context.sql.get_config(context, "displayname");
let displayname = context.sql.get_config(context, "displayname", None);
let chats = dc_get_chat_cnt(context) as usize;
let real_msgs = dc_get_real_msg_cnt(context) as usize;
let deaddrop_msgs = dc_get_deaddrop_msg_cnt(context) as usize;
let contacts = dc_get_real_contact_cnt(context) as usize;
let is_configured = context
.sql
.get_config_int(context, "configured")
.unwrap_or_default();
let dbversion = context
.sql
.get_config_int(context, "dbversion")
.unwrap_or_default();
let e2ee_enabled = context
.sql
.get_config_int(context, "e2ee_enabled")
.unwrap_or_else(|| 1);
let mdns_enabled = context
.sql
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1);
let is_configured = context.sql.get_config_int(context, "configured", 0);
let dbversion = context.sql.get_config_int(context, "dbversion", 0);
let e2ee_enabled = context.sql.get_config_int(context, "e2ee_enabled", 1);
let mdns_enabled = context.sql.get_config_int(context, "mdns_enabled", 1);
let prv_key_cnt: Option<isize> = context.sql.query_row_col(
context,
@@ -419,34 +415,19 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
let l_readable_str = dc_loginparam_get_readable(&l);
let l2_readable_str = dc_loginparam_get_readable(&l2);
let inbox_watch = context
.sql
.get_config_int(context, "inbox_watch")
.unwrap_or_else(|| 1);
let sentbox_watch = context
.sql
.get_config_int(context, "sentbox_watch")
.unwrap_or_else(|| 1);
let mvbox_watch = context
.sql
.get_config_int(context, "mvbox_watch")
.unwrap_or_else(|| 1);
let mvbox_move = context
.sql
.get_config_int(context, "mvbox_move")
.unwrap_or_else(|| 1);
let folders_configured = context
.sql
.get_config_int(context, "folders_configured")
.unwrap_or_default();
let configured_sentbox_folder = context
.sql
.get_config(context, "configured_sentbox_folder")
.unwrap_or_else(|| "<unset>".to_string());
let configured_mvbox_folder = context
.sql
.get_config(context, "configured_mvbox_folder")
.unwrap_or_else(|| "<unset>".to_string());
let inbox_watch = context.sql.get_config_int(context, "inbox_watch", 1);
let sentbox_watch = context.sql.get_config_int(context, "sentbox_watch", 1);
let mvbox_watch = context.sql.get_config_int(context, "mvbox_watch", 1);
let mvbox_move = context.sql.get_config_int(context, "mvbox_move", 1);
let folders_configured = context.sql.get_config_int(context, "folders_configured", 0);
let configured_sentbox_folder =
context
.sql
.get_config(context, "configured_sentbox_folder", Some("<unset>"));
let configured_mvbox_folder =
context
.sql
.get_config(context, "configured_mvbox_folder", Some("<unset>"));
let res = format!(
"deltachat_core_version=v{}\n\
@@ -506,8 +487,8 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
mvbox_watch,
mvbox_move,
folders_configured,
configured_sentbox_folder,
configured_mvbox_folder,
configured_sentbox_folder.unwrap_or_default(),
configured_mvbox_folder.unwrap_or_default(),
mdns_enabled,
e2ee_enabled,
prv_key_cnt.unwrap_or_default(),
@@ -515,7 +496,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
fingerprint_str,
);
to_cstring(res)
strdup(to_cstring(res).as_ptr())
}
pub unsafe fn dc_get_version_str() -> *mut libc::c_char {
@@ -608,7 +589,9 @@ pub fn dc_is_inbox(_context: &Context, folder_name: impl AsRef<str>) -> bool {
}
pub fn dc_is_sentbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
let sentbox_name = context.sql.get_config(context, "configured_sentbox_folder");
let sentbox_name = context
.sql
.get_config(context, "configured_sentbox_folder", None);
if let Some(name) = sentbox_name {
name == folder_name.as_ref()
} else {
@@ -617,7 +600,9 @@ pub fn dc_is_sentbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
}
pub fn dc_is_mvbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
let mvbox_name = context.sql.get_config(context, "configured_mvbox_folder");
let mvbox_name = context
.sql
.get_config(context, "configured_mvbox_folder", None);
if let Some(name) = mvbox_name {
name == folder_name.as_ref()

View File

@@ -3,8 +3,6 @@ use crate::dc_tools::*;
use crate::types::*;
use crate::x::*;
const DC_ARRAY_MAGIC: uint32_t = 0x000a11aa;
/* * the structure behind dc_array_t */
#[derive(Copy, Clone)]
#[repr(C)]
@@ -25,7 +23,7 @@ pub struct dc_array_t {
* To free an array object, use dc_array_unref().
*/
pub unsafe fn dc_array_unref(mut array: *mut dc_array_t) {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
return;
}
if (*array).type_0 == 1i32 {
@@ -37,7 +35,7 @@ pub unsafe fn dc_array_unref(mut array: *mut dc_array_t) {
}
pub unsafe fn dc_array_free_ptr(array: *mut dc_array_t) {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
return;
}
let mut i: size_t = 0i32 as size_t;
@@ -55,7 +53,7 @@ pub unsafe fn dc_array_free_ptr(array: *mut dc_array_t) {
}
pub unsafe fn dc_array_add_uint(mut array: *mut dc_array_t, item: uintptr_t) {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
return;
}
if (*array).count == (*array).allocated {
@@ -80,21 +78,21 @@ pub unsafe fn dc_array_add_ptr(array: *mut dc_array_t, item: *mut libc::c_void)
}
pub unsafe fn dc_array_get_cnt(array: *const dc_array_t) -> size_t {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
return 0i32 as size_t;
}
(*array).count
}
pub unsafe fn dc_array_get_uint(array: *const dc_array_t, index: size_t) -> uintptr_t {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || index >= (*array).count {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || index >= (*array).count {
return 0i32 as uintptr_t;
}
*(*array).array.offset(index as isize)
}
pub unsafe fn dc_array_get_id(array: *const dc_array_t, index: size_t) -> uint32_t {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || index >= (*array).count {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || index >= (*array).count {
return 0i32 as uint32_t;
}
if (*array).type_0 == 1i32 {
@@ -104,7 +102,7 @@ pub unsafe fn dc_array_get_id(array: *const dc_array_t, index: size_t) -> uint32
}
pub unsafe fn dc_array_get_ptr(array: *const dc_array_t, index: size_t) -> *mut libc::c_void {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || index >= (*array).count {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || index >= (*array).count {
return 0 as *mut libc::c_void;
}
*(*array).array.offset(index as isize) as *mut libc::c_void
@@ -112,7 +110,7 @@ pub unsafe fn dc_array_get_ptr(array: *const dc_array_t, index: size_t) -> *mut
pub unsafe fn dc_array_get_latitude(array: *const dc_array_t, index: size_t) -> libc::c_double {
if array.is_null()
|| (*array).magic != DC_ARRAY_MAGIC
|| (*array).magic != 0xa11aai32 as libc::c_uint
|| index >= (*array).count
|| (*array).type_0 != 1i32
|| *(*array).array.offset(index as isize) == 0
@@ -124,7 +122,7 @@ pub unsafe fn dc_array_get_latitude(array: *const dc_array_t, index: size_t) ->
pub unsafe fn dc_array_get_longitude(array: *const dc_array_t, index: size_t) -> libc::c_double {
if array.is_null()
|| (*array).magic != DC_ARRAY_MAGIC
|| (*array).magic != 0xa11aai32 as libc::c_uint
|| index >= (*array).count
|| (*array).type_0 != 1i32
|| *(*array).array.offset(index as isize) == 0
@@ -136,7 +134,7 @@ pub unsafe fn dc_array_get_longitude(array: *const dc_array_t, index: size_t) ->
pub unsafe fn dc_array_get_accuracy(array: *const dc_array_t, index: size_t) -> libc::c_double {
if array.is_null()
|| (*array).magic != DC_ARRAY_MAGIC
|| (*array).magic != 0xa11aai32 as libc::c_uint
|| index >= (*array).count
|| (*array).type_0 != 1i32
|| *(*array).array.offset(index as isize) == 0
@@ -148,7 +146,7 @@ pub unsafe fn dc_array_get_accuracy(array: *const dc_array_t, index: size_t) ->
pub unsafe fn dc_array_get_timestamp(array: *const dc_array_t, index: size_t) -> i64 {
if array.is_null()
|| (*array).magic != DC_ARRAY_MAGIC
|| (*array).magic != 0xa11aai32 as libc::c_uint
|| index >= (*array).count
|| (*array).type_0 != 1i32
|| *(*array).array.offset(index as isize) == 0
@@ -160,7 +158,7 @@ pub unsafe fn dc_array_get_timestamp(array: *const dc_array_t, index: size_t) ->
pub unsafe fn dc_array_get_chat_id(array: *const dc_array_t, index: size_t) -> uint32_t {
if array.is_null()
|| (*array).magic != DC_ARRAY_MAGIC
|| (*array).magic != 0xa11aai32 as libc::c_uint
|| index >= (*array).count
|| (*array).type_0 != 1i32
|| *(*array).array.offset(index as isize) == 0
@@ -172,7 +170,7 @@ pub unsafe fn dc_array_get_chat_id(array: *const dc_array_t, index: size_t) -> u
pub unsafe fn dc_array_get_contact_id(array: *const dc_array_t, index: size_t) -> uint32_t {
if array.is_null()
|| (*array).magic != DC_ARRAY_MAGIC
|| (*array).magic != 0xa11aai32 as libc::c_uint
|| index >= (*array).count
|| (*array).type_0 != 1i32
|| *(*array).array.offset(index as isize) == 0
@@ -184,7 +182,7 @@ pub unsafe fn dc_array_get_contact_id(array: *const dc_array_t, index: size_t) -
pub unsafe fn dc_array_get_msg_id(array: *const dc_array_t, index: size_t) -> uint32_t {
if array.is_null()
|| (*array).magic != DC_ARRAY_MAGIC
|| (*array).magic != 0xa11aai32 as libc::c_uint
|| index >= (*array).count
|| (*array).type_0 != 1i32
|| *(*array).array.offset(index as isize) == 0
@@ -196,7 +194,7 @@ pub unsafe fn dc_array_get_msg_id(array: *const dc_array_t, index: size_t) -> ui
pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *mut libc::c_char {
if array.is_null()
|| (*array).magic != DC_ARRAY_MAGIC
|| (*array).magic != 0xa11aai32 as libc::c_uint
|| index >= (*array).count
|| (*array).type_0 != 1i32
|| *(*array).array.offset(index as isize) == 0
@@ -218,7 +216,7 @@ pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *m
*/
pub unsafe fn dc_array_is_independent(array: *const dc_array_t, index: size_t) -> libc::c_int {
if array.is_null()
|| (*array).magic != DC_ARRAY_MAGIC
|| (*array).magic != 0xa11aai32 as libc::c_uint
|| index >= (*array).count
|| (*array).type_0 != 1i32
|| *(*array).array.offset(index as isize) == 0
@@ -234,7 +232,7 @@ pub unsafe fn dc_array_search_id(
needle: uint32_t,
ret_index: *mut size_t,
) -> bool {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
return false;
}
let data: *mut uintptr_t = (*array).array;
@@ -253,7 +251,7 @@ pub unsafe fn dc_array_search_id(
}
pub unsafe fn dc_array_get_raw(array: *const dc_array_t) -> *const uintptr_t {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
return 0 as *const uintptr_t;
}
(*array).array
@@ -268,7 +266,7 @@ pub unsafe fn dc_array_new_typed(type_0: libc::c_int, initsize: size_t) -> *mut
array = calloc(1, ::std::mem::size_of::<dc_array_t>()) as *mut dc_array_t;
assert!(!array.is_null());
(*array).magic = DC_ARRAY_MAGIC;
(*array).magic = 0xa11aai32 as uint32_t;
(*array).count = 0i32 as size_t;
(*array).allocated = if initsize < 1 { 1 } else { initsize };
(*array).type_0 = type_0;
@@ -284,7 +282,7 @@ pub unsafe fn dc_array_new_typed(type_0: libc::c_int, initsize: size_t) -> *mut
}
pub unsafe fn dc_array_empty(mut array: *mut dc_array_t) {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
return;
}
(*array).count = 0i32 as size_t;
@@ -292,7 +290,7 @@ pub unsafe fn dc_array_empty(mut array: *mut dc_array_t) {
pub unsafe fn dc_array_duplicate(array: *const dc_array_t) -> *mut dc_array_t {
let mut ret: *mut dc_array_t;
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
return 0 as *mut dc_array_t;
}
ret = dc_array_new((*array).allocated);
@@ -308,7 +306,7 @@ pub unsafe fn dc_array_duplicate(array: *const dc_array_t) -> *mut dc_array_t {
}
pub unsafe fn dc_array_sort_ids(array: *mut dc_array_t) {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || (*array).count <= 1 {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || (*array).count <= 1 {
return;
}
qsort(
@@ -332,7 +330,7 @@ unsafe extern "C" fn cmp_intptr_t(p1: *const libc::c_void, p2: *const libc::c_vo
}
pub unsafe fn dc_array_sort_strings(array: *mut dc_array_t) {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || (*array).count <= 1 {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || (*array).count <= 1 {
return;
}
qsort(
@@ -357,7 +355,7 @@ pub unsafe fn dc_array_get_string(
array: *const dc_array_t,
sep: *const libc::c_char,
) -> *mut libc::c_char {
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || sep.is_null() {
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || sep.is_null() {
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
}
let cnt = (*array).count as usize;
@@ -376,7 +374,7 @@ pub unsafe fn dc_array_get_string(
}
res
});
to_cstring(res)
strdup(to_cstring(res).as_ptr())
}
/// return comma-separated value-string from integer array
@@ -398,7 +396,7 @@ pub unsafe fn dc_arr_to_string(arr: *const uint32_t, cnt: libc::c_int) -> *mut l
res
},
);
to_cstring(res)
strdup(to_cstring(res).as_ptr())
}
#[cfg(test)]
@@ -412,17 +410,22 @@ mod tests {
let arr = dc_array_new(7 as size_t);
assert_eq!(dc_array_get_cnt(arr), 0);
for i in 0..1000 {
let mut i: libc::c_int = 0;
while i < 1000 {
dc_array_add_id(arr, (i + 2) as uint32_t);
i += 1
}
assert_eq!(dc_array_get_cnt(arr), 1000);
for i in 0..1000 {
i = 0;
while i < 1000i32 {
assert_eq!(
dc_array_get_id(arr, i as size_t),
(i + 1i32 * 2i32) as libc::c_uint
);
i += 1
}
assert_eq!(dc_array_get_id(arr, -1i32 as size_t), 0);

View File

@@ -107,7 +107,6 @@ pub fn dc_block_chat(context: &Context, chat_id: u32, new_blocking: libc::c_int)
"UPDATE chats SET blocked=? WHERE id=?;",
params![new_blocking, chat_id as i32],
)
.is_ok()
}
pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
@@ -130,30 +129,20 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
c.type_0 = row.get(1)?;
c.name = {
let raw: String = row.get(2)?;
unsafe { to_cstring(raw) }
unsafe { strdup(to_cstring(raw).as_ptr()) }
};
c.grpid = {
let raw: String = row.get(3)?;
unsafe { to_cstring(raw) }
unsafe { strdup(to_cstring(raw).as_ptr()) }
};
let packed: String = row.get(4)?;
unsafe {
let p = to_cstring(&packed);
dc_param_set_packed((*chat).param, p);
free(p as *mut _);
};
unsafe { dc_param_set_packed((*chat).param, to_cstring(&packed).as_ptr()) };
c.archived = row.get(5)?;
c.blocked = row.get::<_, Option<i32>>(6)?.unwrap_or_default();
c.blocked = row.get(6)?;
c.gossiped_timestamp = row.get(7)?;
c.is_sending_locations = row.get(8)?;
Ok(())
},
);
match res {
Ok(_) => {
let c = unsafe { &mut *chat };
match c.id {
1 => unsafe {
free((*chat).name as *mut libc::c_void);
@@ -182,18 +171,19 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
}
}
}
true
}
Err(err) => match err {
QueryReturnedNoRows => false,
_ => {
error!(
context,
0, "chat: failed to load from db {}: {:?}", chat_id, err
);
false
}
Ok(())
},
);
match res {
Ok(_) => true,
Err(err) => {
error!(
context,
0, "chat: failed to load from db {}: {:?}", chat_id, err
);
false
}
}
}
@@ -286,7 +276,7 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
as_str((*contact).addr),
),
params![],
).is_ok() {
) {
chat_id = sql::get_rowid(
context,
&context.sql,
@@ -333,7 +323,7 @@ pub fn dc_lookup_real_nchat_by_contact_id(
if let Ok((id, blocked)) = context.sql.query_row(
"SELECT c.id, c.blocked FROM chats c INNER JOIN chats_contacts j ON c.id=j.chat_id WHERE c.type=100 AND c.id>9 AND j.contact_id=?;",
params![contact_id as i32],
|row| Ok((row.get(0)?, row.get::<_, Option<i32>>(1)?.unwrap_or_default())),
|row| Ok((row.get(0)?, row.get(1)?)),
) {
unsafe { *ret_chat_id = id };
unsafe { *ret_chat_blocked = blocked };
@@ -494,7 +484,7 @@ unsafe fn prepare_msg_raw(
"Cannot send message; self not in group.",
);
} else {
let from = context.sql.get_config(context, "configured_addr");
let from = context.sql.get_config(context, "configured_addr", None);
if from.is_none() {
error!(context, 0, "Cannot send message, not configured.",);
} else {
@@ -505,9 +495,8 @@ unsafe fn prepare_msg_raw(
} else {
0 as *mut libc::c_char
},
from_c,
from_c.as_ptr(),
);
free(from_c as *mut _);
if (*chat).type_0 == 100 {
if let Some(id) = context.sql.query_row_col(
@@ -544,22 +533,18 @@ unsafe fn prepare_msg_raw(
so that E2EE is no longer available at a later point (reset, changed settings),
we do not send the message out at all */
do_guarantee_e2ee = 0;
e2ee_enabled = context
.sql
.get_config_int(context, "e2ee_enabled")
.unwrap_or_else(|| 1);
e2ee_enabled = context.sql.get_config_int(context, "e2ee_enabled", 1);
if 0 != e2ee_enabled && dc_param_get_int((*msg).param, 'u' as i32, 0) == 0 {
let mut can_encrypt = 1;
let mut all_mutual = 1;
let mut can_encrypt: libc::c_int = 1;
let mut all_mutual: libc::c_int = 1;
let res = context.sql.query_row(
context.sql.query_row(
"SELECT ps.prefer_encrypted, c.addr \
FROM chats_contacts cc \
LEFT JOIN contacts c ON cc.contact_id=c.id \
LEFT JOIN acpeerstates ps ON c.addr=ps.addr \
WHERE cc.chat_id=? AND cc.contact_id>9;",
params![(*chat).id],
|row| {
params![(*chat).id], |row| {
let state: String = row.get(1)?;
if let Some(prefer_encrypted) = row.get::<_, Option<i32>>(0)? {
@@ -583,14 +568,8 @@ unsafe fn prepare_msg_raw(
all_mutual = 0;
}
Ok(())
},
);
match res {
Ok(_) => {}
Err(err) => {
warn!(context, 0, "chat: failed to load peerstates: {:?}", err);
}
}
).unwrap();
if 0 != can_encrypt {
if 0 != all_mutual {
@@ -681,9 +660,7 @@ unsafe fn prepare_msg_raw(
0.0,
),
],
)
.is_ok()
{
) {
location_id = sql::get_rowid2(
context,
&context.sql,
@@ -717,7 +694,7 @@ unsafe fn prepare_msg_raw(
to_string(new_references),
location_id as i32,
]
).is_ok() {
) {
msg_id = sql::get_rowid(
context,
&context.sql,
@@ -771,9 +748,9 @@ unsafe fn get_parent_mime_headers(
FROM msgs WHERE chat_id=? AND from_id!=?);",
params![(*chat).id as i32, 1],
|row| {
*parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?);
*parent_in_reply_to = to_cstring(row.get::<_, String>(1)?);
*parent_references = to_cstring(row.get::<_, String>(2)?);
*parent_rfc724_mid = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
*parent_in_reply_to = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
*parent_references = dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
Ok(())
},
)
@@ -789,9 +766,12 @@ unsafe fn get_parent_mime_headers(
FROM msgs WHERE chat_id=? AND from_id==?);",
params![(*chat).id as i32, 1],
|row| {
*parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?);
*parent_in_reply_to = to_cstring(row.get::<_, String>(1)?);
*parent_references = to_cstring(row.get::<_, String>(2)?);
*parent_rfc724_mid =
dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
*parent_in_reply_to =
dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
*parent_references =
dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
Ok(())
},
)
@@ -830,8 +810,7 @@ unsafe fn last_msg_in_chat_encrypted(
if let Some(packed) = packed {
let msg_param = dc_param_new();
let packed_c = to_cstring(packed);
dc_param_set_packed(msg_param, packed_c);
free(packed_c as *mut _);
dc_param_set_packed(msg_param, packed_c.as_ptr());
if 0 != dc_param_exists(msg_param, 'c' as i32) {
last_is_encrypted = 1;
@@ -849,8 +828,7 @@ pub unsafe fn dc_chat_update_param(chat: *mut Chat) -> libc::c_int {
&(*chat).context.sql,
"UPDATE chats SET param=? WHERE id=?",
params![to_string((*(*chat).param).packed), (*chat).id as i32],
)
.is_ok() as libc::c_int
) as libc::c_int
}
pub unsafe fn dc_is_contact_in_chat(
@@ -1021,7 +999,7 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t
to_string((*(*msg).param).packed),
1,
]
).is_ok() {
) {
sth_changed = 1;
}
}
@@ -1097,10 +1075,7 @@ pub unsafe fn dc_get_chat_msgs(
};
let success = if chat_id == 1 {
let show_emails = context
.sql
.get_config_int(context, "show_emails")
.unwrap_or_default();
let show_emails = context.sql.get_config_int(context, "show_emails", 0);
context.sql.query_map(
"SELECT m.id, m.timestamp FROM msgs m \
LEFT JOIN chats ON m.chat_id=chats.id \
@@ -1186,15 +1161,13 @@ pub fn dc_marknoticed_chat(context: &Context, chat_id: u32) -> bool {
{
return false;
}
if sql::execute(
if !sql::execute(
context,
&context.sql,
"UPDATE msgs \
SET state=13 WHERE chat_id=? AND state=10;",
params![chat_id as i32],
)
.is_err()
{
) {
return false;
}
context.call_cb(Event::MSGS_CHANGED, 0 as uintptr_t, 0 as uintptr_t);
@@ -1214,15 +1187,13 @@ pub fn dc_marknoticed_all_chats(context: &Context) -> bool {
return false;
}
if sql::execute(
if !sql::execute(
context,
&context.sql,
"UPDATE msgs \
SET state=13 WHERE state=10;",
params![],
)
.is_err()
{
) {
return false;
}
@@ -1322,25 +1293,21 @@ pub fn dc_archive_chat(context: &Context, chat_id: u32, archive: libc::c_int) ->
return true;
}
if 0 != archive {
if sql::execute(
if !sql::execute(
context,
&context.sql,
"UPDATE msgs SET state=13 WHERE chat_id=? AND state=10;",
params![chat_id as i32],
)
.is_err()
{
) {
return false;
}
}
if sql::execute(
if !sql::execute(
context,
&context.sql,
"UPDATE chats SET archived=? WHERE id=?;",
params![archive, chat_id as i32],
)
.is_err()
{
) {
return false;
}
context.call_cb(Event::MSGS_CHANGED, 0 as uintptr_t, 0 as uintptr_t);
@@ -1359,44 +1326,36 @@ pub fn dc_delete_chat(context: &Context, chat_id: u32) -> bool {
}
unsafe { dc_chat_unref(obj) };
if sql::execute(
if !sql::execute(
context,
&context.sql,
"DELETE FROM msgs_mdns WHERE msg_id IN (SELECT id FROM msgs WHERE chat_id=?);",
params![chat_id as i32],
)
.is_err()
{
) {
return false;
}
if sql::execute(
if !sql::execute(
context,
&context.sql,
"DELETE FROM msgs WHERE chat_id=?;",
params![chat_id as i32],
)
.is_err()
{
) {
return false;
}
if sql::execute(
if !sql::execute(
context,
&context.sql,
"DELETE FROM chats_contacts WHERE chat_id=?;",
params![chat_id as i32],
)
.is_err()
{
) {
return false;
}
if sql::execute(
if !sql::execute(
context,
&context.sql,
"DELETE FROM chats WHERE id=?;",
params![chat_id as i32],
)
.is_err()
{
) {
return false;
}
@@ -1480,9 +1439,7 @@ pub unsafe fn dc_create_group_chat(
as_str(chat_name),
grpid
],
)
.is_ok()
{
) {
chat_id = sql::get_rowid(context, &context.sql, "chats", "grpid", grpid);
if chat_id != 0 {
if 0 != dc_add_to_chat_contacts_table(context, chat_id, 1) {
@@ -1518,8 +1475,7 @@ pub fn dc_add_to_chat_contacts_table(
&context.sql,
"INSERT INTO chats_contacts (chat_id, contact_id) VALUES(?, ?)",
params![chat_id as i32, contact_id as i32],
)
.is_ok() as libc::c_int
) as libc::c_int
}
pub unsafe fn dc_add_contact_to_chat(
@@ -1558,14 +1514,14 @@ pub unsafe fn dc_add_contact_to_chat_ex(
"Cannot add contact to group; self not in group.",
);
} else {
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
/* we shoud respect this - whatever we send to the group, it gets discarded anyway! */
if 0 != flags & 0x1 && dc_param_get_int((*chat).param, 'U' as i32, 0) == 1 {
dc_param_set((*chat).param, 'U' as i32, 0 as *const libc::c_char);
dc_chat_update_param(chat);
}
let self_addr = context
.sql
.get_config(context, "configured_addr")
.get_config(context, "configured_addr", Some(""))
.unwrap_or_default();
if as_str((*contact).addr) != &self_addr {
// ourself is added using DC_CONTACT_ID_SELF, do not add it explicitly.
@@ -1718,7 +1674,7 @@ pub unsafe fn dc_remove_contact_from_chat(
"Cannot remove contact from chat; self not in group.",
);
} else {
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
/* we shoud respect this - whatever we send to the group, it gets discarded anyway! */
if !contact.is_null() {
if dc_param_get_int((*chat).param, 'U' as i32, 0) == 0 {
(*msg).type_0 = 10;
@@ -1755,9 +1711,7 @@ pub unsafe fn dc_remove_contact_from_chat(
&context.sql,
"DELETE FROM chats_contacts WHERE chat_id=? AND contact_id=?;",
params![chat_id as i32, contact_id as i32],
)
.is_ok()
{
) {
context.call_cb(Event::CHAT_MODIFIED, chat_id as uintptr_t, 0 as uintptr_t);
success = 1;
}
@@ -1820,7 +1774,7 @@ pub unsafe fn dc_set_chat_name(
"Cannot set chat name; self not in group",
);
} else {
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
/* we shoud respect this - whatever we send to the group, it gets discarded anyway! */
if sql::execute(
context,
&context.sql,
@@ -1830,9 +1784,7 @@ pub unsafe fn dc_set_chat_name(
chat_id as i32
),
params![],
)
.is_ok()
{
) {
if dc_param_get_int((*chat).param, 'U' as i32, 0i32) == 0i32 {
(*msg).type_0 = 10i32;
(*msg).text = dc_stock_system_msg(
@@ -1889,7 +1841,7 @@ pub unsafe fn dc_set_chat_profile_image(
"Cannot set chat profile image; self not in group.",
);
} else {
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
/* we shoud respect this - whatever we send to the group, it gets discarded anyway! */
if !new_image.is_null() {
new_image_rel = dc_strdup(new_image);
if 0 == dc_make_rel_and_copy(context, &mut new_image_rel) {
@@ -1970,69 +1922,73 @@ pub unsafe fn dc_forward_msgs(
curr_timestamp = dc_create_smeared_timestamps(context, msg_cnt);
idsstr = dc_arr_to_string(msg_ids, msg_cnt);
let ids = context.sql.query_map(
format!(
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
as_str(idsstr)
),
params![],
|row| row.get::<_, i32>(0),
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
);
for id in ids.unwrap() {
let src_msg_id = id;
if !dc_msg_load_from_db(msg, context, src_msg_id as u32) {
break;
}
dc_param_set_packed(original_param, (*(*msg).param).packed);
if (*msg).from_id != 1i32 as libc::c_uint {
dc_param_set_int((*msg).param, 'a' as i32, 1i32);
}
dc_param_set((*msg).param, 'c' as i32, 0 as *const libc::c_char);
dc_param_set((*msg).param, 'u' as i32, 0 as *const libc::c_char);
dc_param_set((*msg).param, 'S' as i32, 0 as *const libc::c_char);
let new_msg_id: uint32_t;
if (*msg).state == 18i32 {
let fresh9 = curr_timestamp;
curr_timestamp = curr_timestamp + 1;
new_msg_id = prepare_msg_raw(context, chat, msg, fresh9);
let save_param: *mut dc_param_t = (*msg).param;
(*msg).param = original_param;
(*msg).id = src_msg_id as uint32_t;
let old_fwd: *mut libc::c_char = dc_param_get(
(*msg).param,
'P' as i32,
b"\x00" as *const u8 as *const libc::c_char,
);
let new_fwd: *mut libc::c_char = dc_mprintf(
b"%s %d\x00" as *const u8 as *const libc::c_char,
old_fwd,
new_msg_id,
);
dc_param_set((*msg).param, 'P' as i32, new_fwd);
dc_msg_save_param_to_disk(msg);
free(new_fwd as *mut libc::c_void);
free(old_fwd as *mut libc::c_void);
(*msg).param = save_param
} else {
(*msg).state = 20i32;
let fresh10 = curr_timestamp;
curr_timestamp = curr_timestamp + 1;
new_msg_id = prepare_msg_raw(context, chat, msg, fresh10);
dc_job_send_msg(context, new_msg_id);
}
carray_add(
created_db_entries,
chat_id as uintptr_t as *mut libc::c_void,
0 as *mut libc::c_uint,
);
carray_add(
created_db_entries,
new_msg_id as uintptr_t as *mut libc::c_void,
0 as *mut libc::c_uint,
);
}
context
.sql
.query_map(
format!(
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
as_str(idsstr)
),
params![],
|row| row.get::<_, i32>(0),
|ids| {
for id in ids {
let src_msg_id = id?;
if !dc_msg_load_from_db(msg, context, src_msg_id as u32) {
break;
}
dc_param_set_packed(original_param, (*(*msg).param).packed);
if (*msg).from_id != 1i32 as libc::c_uint {
dc_param_set_int((*msg).param, 'a' as i32, 1i32);
}
dc_param_set((*msg).param, 'c' as i32, 0 as *const libc::c_char);
dc_param_set((*msg).param, 'u' as i32, 0 as *const libc::c_char);
dc_param_set((*msg).param, 'S' as i32, 0 as *const libc::c_char);
let new_msg_id: uint32_t;
if (*msg).state == 18i32 {
let fresh9 = curr_timestamp;
curr_timestamp = curr_timestamp + 1;
new_msg_id = prepare_msg_raw(context, chat, msg, fresh9);
let save_param: *mut dc_param_t = (*msg).param;
(*msg).param = original_param;
(*msg).id = src_msg_id as uint32_t;
let old_fwd: *mut libc::c_char = dc_param_get(
(*msg).param,
'P' as i32,
b"\x00" as *const u8 as *const libc::c_char,
);
let new_fwd: *mut libc::c_char = dc_mprintf(
b"%s %d\x00" as *const u8 as *const libc::c_char,
old_fwd,
new_msg_id,
);
dc_param_set((*msg).param, 'P' as i32, new_fwd);
dc_msg_save_param_to_disk(msg);
free(new_fwd as *mut libc::c_void);
free(old_fwd as *mut libc::c_void);
(*msg).param = save_param
} else {
(*msg).state = 20i32;
let fresh10 = curr_timestamp;
curr_timestamp = curr_timestamp + 1;
new_msg_id = prepare_msg_raw(context, chat, msg, fresh10);
dc_job_send_msg(context, new_msg_id);
}
carray_add(
created_db_entries,
chat_id as uintptr_t as *mut libc::c_void,
0 as *mut libc::c_uint,
);
carray_add(
created_db_entries,
new_msg_id as uintptr_t as *mut libc::c_void,
0 as *mut libc::c_uint,
);
}
Ok(())
},
)
.unwrap(); // TODO: better error handling
}
if !created_db_entries.is_null() {
@@ -2098,7 +2054,7 @@ pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char {
0,
)
.unwrap_or_else(|| "Err".into());
ret = to_cstring(ret_raw);
ret = dc_strdup(to_cstring(ret_raw).as_ptr());
} else if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
if (*chat).id == 1 {
ret = dc_stock_str((*chat).context, 8)

View File

@@ -74,12 +74,7 @@ pub unsafe fn dc_has_ongoing(context: &Context) -> libc::c_int {
}
}
pub fn dc_is_configured(context: &Context) -> libc::c_int {
if context
.sql
.get_config_int(context, "configured")
.unwrap_or_default()
> 0
{
if context.sql.get_config_int(context, "configured", 0) > 0 {
1
} else {
0
@@ -102,14 +97,14 @@ pub fn dc_stop_ongoing_process(context: &Context) {
pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_job_t) {
let flags: libc::c_int;
let mut current_block: u64;
let mut success = false;
let mut imap_connected_here = false;
let mut smtp_connected_here = false;
let mut ongoing_allocated_here = false;
let mut success: libc::c_int = 0i32;
let mut imap_connected_here: libc::c_int = 0i32;
let mut smtp_connected_here: libc::c_int = 0i32;
let mut ongoing_allocated_here: libc::c_int = 0i32;
let mut param_autoconfig = None;
if !(0 == dc_alloc_ongoing(context)) {
ongoing_allocated_here = true;
ongoing_allocated_here = 1i32;
if !context.sql.is_open() {
error!(context, 0, "Cannot configure, database not opened.",);
} else {
@@ -634,7 +629,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
let r_0 = dc_loginparam_get_readable(&param);
info!(context, 0, "Trying: {}", r_0,);
if context
if 0 != context
.inbox
.read()
.unwrap()
@@ -671,7 +666,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
let r_1 = dc_loginparam_get_readable(&param);
info!(context, 0, "Trying: {}", r_1,);
if context
if 0 != context
.inbox
.read()
.unwrap()
@@ -703,7 +698,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
let r_2 = dc_loginparam_get_readable(&param);
info!(context, 0, "Trying: {}", r_2,);
if context
if 0 != context
.inbox
.read()
.unwrap()
@@ -759,7 +754,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
match current_block {
2927484062889439186 => {}
_ => {
imap_connected_here = true;
imap_connected_here = 1;
if !s.shall_stop_ongoing {
context.call_cb(
Event::CONFIGURE_PROGRESS,
@@ -774,7 +769,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
0 as uintptr_t,
);
/* try to connect to SMTP - if we did not got an autoconfig, the first try was SSL-465 and we do a second try with STARTTLS-587 */
if !context
if 0 == context
.smtp
.clone()
.lock()
@@ -814,7 +809,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
0, "Trying: {}", r_3,
);
if !context
if 0 == context
.smtp
.clone()
.lock()
@@ -860,7 +855,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
r_4
);
if !context
if 0 == context
.smtp
.clone()
.lock()
@@ -887,7 +882,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
match current_block {
2927484062889439186 => {}
_ => {
smtp_connected_here = true;
smtp_connected_here = 1;
if !s.shall_stop_ongoing {
context.call_cb(
Event::CONFIGURE_PROGRESS,
@@ -907,18 +902,14 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
.get_config_int(
context,
"mvbox_watch",
)
.unwrap_or_else(
|| 1,
1,
)
|| 0 != context
.sql
.get_config_int(
context,
"mvbox_move",
)
.unwrap_or_else(
|| 1,
1,
) {
0x1
} else {
@@ -991,7 +982,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
uintptr_t
);
dc_ensure_secret_key_exists(context);
success = true;
success = 1;
info!(
context,
0,
@@ -1039,37 +1030,21 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
}
}
}
if imap_connected_here {
if 0 != imap_connected_here {
context.inbox.read().unwrap().disconnect(context);
}
if smtp_connected_here {
if 0 != smtp_connected_here {
context.smtp.clone().lock().unwrap().disconnect();
}
/*
if !success {
// disconnect if configure did not succeed
if imap_connected_here {
// context.inbox.read().unwrap().disconnect(context);
}
if smtp_connected_here {
// context.smtp.clone().lock().unwrap().disconnect();
}
} else {
assert!(imap_connected_here && smtp_connected_here);
info!(
context,
0, "Keeping IMAP/SMTP connections open after successful configuration"
);
}
*/
if ongoing_allocated_here {
if 0 != ongoing_allocated_here {
dc_free_ongoing(context);
}
context.call_cb(
Event::CONFIGURE_PROGRESS,
(if success { 1000 } else { 0 }) as uintptr_t,
(if 0 != success { 1000 } else { 0 }) as uintptr_t,
0 as uintptr_t,
);
}
@@ -1098,14 +1073,12 @@ unsafe fn moz_autoconfigure(
tag_config: 0,
};
let url_c = to_cstring(url);
let xml_raw = read_autoconf_file(context, url_c);
free(url_c as *mut libc::c_void);
let xml_raw = read_autoconf_file(context, to_cstring(url).as_ptr());
if xml_raw.is_null() {
return None;
}
moz_ac.in_emaillocalpart = to_cstring(&param_in.addr);
moz_ac.in_emaillocalpart = dc_strdup(to_cstring(&param_in.addr).as_ptr());
let p = strchr(moz_ac.in_emaillocalpart, '@' as i32);
if p.is_null() {
@@ -1162,13 +1135,11 @@ unsafe fn moz_autoconfigure_text_cb(
let mut moz_ac: *mut moz_autoconfigure_t = userdata as *mut moz_autoconfigure_t;
let mut val: *mut libc::c_char = dc_strdup(text);
dc_trim(val);
let addr = to_cstring(&(*moz_ac).in_0.addr);
dc_str_replace(
&mut val,
b"%EMAILADDRESS%\x00" as *const u8 as *const libc::c_char,
addr,
to_cstring(&(*moz_ac).in_0.addr).as_ptr(),
);
free(addr as *mut libc::c_void);
dc_str_replace(
&mut val,
b"%EMAILLOCALPART%\x00" as *const u8 as *const libc::c_char,
@@ -1302,7 +1273,7 @@ fn read_autoconf_file(context: &Context, url: *const libc::c_char) -> *mut libc:
.send()
.and_then(|mut res| res.text())
{
Ok(res) => unsafe { to_cstring(res) },
Ok(res) => unsafe { libc::strdup(to_cstring(res).as_ptr()) },
Err(_err) => {
info!(context, 0, "Can\'t read file.",);
@@ -1318,7 +1289,7 @@ unsafe fn outlk_autodiscover(
) -> Option<dc_loginparam_t> {
let current_block: u64;
let mut xml_raw: *mut libc::c_char = 0 as *mut libc::c_char;
let mut url = to_cstring(url__);
let mut url = dc_strdup(to_cstring(url__).as_ptr());
let mut outlk_ad = outlk_autodiscover_t {
in_0: param_in,
out: dc_loginparam_new(),
@@ -1511,18 +1482,13 @@ pub fn dc_connect_to_configured_imap(context: &Context, imap: &Imap) -> libc::c_
if imap.is_connected() {
ret_connected = 1
} else if context
.sql
.get_config_int(context, "configured")
.unwrap_or_default()
== 0
{
} else if context.sql.get_config_int(context, "configured", 0) == 0 {
warn!(context, 0, "Not configured, cannot connect.",);
} else {
let param = dc_loginparam_read(context, &context.sql, "configured_");
// the trailing underscore is correct
if imap.connect(context, &param) {
if 0 != imap.connect(context, &param) {
ret_connected = 2;
}
}

View File

@@ -34,9 +34,7 @@ pub fn dc_marknoticed_contact(context: &Context, contact_id: u32) {
&context.sql,
"UPDATE msgs SET state=13 WHERE from_id=? AND state=10;",
params![contact_id as i32],
)
.is_ok()
{
) {
context.call_cb(Event::MSGS_CHANGED, 0, 0);
}
}
@@ -74,7 +72,7 @@ pub unsafe fn dc_lookup_contact_id_by_addr(
let addr_normalized = as_str(addr_normalized_c);
let addr_self = context
.sql
.get_config(context, "configured_addr")
.get_config(context, "configured_addr", None)
.unwrap_or_default();
let contact_id = if addr_normalized == addr_self {
@@ -163,9 +161,7 @@ pub unsafe fn dc_block_contact(context: &Context, contact_id: uint32_t, new_bloc
&context.sql,
"UPDATE contacts SET blocked=? WHERE id=?;",
params![new_blocking, contact_id as i32],
)
.is_ok()
{
) {
// also (un)block all chats with _only_ this contact - we do not delete them to allow a
// non-destructive blocking->unblocking.
// (Maybe, beside normal chats (type=100) we should also block group chats with only this user.
@@ -176,7 +172,7 @@ pub unsafe fn dc_block_contact(context: &Context, contact_id: uint32_t, new_bloc
&context.sql,
"UPDATE chats SET blocked=? WHERE type=? AND id IN (SELECT chat_id FROM chats_contacts WHERE contact_id=?);",
params![new_blocking, 100, contact_id as i32],
).is_ok() {
) {
dc_marknoticed_contact(context, contact_id);
context.call_cb(
Event::CONTACTS_CHANGED,
@@ -259,7 +255,7 @@ pub unsafe fn dc_contact_empty(mut contact: *mut dc_contact_t) {
/* address is in our address book */
/* set on Alice's side for contacts like Bob that have scanned the QR code offered by her. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling dc_contact_is_verified() ! */
/* set on Bob's side for contacts scanned and verified from a QR code. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling dc_contact_is_verified() ! */
/* contact added manually by dc_create_contact(), this should be the largets origin as otherwise the user cannot modify the names */
/* contact added mannually by dc_create_contact(), this should be the largets origin as otherwise the user cannot modify the names */
/* contacts with at least this origin value are shown in the contact list */
/* contacts with at least this origin value are verified and known not to be spam */
/* contacts with at least this origin value start a new "normal" chat, defaults to off */
@@ -277,12 +273,15 @@ pub unsafe fn dc_contact_load_from_db(
if contact_id == 1 as libc::c_uint {
(*contact).id = contact_id;
(*contact).name = dc_stock_str((*contact).context, 2);
(*contact).addr = to_cstring(
(*contact)
.context
.sql
.get_config((*contact).context, "configured_addr")
.unwrap_or_default(),
(*contact).addr = dc_strdup(
to_cstring(
(*contact)
.context
.sql
.get_config((*contact).context, "configured_addr", Some(""))
.unwrap_or_default(),
)
.as_ptr(),
);
true
} else {
@@ -291,11 +290,11 @@ pub unsafe fn dc_contact_load_from_db(
params![contact_id as i32],
|row| {
(*contact).id = contact_id;
(*contact).name = to_cstring(row.get::<_, String>(0)?);
(*contact).addr = to_cstring(row.get::<_, String>(1)?);
(*contact).name = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
(*contact).addr = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
(*contact).origin = row.get(2)?;
(*contact).blocked = row.get::<_, Option<i32>>(3)?.unwrap_or_default();
(*contact).authname = to_cstring(row.get::<_, String>(4)?);
(*contact).blocked = row.get(3)?;
(*contact).authname = dc_strdup(to_cstring(row.get::<_, String>(4)?).as_ptr());
Ok(())
}
).is_ok()
@@ -338,7 +337,7 @@ pub fn dc_add_or_lookup_contact(
let addr = as_str(addr_c);
let addr_self = context
.sql
.get_config(context, "configured_addr")
.get_config(context, "configured_addr", Some(""))
.unwrap_or_default();
if addr == addr_self {
@@ -436,9 +435,7 @@ pub fn dc_add_or_lookup_contact(
&context.sql,
"INSERT INTO contacts (name, addr, origin) VALUES(?, ?, ?);",
params![to_string(name), addr, origin,],
)
.is_ok()
{
) {
row_id = sql::get_rowid(context, &context.sql, "contacts", "addr", addr);
unsafe { *sth_modified = 2 };
} else {
@@ -530,7 +527,7 @@ pub fn dc_get_contacts(
) -> *mut dc_array_t {
let self_addr = context
.sql
.get_config(context, "configured_addr")
.get_config(context, "configured_addr", Some(""))
.unwrap_or_default();
let mut add_self = false;
@@ -571,7 +568,7 @@ pub fn dc_get_contacts(
let self_name = context
.sql
.get_config(context, "displayname")
.get_config(context, "displayname", Some(""))
.unwrap_or_default();
let self_name2 = unsafe { dc_stock_str(context, 2) };
@@ -732,7 +729,7 @@ pub unsafe fn dc_get_contact_encrinfo(
free(fingerprint_other_verified as *mut libc::c_void);
free(fingerprint_other_unverified as *mut libc::c_void);
to_cstring(ret)
strdup(to_cstring(ret).as_ptr())
}
unsafe fn cat_fingerprint(
@@ -801,9 +798,7 @@ pub fn dc_delete_contact(context: &Context, contact_id: u32) -> bool {
&context.sql,
"DELETE FROM contacts WHERE id=?;",
params![contact_id as i32],
)
.is_ok()
{
) {
context.call_cb(Event::CONTACTS_CHANGED, 0, 0);
true
} else {
@@ -900,9 +895,9 @@ pub fn dc_contact_get_profile_image(contact: *const dc_contact_t) -> *mut libc::
}
if unsafe { (*contact).id } == 1 {
let context = unsafe { (*contact) }.context;
if let Some(avatar) = context.get_config(config::Config::Selfavatar) {
image_abs = unsafe { to_cstring(avatar) };
let avatar = config::get(unsafe { (*contact).context }, "selfavatar");
if !avatar.is_empty() {
image_abs = unsafe { dc_strdup(to_cstring(avatar).as_ptr()) };
}
}
// TODO: else get image_abs from contact param
@@ -992,7 +987,7 @@ pub fn dc_addr_equals_self(context: &Context, addr: *const libc::c_char) -> libc
if !addr.is_null() {
let normalized_addr = unsafe { dc_addr_normalize(addr) };
if let Some(self_addr) = context.sql.get_config(context, "configured_addr") {
if let Some(self_addr) = context.sql.get_config(context, "configured_addr", None) {
ret = (as_str(normalized_addr) == self_addr) as libc::c_int;
}
unsafe { free(normalized_addr as *mut libc::c_void) };

View File

@@ -53,7 +53,7 @@ pub unsafe fn dc_dehtml(buf_terminated: *mut libc::c_char) -> *mut libc::c_char
dc_saxparser_parse(&mut saxparser, buf_terminated);
free(dehtml.last_href as *mut libc::c_void);
to_cstring(dehtml.strbuilder)
strdup(to_cstring(dehtml.strbuilder).as_ptr())
}
unsafe fn dehtml_text_cb(

View File

@@ -1,5 +1,5 @@
use std::collections::HashSet;
use std::ffi::CStr;
use std::ffi::{CStr, CString};
use std::str::FromStr;
use mmime::clist::*;
@@ -31,7 +31,7 @@ use crate::x::*;
// attachments of 25 mb brutto should work on the majority of providers
// (brutto examples: web.de=50, 1&1=40, t-online.de=32, gmail=25, posteo=50, yahoo=25, all-inkl=100).
// as an upper limit, we double the size; the core won't send messages larger than this
// to get the netto sizes, we subtract 1 mb header-overhead and the base64-overhead.
// to get the netto sizes, we substract 1 mb header-overhead and the base64-overhead.
// some defaults
#[derive(Clone)]
pub struct dc_e2ee_helper_t {
@@ -80,18 +80,13 @@ pub unsafe fn dc_e2ee_encrypt(
|| plain.is_null())
{
/* libEtPan's pgp_encrypt_mime() takes the parent as the new root. We just expect the root as being given to this function. */
let prefer_encrypt = if 0
!= context
.sql
.get_config_int(context, "e2ee_enabled")
.unwrap_or_default()
{
let prefer_encrypt = if 0 != context.sql.get_config_int(context, "e2ee_enabled", 1) {
EncryptPreference::Mutual
} else {
EncryptPreference::NoPreference
};
let addr = context.sql.get_config(context, "configured_addr");
let addr = context.sql.get_config(context, "configured_addr", None);
if let Some(addr) = addr {
if let Some(public_key) =
@@ -184,7 +179,7 @@ pub unsafe fn dc_e2ee_encrypt(
b"Autocrypt-Gossip\x00" as *const u8
as *const libc::c_char,
),
header,
strdup(header.as_ptr()),
),
);
}
@@ -294,8 +289,10 @@ pub unsafe fn dc_e2ee_encrypt(
sign_key.as_ref(),
) {
let ctext_bytes = ctext_v.len();
let ctext = to_cstring(ctext_v);
(*helper).cdata_to_free = ctext as *mut _;
let ctext_c = CString::new(ctext_v).unwrap();
let ctext = strdup(ctext_c.as_ptr());
(*helper).cdata_to_free = ctext as *mut libc::c_void;
/* create MIME-structure that will contain the encrypted text */
let mut encrypted_part: *mut mailmime = new_data_part(
@@ -352,13 +349,13 @@ pub unsafe fn dc_e2ee_encrypt(
14181132614457621749 => {}
_ => {
let aheader = Aheader::new(addr, public_key, prefer_encrypt);
let rendered = to_cstring(aheader.to_string());
let rendered = CString::new(aheader.to_string()).unwrap();
mailimf_fields_add(
imffields_unprotected,
mailimf_field_new_custom(
strdup(b"Autocrypt\x00" as *const u8 as *const libc::c_char),
rendered,
strdup(rendered.as_ptr()),
),
);
}
@@ -599,7 +596,7 @@ pub unsafe fn dc_e2ee_decrypt(
}
}
/* load private key for decryption */
let self_addr = context.sql.get_config(context, "configured_addr");
let self_addr = context.sql.get_config(context, "configured_addr", None);
if let Some(self_addr) = self_addr {
if private_keyring.load_self_private_for_decrypting(context, self_addr, &context.sql) {
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
@@ -933,12 +930,13 @@ unsafe fn decrypt_part(
add_signatures,
) {
let plain_bytes = plain.len();
let plain_buf = plain.as_ptr() as *const libc::c_char;
let plain_c = CString::new(plain).unwrap();
let plain_buf = strdup(plain_c.as_ptr());
let mut index: size_t = 0i32 as size_t;
let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime;
if mailmime_parse(
plain_buf as *const _,
plain_buf as *const libc::c_char,
plain_bytes,
&mut index,
&mut decrypted_mime,
@@ -1007,7 +1005,7 @@ unsafe fn has_decrypted_pgp_armor(
* that we could use the normal Autocrypt processing.
*
* @private
* @param mime The mime structure to check
* @param mime The mime struture to check
* @return 1=multipart/report found in MIME, 0=no multipart/report found
*/
// TODO should return bool /rtn
@@ -1067,7 +1065,7 @@ pub unsafe fn dc_ensure_secret_key_exists(context: &Context) -> libc::c_int {
(this is to gain some extra-random-seed by the message content and the timespan between program start and message sending) */
let mut success: libc::c_int = 0i32;
let self_addr = context.sql.get_config(context, "configured_addr");
let self_addr = context.sql.get_config(context, "configured_addr", None);
if self_addr.is_none() {
warn!(
context,

View File

@@ -69,9 +69,7 @@ pub unsafe fn dc_imex_has_backup(
if name.starts_with("delta-chat") && name.ends_with(".bak") {
let sql = Sql::new();
if sql.open(context, &path, 0x1) {
let curr_backup_time =
sql.get_config_int(context, "backup_time")
.unwrap_or_default() as u64;
let curr_backup_time = sql.get_config_int(context, "backup_time", 0) as u64;
if curr_backup_time > newest_backup_time {
newest_backup_path = Some(path);
newest_backup_time = curr_backup_time;
@@ -226,13 +224,10 @@ pub unsafe extern "C" fn dc_render_setup_file(
if !(0 == dc_ensure_secret_key_exists(context)) {
let self_addr = context
.sql
.get_config(context, "configured_addr")
.get_config(context, "configured_addr", None)
.unwrap_or_default();
let curr_private_key = Key::from_self_private(context, self_addr, &context.sql);
let e2ee_enabled = context
.sql
.get_config_int(context, "e2ee_enabled")
.unwrap_or_else(|| 1);
let e2ee_enabled = context.sql.get_config_int(context, "e2ee_enabled", 1);
let headers = if 0 != e2ee_enabled {
Some(("Autocrypt-Prefer-Encrypt", "mutual"))
@@ -309,7 +304,7 @@ pub unsafe fn dc_create_setup_code(_context: &Context) -> *mut libc::c_char {
);
}
to_cstring(ret)
strdup(to_cstring(ret).as_ptr())
}
// TODO should return bool /rtn
@@ -393,33 +388,29 @@ fn set_self_key(
let (private_key, public_key, header) = keys.unwrap();
let preferencrypt = header.get("Autocrypt-Prefer-Encrypt");
if sql::execute(
if !sql::execute(
context,
&context.sql,
"DELETE FROM keypairs WHERE public_key=? OR private_key=?;",
params![public_key.to_bytes(), private_key.to_bytes()],
)
.is_err()
{
) {
return 0;
}
if 0 != set_default {
if sql::execute(
if !sql::execute(
context,
&context.sql,
"UPDATE keypairs SET is_default=0;",
params![],
)
.is_err()
{
) {
return 0;
}
} else {
error!(context, 0, "File does not contain a private key.",);
}
let self_addr = context.sql.get_config(context, "configured_addr");
let self_addr = context.sql.get_config(context, "configured_addr", None);
if self_addr.is_none() {
error!(context, 0, "Missing self addr");
@@ -440,14 +431,8 @@ fn set_self_key(
match preferencrypt.map(|s| s.as_str()) {
Some("") => 0,
Some("nopreference") => context
.sql
.set_config_int(context, "e2ee_enabled", 0)
.is_ok() as libc::c_int,
Some("mutual") => context
.sql
.set_config_int(context, "e2ee_enabled", 1)
.is_ok() as libc::c_int,
Some("nopreference") => context.sql.set_config_int(context, "e2ee_enabled", 0),
Some("mutual") => context.sql.set_config_int(context, "e2ee_enabled", 1),
_ => 1,
}
}
@@ -539,7 +524,7 @@ pub unsafe fn dc_normalize_setup_code(
p1 = p1.offset(1);
}
to_cstring(out)
strdup(to_cstring(out).as_ptr())
}
pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) {
@@ -806,75 +791,77 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
0, "***IMPORT-in-progress: total_files_cnt={:?}", total_files_cnt,
);
let res = context.sql.query_map(
"SELECT file_name, file_content FROM backup_blobs ORDER BY id;",
params![],
|row| {
let name: String = row.get(0)?;
let blob: Vec<u8> = row.get(1)?;
context
.sql
.query_map(
"SELECT file_name, file_content FROM backup_blobs ORDER BY id;",
params![],
|row| {
let name: String = row.get(0)?;
let blob: Vec<u8> = row.get(1)?;
Ok((name, blob))
},
|files| {
let mut loop_success = true;
let mut processed_files_cnt = 0;
Ok((name, blob))
},
|files| {
let mut loop_success = true;
let mut processed_files_cnt = 0;
for file in files {
let (file_name, file_blob) = file?;
for file in files {
if file.is_err() {
loop_success = false;
break;
}
let (file_name, file_blob) = file.unwrap();
if context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
if context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
loop_success = false;
break;
}
processed_files_cnt += 1;
let mut permille = processed_files_cnt * 1000 / total_files_cnt;
if permille < 10 {
permille = 10
}
if permille > 990 {
permille = 990
}
context.call_cb(Event::IMEX_PROGRESS, permille as uintptr_t, 0);
if file_blob.is_empty() {
continue;
}
let pathNfilename = format!("{}/{}", as_str(context.get_blobdir()), file_name);
if dc_write_file_safe(context, &pathNfilename, &file_blob) {
continue;
}
error!(
context,
0,
"Storage full? Cannot write file {} with {} bytes.",
&pathNfilename,
file_blob.len(),
);
// otherwise the user may believe the stuff is imported correctly, but there are files missing ...
loop_success = false;
break;
}
processed_files_cnt += 1;
let mut permille = processed_files_cnt * 1000 / total_files_cnt;
if permille < 10 {
permille = 10
}
if permille > 990 {
permille = 990
}
context.call_cb(Event::IMEX_PROGRESS, permille as uintptr_t, 0);
if file_blob.is_empty() {
continue;
}
let pathNfilename = format!("{}/{}", as_str(context.get_blobdir()), file_name);
if dc_write_file_safe(context, &pathNfilename, &file_blob) {
continue;
if !loop_success {
return Err(format_err!("fail").into());
}
error!(
context,
0,
"Storage full? Cannot write file {} with {} bytes.",
&pathNfilename,
file_blob.len(),
);
// otherwise the user may believe the stuff is imported correctly, but there are files missing ...
loop_success = false;
break;
}
if !loop_success {
return Err(format_err!("fail").into());
}
Ok(())
},
);
res.and_then(|_| {
sql::execute(context, &context.sql, "DROP TABLE backup_blobs;", params![])?;
sql::try_execute(context, &context.sql, "VACUUM;")?;
Ok(())
})
.is_ok() as libc::c_int
sql::execute(context, &context.sql, "DROP TABLE backup_blobs;", params![]);
sql::try_execute(context, &context.sql, "VACUUM;");
Ok(())
},
)
.is_ok() as libc::c_int
}
/*******************************************************************************
@@ -895,8 +882,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
.format("delta-chat-%Y-%m-%d.bak")
.to_string();
let buffer = to_cstring(res);
let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer);
free(buffer as *mut _);
let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer.as_ptr());
if dest_pathNfilename.is_null() {
error!(context, 0, "Cannot get backup file name.",);
@@ -923,14 +909,12 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
let sql = Sql::new();
if sql.open(context, as_path(dest_pathNfilename), 0) {
if !sql.table_exists("backup_blobs") {
if sql::execute(
if !sql::execute(
context,
&sql,
"CREATE TABLE backup_blobs (id INTEGER PRIMARY KEY, file_name, file_content);",
params![],
)
.is_err()
{
) {
/* error already logged */
current_block = 11487273724841241105;
} else {
@@ -972,7 +956,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
sql.prepare(
"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);",
move |mut stmt, _| {
move |mut stmt| {
let mut processed_files_cnt = 0;
for entry in dir_handle {
if entry.is_err() {
@@ -1053,10 +1037,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
match current_block {
11487273724841241105 => {}
_ => {
if sql
.set_config_int(context, "backup_time", now as i32)
.is_ok()
{
if 0 != sql.set_config_int(context, "backup_time", now as i32) {
context.call_cb(
Event::IMEX_FILE_WRITTEN,
dest_pathNfilename as uintptr_t,
@@ -1095,7 +1076,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
let mut imported_cnt: libc::c_int = 0;
let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char;
let mut path_plus_name: *mut libc::c_char = 0 as *mut libc::c_char;
let mut name_c: *mut libc::c_char = 0 as *mut libc::c_char;
let mut set_default: libc::c_int;
let mut buf: *mut libc::c_char = 0 as *mut libc::c_char;
let mut buf_bytes: size_t = 0 as size_t;
@@ -1123,9 +1103,8 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
let entry = entry.unwrap();
free(suffix as *mut libc::c_void);
let name_f = entry.file_name();
free(name_c as *mut libc::c_void);
name_c = to_cstring(name_f.to_string_lossy());
suffix = dc_get_filesuffix_lc(name_c);
let name_c = to_cstring(name_f.to_string_lossy());
suffix = dc_get_filesuffix_lc(name_c.as_ptr());
if suffix.is_null()
|| strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0
{
@@ -1135,7 +1114,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
path_plus_name = dc_mprintf(
b"%s/%s\x00" as *const u8 as *const libc::c_char,
dir_name,
name_c,
name_c.as_ptr(),
);
info!(context, 0, "Checking: {}", as_str(path_plus_name));
free(buf as *mut libc::c_void);
@@ -1173,7 +1152,12 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
}
}
set_default = 1;
if !strstr(name_c, b"legacy\x00" as *const u8 as *const libc::c_char).is_null() {
if !strstr(
name_c.as_ptr(),
b"legacy\x00" as *const u8 as *const libc::c_char,
)
.is_null()
{
info!(
context,
0,
@@ -1198,7 +1182,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
}
}
free(name_c as *mut libc::c_void);
free(suffix as *mut libc::c_void);
free(path_plus_name as *mut libc::c_void);
free(buf as *mut libc::c_void);

View File

@@ -48,14 +48,14 @@ pub struct dc_job_t {
}
pub unsafe fn dc_perform_imap_jobs(context: &Context) {
info!(context, 0, "dc_perform_imap_jobs starting.",);
info!(context, 0, "INBOX-jobs started...",);
let probe_imap_network = *context.probe_imap_network.clone().read().unwrap();
*context.probe_imap_network.write().unwrap() = 0;
*context.perform_inbox_jobs_needed.write().unwrap() = 0;
dc_job_perform(context, 100, probe_imap_network);
info!(context, 0, "dc_perform_imap_jobs ended.",);
info!(context, 0, "INBOX-jobs ended.",);
}
unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: libc::c_int) {
@@ -80,42 +80,36 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
params_probe
};
let jobs: Result<Vec<dc_job_t>, _> = context.sql.query_map(
query,
params,
|row| {
let job = dc_job_t {
job_id: row.get(0)?,
action: row.get(1)?,
foreign_id: row.get(2)?,
desired_timestamp: row.get(5)?,
added_timestamp: row.get(4)?,
tries: row.get(6)?,
param: dc_param_new(),
try_again: 0,
pending_error: 0 as *mut libc::c_char,
};
let jobs: Vec<dc_job_t> = context
.sql
.query_map(
query,
params,
|row| {
let job = dc_job_t {
job_id: row.get(0)?,
action: row.get(1)?,
foreign_id: row.get(2)?,
desired_timestamp: row.get(5)?,
added_timestamp: row.get(4)?,
tries: row.get(6)?,
param: dc_param_new(),
try_again: 0,
pending_error: 0 as *mut libc::c_char,
};
let packed: String = row.get(3)?;
let packed_c = to_cstring(packed);
dc_param_set_packed(job.param, packed_c);
free(packed_c as *mut _);
Ok(job)
},
|jobs| {
let res = jobs
.collect::<Result<Vec<dc_job_t>, _>>()
.map_err(Into::into);
res
},
);
match jobs {
Ok(ref res) => {}
Err(ref err) => {
info!(context, 0, "query failed: {:?}", err);
}
}
for mut job in jobs.unwrap_or_default() {
let packed: String = row.get(3)?;
dc_param_set_packed(job.param, to_cstring(packed).as_ptr());
Ok(job)
},
|jobs| {
jobs.collect::<Result<Vec<dc_job_t>, _>>()
.map_err(Into::into)
},
)
.unwrap_or_default();
for mut job in jobs {
info!(
context,
0,
@@ -265,7 +259,6 @@ fn dc_job_update(context: &Context, job: &dc_job_t) -> bool {
job.job_id as i32,
],
)
.is_ok()
}
unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: libc::c_int) {
@@ -291,7 +284,7 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
let loginparam = dc_loginparam_read(context, &context.sql, "configured_");
let connected = context.smtp.lock().unwrap().connect(context, &loginparam);
if !connected {
if 0 == connected {
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
current_block = 14216916617354591294;
} else {
@@ -422,15 +415,12 @@ unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
match current_block {
2473556513754201174 => {
if dc_msg_load_from_db(msg, context, job.foreign_id) {
if context
.sql
.get_config_int(context, "folders_configured")
.unwrap_or_default()
< 3
{
if context.sql.get_config_int(context, "folders_configured", 0) < 3 {
inbox.configure_folders(context, 0x1i32);
}
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
let dest_folder = context
.sql
.get_config(context, "configured_mvbox_folder", None);
if let Some(dest_folder) = dest_folder {
let server_folder = as_str((*msg).server_folder);
@@ -522,15 +512,12 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context: &Context, job: &mut dc_
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
}
if 0 != dc_param_get_int(job.param, 'M' as i32, 0i32) {
if context
.sql
.get_config_int(context, "folders_configured")
.unwrap_or_default()
< 3
{
if context.sql.get_config_int(context, "folders_configured", 0) < 3 {
inbox.configure_folders(context, 0x1i32);
}
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
let dest_folder = context
.sql
.get_config(context, "configured_mvbox_folder", None);
if let Some(dest_folder) = dest_folder {
if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid)
as libc::c_uint
@@ -575,10 +562,7 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
}
_ => {
if 0 != dc_param_get_int((*msg).param, 'r' as i32, 0i32)
&& 0 != context
.sql
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1)
&& 0 != context.sql.get_config_int(context, "mdns_enabled", 1)
{
let folder =
CStr::from_ptr((*msg).server_folder).to_str().unwrap();
@@ -629,10 +613,7 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
}
_ => {
if 0 != dc_param_get_int((*msg).param, 'r' as i32, 0i32)
&& 0 != context
.sql
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1)
&& 0 != context.sql.get_config_int(context, "mdns_enabled", 1)
{
let folder =
CStr::from_ptr((*msg).server_folder).to_str().unwrap();
@@ -912,22 +893,17 @@ pub fn dc_job_kill_action(context: &Context, action: libc::c_int) -> bool {
"DELETE FROM jobs WHERE action=?;",
params![action],
)
.is_ok()
}
pub unsafe fn dc_perform_imap_fetch(context: &Context) {
let inbox = context.inbox.read().unwrap();
info!(context, 0, "dc_perform_imap_fetch got inbox");
let start = clock();
if 0 == connect_to_inbox(context, &inbox) {
return;
}
if context
.sql
.get_config_int(context, "inbox_watch")
.unwrap_or_else(|| 1)
== 0
{
if context.sql.get_config_int(context, "inbox_watch", 1) == 0 {
info!(context, 0, "INBOX-watch disabled.",);
return;
}
@@ -963,10 +939,7 @@ pub fn dc_perform_imap_idle(context: &Context) {
}
pub unsafe fn dc_perform_mvbox_fetch(context: &Context) {
let use_network = context
.sql
.get_config_int(context, "mvbox_watch")
.unwrap_or_else(|| 1);
let use_network = context.sql.get_config_int(context, "mvbox_watch", 1);
dc_jobthread_fetch(
context,
&mut context.mvbox_thread.clone().write().unwrap(),
@@ -975,10 +948,7 @@ pub unsafe fn dc_perform_mvbox_fetch(context: &Context) {
}
pub unsafe fn dc_perform_mvbox_idle(context: &Context) {
let use_network = context
.sql
.get_config_int(context, "mvbox_watch")
.unwrap_or_else(|| 1);
let use_network = context.sql.get_config_int(context, "mvbox_watch", 1);
dc_jobthread_idle(
context,
@@ -992,10 +962,7 @@ pub unsafe fn dc_interrupt_mvbox_idle(context: &Context) {
}
pub unsafe fn dc_perform_sentbox_fetch(context: &Context) {
let use_network = context
.sql
.get_config_int(context, "sentbox_watch")
.unwrap_or_else(|| 1);
let use_network = context.sql.get_config_int(context, "sentbox_watch", 1);
dc_jobthread_fetch(
context,
&mut context.sentbox_thread.clone().write().unwrap(),
@@ -1004,10 +971,7 @@ pub unsafe fn dc_perform_sentbox_fetch(context: &Context) {
}
pub unsafe fn dc_perform_sentbox_idle(context: &Context) {
let use_network = context
.sql
.get_config_int(context, "sentbox_watch")
.unwrap_or_else(|| 1);
let use_network = context.sql.get_config_int(context, "sentbox_watch", 1);
dc_jobthread_idle(
context,
&context.sentbox_thread.clone().read().unwrap(),

View File

@@ -136,18 +136,14 @@ unsafe fn connect_to_imap(context: &Context, jobthread: &dc_jobthread_t) -> libc
let mut ret_connected = dc_connect_to_configured_imap(context, &jobthread.imap);
if !(0 == ret_connected) {
if context
.sql
.get_config_int(context, "folders_configured")
.unwrap_or_default()
< 3
{
if context.sql.get_config_int(context, "folders_configured", 0) < 3 {
jobthread.imap.configure_folders(context, 0x1);
}
if let Some(mvbox_name) = context
.sql
.get_config(context, jobthread.folder_config_name)
if let Some(mvbox_name) =
context
.sql
.get_config(context, jobthread.folder_config_name, None)
{
jobthread.imap.set_watch_folder(mvbox_name);
} else {

View File

@@ -64,9 +64,7 @@ pub unsafe fn dc_send_locations_to_chat(
},
chat_id as i32,
],
)
.is_ok()
{
) {
if 0 != seconds && !is_sending_locations_before {
msg = dc_msg_new(context, 10i32);
(*msg).text = dc_stock_system_msg(
@@ -215,10 +213,8 @@ pub fn dc_get_locations(
if 0 != (*loc).msg_id {
let txt: String = row.get(9)?;
let txt_c = to_cstring(txt);
if 0 != is_marker(txt_c) {
(*loc).marker = txt_c;
} else {
free(txt_c as *mut _);
if 0 != is_marker(txt_c.as_ptr()) {
(*loc).marker = strdup(txt_c.as_ptr());
}
}
Ok(loc)
@@ -248,7 +244,7 @@ unsafe fn is_marker(txt: *const libc::c_char) -> libc::c_int {
}
pub fn dc_delete_all_locations(context: &Context) -> bool {
if sql::execute(context, &context.sql, "DELETE FROM locations;", params![]).is_err() {
if !sql::execute(context, &context.sql, "DELETE FROM locations;", params![]) {
return false;
}
context.call_cb(Event::LOCATION_CHANGED, 0, 0);
@@ -265,10 +261,13 @@ pub fn dc_get_location_kml(
let mut location_count: libc::c_int = 0;
let mut ret = String::new();
let self_addr = context
.sql
.get_config(context, "configured_addr")
.unwrap_or_default();
let self_addr = context.sql.get_config(context, "configured_addr", Some(""));
if self_addr.is_none() {
return std::ptr::null_mut();
}
let self_addr = self_addr.unwrap();
if let Ok((locations_send_begin, locations_send_until, locations_last_sent)) = context.sql.query_row(
"SELECT locations_send_begin, locations_send_until, locations_last_sent FROM chats WHERE id=?;",
@@ -332,9 +331,9 @@ pub fn dc_get_location_kml(
}
if 0 != success {
unsafe { to_cstring(ret) }
unsafe { strdup(to_cstring(ret).as_ptr()) }
} else {
std::ptr::null_mut()
0 as *mut libc::c_char
}
}
@@ -346,7 +345,7 @@ unsafe fn get_kml_timestamp(utc: i64) -> *mut libc::c_char {
let res = chrono::NaiveDateTime::from_timestamp(utc, 0)
.format("%Y-%m-%dT%H:%M:%SZ")
.to_string();
to_cstring(res)
strdup(to_cstring(res).as_ptr())
}
pub unsafe fn dc_get_message_kml(
@@ -387,7 +386,6 @@ pub fn dc_set_kml_sent_timestamp(context: &Context, chat_id: u32, timestamp: i64
"UPDATE chats SET locations_last_sent=? WHERE id=?;",
params![timestamp, chat_id as i32],
)
.is_ok()
}
pub fn dc_set_msg_location_id(context: &Context, msg_id: u32, location_id: u32) -> bool {
@@ -397,7 +395,6 @@ pub fn dc_set_msg_location_id(context: &Context, msg_id: u32, location_id: u32)
"UPDATE msgs SET location_id=? WHERE id=?;",
params![location_id, msg_id as i32],
)
.is_ok()
}
pub unsafe fn dc_save_locations(
@@ -663,7 +660,7 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: *mu
AND timestamp>? \
AND independent=0 \
ORDER BY timestamp;",
|mut stmt_locations, _| {
|mut stmt_locations| {
for (chat_id, locations_send_begin, locations_last_sent) in
rows.filter_map(|r| match r {
Ok(Some(v)) => Some(v),

View File

@@ -36,37 +36,37 @@ pub fn dc_loginparam_read(
let key = format!("{}addr", prefix);
let addr = sql
.get_config(context, key)
.get_config(context, key, None)
.unwrap_or_default()
.trim()
.to_string();
let key = format!("{}mail_server", prefix);
let mail_server = sql.get_config(context, key).unwrap_or_default();
let mail_server = sql.get_config(context, key, None).unwrap_or_default();
let key = format!("{}mail_port", prefix);
let mail_port = sql.get_config_int(context, key).unwrap_or_default();
let mail_port = sql.get_config_int(context, key, 0);
let key = format!("{}mail_user", prefix);
let mail_user = sql.get_config(context, key).unwrap_or_default();
let mail_user = sql.get_config(context, key, None).unwrap_or_default();
let key = format!("{}mail_pw", prefix);
let mail_pw = sql.get_config(context, key).unwrap_or_default();
let mail_pw = sql.get_config(context, key, None).unwrap_or_default();
let key = format!("{}send_server", prefix);
let send_server = sql.get_config(context, key).unwrap_or_default();
let send_server = sql.get_config(context, key, None).unwrap_or_default();
let key = format!("{}send_port", prefix);
let send_port = sql.get_config_int(context, key).unwrap_or_default();
let send_port = sql.get_config_int(context, key, 0);
let key = format!("{}send_user", prefix);
let send_user = sql.get_config(context, key).unwrap_or_default();
let send_user = sql.get_config(context, key, None).unwrap_or_default();
let key = format!("{}send_pw", prefix);
let send_pw = sql.get_config(context, key).unwrap_or_default();
let send_pw = sql.get_config(context, key, None).unwrap_or_default();
let key = format!("{}server_flags", prefix);
let server_flags = sql.get_config_int(context, key).unwrap_or_default();
let server_flags = sql.get_config_int(context, key, 0);
dc_loginparam_t {
addr: addr.to_string(),

View File

@@ -8,7 +8,7 @@ use mmime::mailmime_write_mem::*;
use mmime::mmapstring::*;
use mmime::other::*;
use crate::constants::*;
use crate::constants::DC_VERSION_STR;
use crate::context::Context;
use crate::dc_chat::*;
use crate::dc_contact::*;
@@ -161,20 +161,24 @@ pub unsafe fn dc_mimefactory_load_msg(
for row in rows {
let (authname, addr) = row?;
let addr_c = to_cstring(addr);
if clist_search_string_nocase((*factory).recipients_addr, addr_c) == 0 {
if clist_search_string_nocase(
(*factory).recipients_addr,
addr_c.as_ptr(),
) == 0
{
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
if !authname.is_empty() {
to_cstring(authname)
dc_strdup(to_cstring(authname).as_ptr())
} else {
std::ptr::null_mut()
0 as *mut libc::c_char
} as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
addr_c as *mut libc::c_void,
dc_strdup(addr_c.as_ptr()) as *mut libc::c_void,
);
}
}
@@ -193,7 +197,7 @@ pub unsafe fn dc_mimefactory_load_msg(
let email_to_remove = to_string(email_to_remove_c);
let self_addr = context
.sql
.get_config(context, "configured_addr")
.get_config(context, "configured_addr", Some(""))
.unwrap_or_default();
if !email_to_remove.is_empty() && email_to_remove != self_addr {
@@ -215,10 +219,7 @@ pub unsafe fn dc_mimefactory_load_msg(
}
if command != 6
&& command != 7
&& 0 != context
.sql
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1)
&& 0 != context.sql.get_config_int(context, "mdns_enabled", 1)
{
(*factory).req_mdn = 1
}
@@ -237,8 +238,8 @@ pub unsafe fn dc_mimefactory_load_msg(
);
match row {
Ok((in_reply_to, references)) => {
(*factory).in_reply_to = to_cstring(in_reply_to);
(*factory).references = to_cstring(references);
(*factory).in_reply_to = dc_strdup(to_cstring(in_reply_to).as_ptr());
(*factory).references = dc_strdup(to_cstring(references).as_ptr());
}
Err(err) => {
error!(
@@ -262,24 +263,32 @@ pub unsafe fn dc_mimefactory_load_msg(
unsafe fn load_from(mut factory: *mut dc_mimefactory_t) {
let context = (*factory).context;
(*factory).from_addr = to_cstring(
context
.sql
.get_config(context, "configured_addr")
.unwrap_or_default(),
(*factory).from_addr = strdup(
to_cstring(
context
.sql
.get_config(context, "configured_addr", None)
.unwrap_or_default(),
)
.as_ptr(),
);
(*factory).from_displayname = to_cstring(
context
.sql
.get_config(context, "displayname")
.unwrap_or_default(),
(*factory).from_displayname = strdup(
to_cstring(
context
.sql
.get_config(context, "displayname", None)
.unwrap_or_default(),
)
.as_ptr(),
);
(*factory).selfstatus = to_cstring(
context
.sql
.get_config(context, "selfstatus")
.unwrap_or_default(),
(*factory).selfstatus = strdup(
to_cstring(
context
.sql
.get_config(context, "selfstatus", None)
.unwrap_or_default(),
)
.as_ptr(),
);
if (*factory).selfstatus.is_null() {
(*factory).selfstatus = dc_stock_str((*factory).context, 13)
@@ -303,8 +312,7 @@ pub unsafe fn dc_mimefactory_load_mdn(
if 0 != (*factory)
.context
.sql
.get_config_int((*factory).context, "mdns_enabled")
.unwrap_or_else(|| 1)
.get_config_int((*factory).context, "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);
@@ -527,7 +535,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
let msg: *mut dc_msg_t = (*factory).msg;
let mut meta_part: *mut mailmime = 0 as *mut mailmime;
let mut placeholdertext: *mut libc::c_char = 0 as *mut libc::c_char;
if (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP as libc::c_int {
if (*chat).type_0 == 130 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -551,9 +559,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
}
/* build header etc. */
let command: libc::c_int = dc_param_get_int((*msg).param, 'S' as i32, 0);
if (*chat).type_0 == DC_CHAT_TYPE_GROUP as libc::c_int
|| (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP as libc::c_int
{
if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -740,7 +746,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
}
if !grpimage.is_null() {
let mut meta: *mut dc_msg_t = dc_msg_new_untyped((*factory).context);
(*meta).type_0 = DC_MSG_IMAGE as libc::c_int;
(*meta).type_0 = 20;
dc_param_set((*meta).param, 'f' as i32, grpimage);
let mut filename_as_sent: *mut libc::c_char = 0 as *mut libc::c_char;
meta_part = build_body_file(
@@ -759,11 +765,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
}
dc_msg_unref(meta);
}
if (*msg).type_0 == DC_MSG_VOICE as libc::c_int
|| (*msg).type_0 == DC_MSG_AUDIO as libc::c_int
|| (*msg).type_0 == DC_MSG_VIDEO as libc::c_int
{
if (*msg).type_0 == DC_MSG_VOICE as libc::c_int {
if (*msg).type_0 == 41 || (*msg).type_0 == 40 || (*msg).type_0 == 50 {
if (*msg).type_0 == 41 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -838,12 +841,12 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
free(fwdhint as *mut libc::c_void);
free(placeholdertext as *mut libc::c_void);
/* add attachment part */
if (*msg).type_0 == DC_MSG_IMAGE as libc::c_int
|| (*msg).type_0 == DC_MSG_GIF as libc::c_int
|| (*msg).type_0 == DC_MSG_AUDIO as libc::c_int
|| (*msg).type_0 == DC_MSG_VOICE as libc::c_int
|| (*msg).type_0 == DC_MSG_VIDEO as libc::c_int
|| (*msg).type_0 == DC_MSG_FILE as libc::c_int
if (*msg).type_0 == 20
|| (*msg).type_0 == 21
|| (*msg).type_0 == 40
|| (*msg).type_0 == 41
|| (*msg).type_0 == 50
|| (*msg).type_0 == 60
{
if 0 == is_file_size_okay(msg) {
let error: *mut libc::c_char = dc_mprintf(
@@ -1096,9 +1099,7 @@ unsafe fn get_subject(
};
if dc_param_get_int((*msg).param, 'S' as i32, 0) == 6 {
ret = dc_stock_str(context, 42)
} else if (*chat).type_0 == DC_CHAT_TYPE_GROUP as libc::c_int
|| (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP as libc::c_int
{
} else if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
ret = dc_mprintf(
b"Chat: %s: %s%s\x00" as *const u8 as *const libc::c_char,
(*chat).name,
@@ -1162,7 +1163,7 @@ unsafe fn build_body_file(
let mut filename_to_send: *mut libc::c_char = 0 as *mut libc::c_char;
let mut filename_encoded: *mut libc::c_char = 0 as *mut libc::c_char;
if !pathNfilename.is_null() {
if (*msg).type_0 == DC_MSG_VOICE as libc::c_int {
if (*msg).type_0 == 41 {
let ts = chrono::Utc.timestamp((*msg).timestamp_sort as i64, 0);
let suffix = if !suffix.is_null() {
@@ -1173,12 +1174,10 @@ unsafe fn build_body_file(
let res = ts
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
.to_string();
filename_to_send = to_cstring(res);
} else if (*msg).type_0 == DC_MSG_AUDIO as libc::c_int {
filename_to_send = strdup(to_cstring(res).as_ptr());
} else if (*msg).type_0 == 40 {
filename_to_send = dc_get_filename(pathNfilename)
} else if (*msg).type_0 == DC_MSG_IMAGE as libc::c_int
|| (*msg).type_0 == DC_MSG_GIF as libc::c_int
{
} else if (*msg).type_0 == 20 || (*msg).type_0 == 21 {
if base_name.is_null() {
base_name = b"image\x00" as *const u8 as *const libc::c_char
}
@@ -1191,7 +1190,7 @@ unsafe fn build_body_file(
b"dat\x00" as *const u8 as *const libc::c_char
},
)
} else if (*msg).type_0 == DC_MSG_VIDEO as libc::c_int {
} else if (*msg).type_0 == 50 {
filename_to_send = dc_mprintf(
b"video.%s\x00" as *const u8 as *const libc::c_char,
if !suffix.is_null() {

View File

@@ -1,5 +1,5 @@
use std::collections::{HashMap, HashSet};
use std::ffi::CStr;
use std::ffi::{CStr, CString};
use charset::Charset;
use mmime::mailimf::*;
@@ -833,7 +833,6 @@ unsafe fn hash_header(
18 => key = b"References\x00" as *const u8 as *const libc::c_char,
19 => key = b"Subject\x00" as *const u8 as *const libc::c_char,
22 => {
// MAILIMF_FIELD_OPTIONAL_FIELD
let optional_field: *const mailimf_optional_field =
(*field).fld_data.fld_optional_field;
if !optional_field.is_null() {
@@ -843,16 +842,17 @@ unsafe fn hash_header(
_ => {}
}
if !key.is_null() {
// XXX the optional field sometimes contains invalid UTF8
// which should not happen (according to the mime standard).
// This might point to a bug in our mime parsing/processing
// logic. As mmime/dc_mimeparser is scheduled fore replacement
// anyway we just use a lossy conversion.
let key_r = &to_string_lossy(key);
if !out.contains_key(key_r) || // key already exists, only overwrite known types (protected headers)
(*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as i32 || key_r.starts_with("Chat-")
{
out.insert(key_r.to_string(), field);
let key_len: libc::c_int = strlen(key) as libc::c_int;
if out.contains_key(as_str(key)) {
if (*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int
|| key_len > 5i32
&& strncasecmp(key, b"Chat-\x00" as *const u8 as *const libc::c_char, 5)
== 0i32
{
out.insert(to_string(key), field);
}
} else {
out.insert(to_string(key), field);
}
}
cur1 = if !cur1.is_null() {
@@ -1204,7 +1204,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
current_block = 8795901732489102124;
} else {
decoded_data_bytes = res.len();
decoded_data = res.as_ptr() as *const libc::c_char;
let res_c = CString::new(res.as_bytes()).unwrap();
decoded_data = strdup(res_c.as_ptr());
current_block = 17788412896529399552;
}
} else {
@@ -1340,9 +1341,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
}
if !filename_parts.is_empty() {
free(desired_filename as *mut libc::c_void);
let parts_c = to_cstring(filename_parts);
desired_filename = dc_decode_ext_header(parts_c);
free(parts_c as *mut _);
desired_filename =
dc_decode_ext_header(to_cstring(filename_parts).as_ptr());
}
if desired_filename.is_null() {
let param = mailmime_find_ct_parameter(
@@ -1440,7 +1440,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
}
}
}
/* add object? (we do not add all objects, eg. signatures etc. are ignored) */
/* add object? (we do not add all objetcs, eg. signatures etc. are ignored) */
dc_simplify_unref(simplifier);
if !transfer_decoding_buffer.is_null() {
mmap_string_unref(transfer_decoding_buffer);

View File

@@ -4,12 +4,7 @@ use crate::dc_job::*;
use crate::dc_msg::*;
pub unsafe fn dc_do_heuristics_moves(context: &Context, folder: &str, msg_id: u32) {
if context
.sql
.get_config_int(context, "mvbox_move")
.unwrap_or_else(|| 1)
== 0
{
if context.sql.get_config_int(context, "mvbox_move", 1) == 0 {
return;
}

View File

@@ -63,7 +63,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
ret += &format!("Cannot load message #{}.", msg_id as usize);
dc_msg_unref(msg);
dc_contact_unref(contact_from);
return to_cstring(ret);
return strdup(to_cstring(ret).as_ptr());
}
let rawtxt = rawtxt.unwrap();
let rawtxt = dc_truncate_str(rawtxt.trim(), 100000);
@@ -91,7 +91,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
// device-internal message, no further details needed
dc_msg_unref(msg);
dc_contact_unref(contact_from);
return to_cstring(ret);
return strdup(to_cstring(ret).as_ptr());
}
context
@@ -209,7 +209,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
dc_msg_unref(msg);
dc_contact_unref(contact_from);
to_cstring(ret)
strdup(to_cstring(ret).as_ptr())
}
pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a> {
@@ -224,8 +224,8 @@ pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a>
* If you want an update, you have to recreate the object.
*/
// to check if a mail was sent, use dc_msg_is_sent()
// approx. max. length returned by dc_msg_get_text()
// approx. max. length returned by dc_get_msg_info()
// approx. max. lenght returned by dc_msg_get_text()
// approx. max. lenght returned by dc_get_msg_info()
pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: libc::c_int) -> *mut dc_msg_t<'a> {
let mut msg: *mut dc_msg_t;
msg = calloc(1, ::std::mem::size_of::<dc_msg_t>()) as *mut dc_msg_t;
@@ -445,12 +445,9 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
dc_msg_empty(msg);
(*msg).id = row.get::<_, i32>(0)? as u32;
(*msg).rfc724_mid = to_cstring(row.get::<_, String>(1)?);
(*msg).in_reply_to = match row.get::<_, Option<String>>(2)? {
Some(s) => to_cstring(s),
None => std::ptr::null_mut(),
};
(*msg).server_folder = to_cstring(row.get::<_, String>(3)?);
(*msg).rfc724_mid = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
(*msg).in_reply_to = dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
(*msg).server_folder = dc_strdup(to_cstring(row.get::<_, String>(3)?).as_ptr());
(*msg).server_uid = row.get(4)?;
(*msg).move_state = row.get(5)?;
(*msg).chat_id = row.get(6)?;
@@ -462,15 +459,15 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
(*msg).type_0 = row.get(12)?;
(*msg).state = row.get(13)?;
(*msg).is_dc_message = row.get(14)?;
(*msg).text = to_cstring(row.get::<_, String>(15).unwrap_or_default());
(*msg).text = dc_strdup(to_cstring(row.get::<_, String>(15).unwrap_or_default()).as_ptr());
dc_param_set_packed(
(*msg).param,
to_cstring(row.get::<_, String>(16)?)
to_cstring(row.get::<_, String>(16)?).as_ptr()
);
(*msg).starred = row.get(17)?;
(*msg).hidden = row.get(18)?;
(*msg).location_id = row.get(19)?;
(*msg).chat_blocked = row.get::<_, Option<i32>>(20)?.unwrap_or_default();
(*msg).chat_blocked = row.get(20)?;
if (*msg).chat_blocked == 2 {
dc_truncate_n_unwrap_str((*msg).text, 256, 0);
}
@@ -481,7 +478,10 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
match res {
Ok(_) => true,
Err(err) => false,
Err(err) => {
error!(context, 0, "msg: load from db failed: {:?}", err);
false
}
}
}
@@ -494,10 +494,7 @@ pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: uint32_t) -> *mut l
);
if let Some(headers) = headers {
let h = to_cstring(headers);
let res = dc_strdup_keep_null(h);
free(h as *mut _);
res
dc_strdup_keep_null(to_cstring(headers).as_ptr())
} else {
std::ptr::null_mut()
}
@@ -534,55 +531,52 @@ pub fn dc_update_msg_chat_id(context: &Context, msg_id: u32, chat_id: u32) -> bo
"UPDATE msgs SET chat_id=? WHERE id=?;",
params![chat_id as i32, msg_id as i32],
)
.is_ok()
}
pub fn dc_markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize) -> bool {
if msg_ids.is_null() || msg_cnt <= 0 {
return false;
}
let msgs = context.sql.prepare(
context.sql.prepare(
"SELECT m.state, c.blocked FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id WHERE m.id=? AND m.chat_id>9",
|mut stmt, _| {
let mut res = Vec::with_capacity(msg_cnt);
|mut stmt| {
let mut send_event = false;
for i in 0..msg_cnt {
// TODO: do I need to reset?
let id = unsafe { *msg_ids.offset(i as isize) };
let (state, blocked) = stmt.query_row(params![id as i32], |row| {
Ok((row.get::<_, i32>(0)?, row.get::<_, Option<i32>>(1)?.unwrap_or_default()))
})?;
res.push((id, state, blocked));
if let Ok((curr_state, curr_blocked)) = stmt
.query_row(params![id as i32], |row| {
Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?))
})
{
if curr_blocked == 0 {
if curr_state == 10 || curr_state == 13 {
dc_update_msg_state(context, id, 16);
info!(context, 0, "Seen message #{}.", id);
unsafe { dc_job_add(
context,
130,
id as i32,
0 as *const libc::c_char,
0,
) };
send_event = true;
}
} else if curr_state == 10 {
dc_update_msg_state(context, id, 13);
send_event = true;
}
}
}
Ok(res)
}
);
if msgs.is_err() {
warn!(context, 0, "markseen_msgs failed: {:?}", msgs);
return false;
}
let mut send_event = false;
let msgs = msgs.unwrap();
for (id, curr_state, curr_blocked) in msgs.into_iter() {
if curr_blocked == 0 {
if curr_state == 10 || curr_state == 13 {
dc_update_msg_state(context, id, 16);
info!(context, 0, "Seen message #{}.", id);
unsafe { dc_job_add(context, 130, id as i32, 0 as *const libc::c_char, 0) };
send_event = true;
if send_event {
context.call_cb(Event::MSGS_CHANGED, 0, 0);
}
} else if curr_state == 10 {
dc_update_msg_state(context, id, 13);
send_event = true;
Ok(())
}
}
if send_event {
context.call_cb(Event::MSGS_CHANGED, 0, 0);
}
true
).is_ok()
}
pub fn dc_update_msg_state(context: &Context, msg_id: uint32_t, state: libc::c_int) -> bool {
@@ -592,7 +586,6 @@ pub fn dc_update_msg_state(context: &Context, msg_id: uint32_t, state: libc::c_i
"UPDATE msgs SET state=? WHERE id=?;",
params![state, msg_id as i32],
)
.is_ok()
}
pub fn dc_star_msgs(
@@ -606,7 +599,7 @@ pub fn dc_star_msgs(
}
context
.sql
.prepare("UPDATE msgs SET starred=? WHERE id=?;", |mut stmt, _| {
.prepare("UPDATE msgs SET starred=? WHERE id=?;", |mut stmt| {
for i in 0..msg_cnt {
stmt.execute(params![star, unsafe { *msg_ids.offset(i as isize) as i32 }])?;
}
@@ -694,7 +687,7 @@ pub unsafe fn dc_msg_get_text(msg: *const dc_msg_t) -> *mut libc::c_char {
}
let res = dc_truncate_str(as_str((*msg).text), 30000);
to_cstring(res)
dc_strdup(to_cstring(res).as_ptr())
}
pub unsafe fn dc_msg_get_filename(msg: *const dc_msg_t) -> *mut libc::c_char {
@@ -1098,7 +1091,6 @@ pub unsafe fn dc_msg_save_param_to_disk(msg: *mut dc_msg_t) -> bool {
"UPDATE msgs SET param=? WHERE id=?;",
params![as_str((*(*msg).param).packed), (*msg).id as i32],
)
.is_ok()
}
pub unsafe fn dc_msg_new_load<'a>(context: &'a Context, msg_id: uint32_t) -> *mut dc_msg_t<'a> {
@@ -1167,7 +1159,6 @@ pub fn dc_update_msg_move_state(
"UPDATE msgs SET move_state=? WHERE rfc724_mid=?;",
params![state as i32, as_str(rfc724_mid)],
)
.is_ok()
}
pub unsafe fn dc_set_msg_failed(context: &Context, msg_id: uint32_t, error: *const libc::c_char) {
@@ -1187,9 +1178,7 @@ pub unsafe fn dc_set_msg_failed(context: &Context, msg_id: uint32_t, error: *con
&context.sql,
"UPDATE msgs SET state=?, param=? WHERE id=?;",
params![(*msg).state, as_str((*(*msg).param).packed), msg_id as i32],
)
.is_ok()
{
) {
context.call_cb(
Event::MSG_FAILED,
(*msg).chat_id as uintptr_t,
@@ -1360,7 +1349,9 @@ pub fn dc_rfc724_mid_exists(
&[as_str(rfc724_mid)],
|row| {
if !ret_server_folder.is_null() {
unsafe { *ret_server_folder = to_cstring(row.get::<_, String>(0)?) };
unsafe {
*ret_server_folder = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr())
};
}
if !ret_server_uid.is_null() {
unsafe { *ret_server_uid = row.get(1)? };

View File

@@ -18,7 +18,7 @@ pub const DC_PARAM_GUARANTEE_E2EE: char = 'c';
pub const DC_PARAM_ERRONEOUS_E2EE: char = 'e';
/// for msgs: force unencrypted message, either DC_FP_ADD_AUTOCRYPT_HEADER (1), DC_FP_NO_AUTOCRYPT_HEADER (2) or 0
pub const DC_PARAM_FORCE_PLAINTEXT: char = 'u';
/// for msgs: an incoming message which requests a MDN (aka read receipt)
/// for msgs: an incoming message which requestes a MDN (aka read receipt)
pub const DC_PARAM_WANTS_MDN: char = 'r';
/// for msgs
pub const DC_PARAM_FORWARDED: char = 'a';
@@ -60,10 +60,10 @@ pub const DC_PARAM_SELFTALK: char = 'K';
pub const DC_FP_ADD_AUTOCRYPT_HEADER: u8 = 1;
pub const DC_FP_NO_AUTOCRYPT_HEADER: u8 = 2;
/// An object for handling key=value parameter lists; for the key, currently only
/// An object for handling key=value parameter lists; for the key, curently only
/// a single character is allowed.
///
/// The object is used eg. by Chat or dc_msg_t, for readable parameter names,
/// The object is used eg. by Chat or dc_msg_t, for readable paramter names,
/// these classes define some DC_PARAM_* constantats.
///
/// Only for library-internal use.

View File

@@ -188,7 +188,7 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
match current_block {
16562876845594826114 => {}
_ => {
/* check the parameters
/* check the paramters
---------------------- */
if !addr.is_null() {
/* urldecoding is needed at least for OPENPGP4FPR but should not hurt in the other cases */
@@ -239,8 +239,13 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
if addr.is_null() || invitenumber.is_null() || auth.is_null() {
if let Some(peerstate) = peerstate {
(*qr_parsed).state = 210i32;
let addr_ptr = if let Some(ref addr) = peerstate.addr {
to_cstring(addr)
let c_addr = peerstate
.addr
.as_ref()
.map(to_cstring)
.unwrap_or_default();
let addr_ptr = if peerstate.addr.is_some() {
c_addr.as_ptr()
} else {
std::ptr::null()
};
@@ -251,7 +256,6 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
0x80i32,
0 as *mut libc::c_int,
);
free(addr_ptr as *mut _);
dc_create_or_lookup_nchat_by_contact_id(
context,
(*qr_parsed).id,

View File

@@ -216,12 +216,10 @@ pub unsafe fn dc_receive_imf(
by checking the state before the message body is downloaded */
let mut allow_creation: libc::c_int = 1;
if msgrmsg == 0 {
let show_emails = context
.sql
.get_config_int(context, "show_emails")
.unwrap_or_default();
let show_emails: libc::c_int =
context.sql.get_config_int(context, "show_emails", 0);
if show_emails == 0 {
chat_id = 3;
chat_id = 3 as uint32_t;
allow_creation = 0
} else if show_emails == 1 {
allow_creation = 0
@@ -405,10 +403,8 @@ pub unsafe fn dc_receive_imf(
dc_unarchive_chat(context, chat_id);
// if the mime-headers should be saved, find out its size
// (the mime-header ends with an empty line)
let save_mime_headers = context
.sql
.get_config_int(context, "save_mime_headers")
.unwrap_or_default();
let save_mime_headers =
context.sql.get_config_int(context, "save_mime_headers", 0);
field = dc_mimeparser_lookup_field(&mime_parser, "In-Reply-To");
if !field.is_null()
&& (*field).fld_type == MAILIMF_FIELD_IN_REPLY_TO as libc::c_int
@@ -443,7 +439,7 @@ pub unsafe fn dc_receive_imf(
timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \
bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \
VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);",
|mut stmt, conn| {
|mut stmt| {
let mut i = 0;
loop {
if !(i < icnt) {
@@ -503,21 +499,16 @@ pub unsafe fn dc_receive_imf(
} else {
""
},
// txt_raw might contain invalid utf8
if !txt_raw.is_null() {
to_string_lossy(txt_raw)
as_str(txt_raw)
} else {
String::new()
""
},
as_str((*(*part).param).packed),
(*part).bytes,
hidden,
if 0 != save_mime_headers {
let body_string = unsafe {
std::str::from_utf8(std::slice::from_raw_parts(imf_raw_not_terminated as *const u8, imf_raw_bytes)).unwrap()
};
Some(body_string)
Some(to_string(imf_raw_not_terminated))
} else {
None
},
@@ -533,9 +524,9 @@ pub unsafe fn dc_receive_imf(
} else {
free(txt_raw as *mut libc::c_void);
txt_raw = 0 as *mut libc::c_char;
insert_msg_id = sql::get_rowid_with_conn(
insert_msg_id = sql::get_rowid(
context,
conn,
&context.sql,
"msgs",
"rfc724_mid",
as_str(rfc724_mid),
@@ -590,10 +581,7 @@ pub unsafe fn dc_receive_imf(
16282941964262048061 => {}
_ => {
if carray_count(mime_parser.reports) > 0 as libc::c_uint {
let mdns_enabled = context
.sql
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1);
let mdns_enabled = context.sql.get_config_int(context, "mdns_enabled", 1);
icnt = carray_count(mime_parser.reports) as size_t;
i = 0 as size_t;
while i < icnt {
@@ -744,15 +732,14 @@ pub unsafe fn dc_receive_imf(
}
if 0 != mime_parser.is_send_by_messenger || 0 != mdn_consumed {
let param = dc_param_new();
let server_folder_c = to_cstring(server_folder.as_ref());
dc_param_set(param, 'Z' as i32, server_folder_c);
free(server_folder_c as *mut _);
dc_param_set(
param,
'Z' as i32,
to_cstring(server_folder.as_ref()).as_ptr(),
);
dc_param_set_int(param, 'z' as i32, server_uid as i32);
if 0 != mime_parser.is_send_by_messenger
&& 0 != context
.sql
.get_config_int(context, "mvbox_move")
.unwrap_or_else(|| 1)
&& 0 != context.sql.get_config_int(context, "mvbox_move", 1)
{
dc_param_set_int(param, 'M' as i32, 1);
}
@@ -830,14 +817,6 @@ pub unsafe fn dc_receive_imf(
}
}
info!(
context,
0,
"received message {} has Message-Id: {}",
server_uid,
to_string(rfc724_mid)
);
free(rfc724_mid as *mut libc::c_void);
free(mime_in_reply_to as *mut libc::c_void);
free(mime_references as *mut libc::c_void);
@@ -895,7 +874,7 @@ unsafe fn calc_timestamps(
}
/* the function tries extracts the group-id from the message and returns the
corresponding chat_id. If the chat_id is not existent, it is created.
corresponding chat_id. If the chat_id is not existant, it is created.
If the message contains groups commands (name, profile image, changed members),
they are executed as well.
@@ -1123,7 +1102,7 @@ unsafe fn create_or_lookup_group(
group_explicitly_left = dc_is_group_explicitly_left(context, grpid);
let self_addr = context
.sql
.get_config(context, "configured_addr")
.get_config(context, "configured_addr", Some(""))
.unwrap_or_default();
if chat_id == 0 as libc::c_uint
&& 0 == dc_mimeparser_is_mailinglist_message(mime_parser)
@@ -1197,9 +1176,7 @@ unsafe fn create_or_lookup_group(
&context.sql,
"UPDATE chats SET name=? WHERE id=?;",
params![as_str(grpname), chat_id as i32],
)
.is_ok()
{
) {
context.call_cb(Event::CHAT_MODIFIED, chat_id as uintptr_t, 0);
}
}
@@ -1386,7 +1363,7 @@ unsafe fn create_or_lookup_adhoc_group(
),
params![],
|row| {
Ok((row.get::<_, i32>(0)?, row.get::<_, Option<i32>>(1)?.unwrap_or_default()))
Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?))
}
);
@@ -1408,7 +1385,7 @@ unsafe fn create_or_lookup_adhoc_group(
/* we do not check if the message is a reply to another group, this may result in
chats with unclear member list. instead we create a new group in the following lines ... */
/* create a new ad-hoc group
- there is no need to check if this group exists; otherwise we would have caught it above */
- there is no need to check if this group exists; otherwise we would have catched it above */
grpid = create_adhoc_grp_id(context, member_ids);
if !grpid.is_null() {
if !mime_parser.subject.is_null()
@@ -1466,7 +1443,7 @@ fn create_group_record(
create_blocked: libc::c_int,
create_verified: libc::c_int,
) -> u32 {
if sql::execute(
if !sql::execute(
context,
&context.sql,
"INSERT INTO chats (type, name, grpid, blocked) VALUES(?, ?, ?, ?);",
@@ -1476,9 +1453,7 @@ fn create_group_record(
as_str(grpid),
create_blocked,
],
)
.is_err()
{
) {
return 0;
}
@@ -1488,15 +1463,15 @@ fn create_group_record(
unsafe fn create_adhoc_grp_id(context: &Context, member_ids: *mut dc_array_t) -> *mut libc::c_char {
/* algorithm:
- sort normalized, lowercased, e-mail addresses alphabetically
- put all e-mail addresses into a single string, separate the address by a single comma
- put all e-mail addresses into a single string, separate the addresss by a single comma
- sha-256 this string (without possibly terminating null-characters)
- encode the first 64 bits of the sha-256 output as lowercase hex (results in 16 characters from the set [0-9a-f])
*/
let member_ids_str = dc_array_get_string(member_ids, b",\x00" as *const u8 as *const _);
let member_cs = context
.sql
.get_config(context, "configured_addr")
.unwrap_or_else(|| "no-self".to_string())
.get_config(context, "configured_addr", Some("no-self"))
.unwrap()
.to_lowercase();
let members = context
@@ -1529,7 +1504,9 @@ fn hex_hash(s: impl AsRef<str>) -> *const libc::c_char {
let bytes = s.as_ref().as_bytes();
let result = Sha256::digest(bytes);
let result_hex = hex::encode(&result[..8]);
unsafe { to_cstring(result_hex) as *const _ }
let result_cstring = to_cstring(result_hex);
unsafe { strdup(result_cstring.as_ptr()) }
}
unsafe fn search_chat_ids_by_contact_ids(
@@ -1613,7 +1590,8 @@ unsafe fn check_verified_properties(
let contact = dc_contact_new(context);
let verify_fail = |reason: String| {
*failure_reason = to_cstring(format!("{}. See \"Info\" for details.", reason));
*failure_reason =
strdup(to_cstring(format!("{}. See \"Info\" for details.", reason)).as_ptr());
warn!(context, 0, "{}", reason);
};
@@ -1659,61 +1637,68 @@ unsafe fn check_verified_properties(
let to_ids_str = to_string(to_ids_str_c);
free(to_ids_str_c as *mut libc::c_void);
let rows = context.sql.query_map(
format!(
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN({}) ",
&to_ids_str,
),
params![],
|row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?)),
|rows| rows.collect::<Result<Vec<_>, _>>().map_err(Into::into),
);
let ok = context
.sql
.query_map(
format!(
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN({}) ",
&to_ids_str,
),
params![],
|row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?)),
|rows| {
for row in rows {
let (to_addr, mut is_verified) = row?;
let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr);
if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr)
&& peerstate.is_some()
{
let peerstate = peerstate.as_mut().unwrap();
if rows.is_err() {
cleanup();
return 0;
}
for (to_addr, mut is_verified) in rows.unwrap().into_iter() {
let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr);
if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr) && peerstate.is_some() {
let peerstate = peerstate.as_mut().unwrap();
// if we're here, we know the gossip key is verified:
// - use the gossip-key as verified-key if there is no verified-key
// - OR if the verified-key does not match public-key or gossip-key
// (otherwise a verified key can _only_ be updated through QR scan which might be annoying,
// see https://github.com/nextleap-project/countermitm/issues/46 for a discussion about this point)
if 0 == is_verified
|| peerstate.verified_key_fingerprint != peerstate.public_key_fingerprint
&& peerstate.verified_key_fingerprint != peerstate.gossip_key_fingerprint
{
info!(
context,
0,
"{} has verfied {}.",
as_str((*contact).addr),
to_addr,
);
let fp = peerstate.gossip_key_fingerprint.clone();
if let Some(fp) = fp {
peerstate.set_verified(0, &fp, 2);
peerstate.save_to_db(&context.sql, false);
is_verified = 1;
// if we're here, we know the gossip key is verified:
// - use the gossip-key as verified-key if there is no verified-key
// - OR if the verified-key does not match public-key or gossip-key
// (otherwise a verified key can _only_ be updated through QR scan which might be annoying,
// see https://github.com/nextleap-project/countermitm/issues/46 for a discussion about this point)
if 0 == is_verified
|| peerstate.verified_key_fingerprint
!= peerstate.public_key_fingerprint
&& peerstate.verified_key_fingerprint
!= peerstate.gossip_key_fingerprint
{
info!(
context,
0,
"{} has verfied {}.",
as_str((*contact).addr),
to_addr,
);
let fp = peerstate.gossip_key_fingerprint.clone();
if let Some(fp) = fp {
peerstate.set_verified(0, &fp, 2);
peerstate.save_to_db(&context.sql, false);
is_verified = 1;
}
}
}
if 0 == is_verified {
verify_fail(format!(
"{} is not a member of this verified group",
to_addr
));
cleanup();
return Err(failure::format_err!("not a valid memember").into());
}
}
}
}
if 0 == is_verified {
verify_fail(format!(
"{} is not a member of this verified group",
to_addr
));
cleanup();
return 0;
}
}
Ok(())
},
)
.is_ok(); // TODO: Better default
1
cleanup();
ok as libc::c_int
}
unsafe fn set_better_msg(mime_parser: &dc_mimeparser_t, better_msg: *mut *mut libc::c_char) {
@@ -1993,8 +1978,8 @@ unsafe fn add_or_lookup_contact_by_addr(
*check_self = 0;
let self_addr = context
.sql
.get_config(context, "configured_addr")
.unwrap_or_default();
.get_config(context, "configured_addr", Some(""))
.unwrap();
if dc_addr_cmp(self_addr, as_str(addr_spec)) {
*check_self = 1;

View File

@@ -51,7 +51,7 @@ pub unsafe fn dc_get_securejoin_qr(
auth = dc_create_id();
dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth);
}
let self_addr = context.sql.get_config(context, "configured_addr");
let self_addr = context.sql.get_config(context, "configured_addr", None);
let cleanup = |fingerprint, chat, group_name, group_name_urlencoded| {
free(fingerprint as *mut libc::c_void);
@@ -62,7 +62,7 @@ pub unsafe fn dc_get_securejoin_qr(
free(group_name_urlencoded as *mut libc::c_void);
if let Some(qr) = qr {
to_cstring(qr)
strdup(to_cstring(qr).as_ptr())
} else {
std::ptr::null_mut()
}
@@ -76,9 +76,8 @@ pub unsafe fn dc_get_securejoin_qr(
let self_addr = self_addr.unwrap();
let self_name = context
.sql
.get_config(context, "displayname")
.unwrap_or_default();
.get_config(context, "displayname", Some(""))
.unwrap();
fingerprint = get_self_fingerprint(context);
if fingerprint.is_null() {
@@ -127,7 +126,7 @@ pub unsafe fn dc_get_securejoin_qr(
}
fn get_self_fingerprint(context: &Context) -> *mut libc::c_char {
if let Some(self_addr) = context.sql.get_config(context, "configured_addr") {
if let Some(self_addr) = context.sql.get_config(context, "configured_addr", None) {
if let Some(key) = Key::from_self_public(context, self_addr, &context.sql) {
return key.fingerprint_c();
}
@@ -939,15 +938,15 @@ pub unsafe fn dc_handle_degrade_event(context: &Context, peerstate: &Peerstate)
&mut contact_chat_id,
0 as *mut libc::c_int,
);
let c_addr_ptr = if let Some(ref addr) = peerstate.addr {
to_cstring(addr)
let c_addr = peerstate.addr.as_ref().map(to_cstring).unwrap_or_default();
let c_addr_ptr = if peerstate.addr.is_some() {
c_addr.as_ptr()
} else {
std::ptr::null_mut()
};
let msg = dc_stock_str_repl_string(context, 37, c_addr_ptr);
dc_add_device_msg(context, contact_chat_id, msg);
free(msg as *mut libc::c_void);
free(c_addr_ptr as *mut _);
context.call_cb(
Event::CHAT_MODIFIED,
contact_chat_id as uintptr_t,

View File

@@ -225,8 +225,7 @@ unsafe fn dc_simplify_simplify_plain_text(
pending_linebreaks -= 1
}
}
// the incoming message might contain invalid UTF8
ret += &to_string_lossy(line);
ret += &to_string(line);
content_lines_added += 1;
pending_linebreaks = 1i32
}
@@ -239,7 +238,7 @@ unsafe fn dc_simplify_simplify_plain_text(
}
dc_free_splitted_lines(lines);
to_cstring(ret)
strdup(to_cstring(ret).as_ptr())
}
/**
@@ -262,7 +261,7 @@ unsafe fn is_quoted_headline(buf: *const libc::c_char) -> bool {
/* This function may be called for the line _directly_ before a quote.
The function checks if the line contains sth. like "On 01.02.2016, xy@z wrote:" in various languages.
- Currently, we simply check if the last character is a ':'.
- Checking for the existence of an email address may fail (headlines may show the user's name instead of the address) */
- Checking for the existance of an email address may fail (headlines may show the user's name instead of the address) */
let buf_len: libc::c_int = strlen(buf) as libc::c_int;
if buf_len > 80i32 {
return false;

View File

@@ -1,4 +1,4 @@
use std::ffi::CStr;
use std::ffi::{CStr, CString};
use charset::Charset;
use mmime::mailmime_decode::*;
@@ -689,9 +689,10 @@ pub unsafe fn dc_decode_ext_header(to_decode: *const libc::c_char) -> *mut libc:
std::slice::from_raw_parts(decoded as *const u8, strlen(decoded));
let (res, _, _) = encoding.decode(data);
free(decoded as *mut _);
let r = std::ffi::CString::new(res.as_bytes()).unwrap();
decoded = dc_strdup(r.as_ptr());
free(decoded as *mut libc::c_void);
let res_c = CString::new(res.as_bytes()).unwrap();
decoded = strdup(res_c.as_ptr());
}
}
}
@@ -711,8 +712,7 @@ unsafe fn print_hex(target: *mut libc::c_char, cur: *const libc::c_char) {
let bytes = std::slice::from_raw_parts(cur as *const _, strlen(cur));
let raw = to_cstring(format!("={}", &hex::encode_upper(bytes)[..2]));
libc::memcpy(target as *mut _, raw as *const _, 4);
free(raw as *mut libc::c_void);
libc::memcpy(target as *mut _, raw.as_ptr() as *const _, 4);
}
#[cfg(test)]

View File

@@ -1,6 +1,7 @@
use crate::context::Context;
use crate::dc_tools::*;
use crate::sql;
use crate::x::strdup;
// Token namespaces
pub type dc_tokennamespc_t = usize;
@@ -25,7 +26,6 @@ pub fn dc_token_save(
"INSERT INTO tokens (namespc, foreign_id, token, timestamp) VALUES (?, ?, ?, ?);",
params![namespc as i32, foreign_id as i32, as_str(token), time()],
)
.is_ok()
}
pub fn dc_token_lookup(
@@ -33,16 +33,16 @@ pub fn dc_token_lookup(
namespc: dc_tokennamespc_t,
foreign_id: u32,
) -> *mut libc::c_char {
context
.sql
.query_row_col::<_, String>(
context,
"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;",
params![namespc as i32, foreign_id as i32],
0,
)
.map(|s| unsafe { to_cstring(s) })
.unwrap_or_else(|| std::ptr::null_mut())
if let Some(token) = context.sql.query_row_col::<_, String>(
context,
"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;",
params![namespc as i32, foreign_id as i32],
0,
) {
unsafe { strdup(to_cstring(token).as_ptr()) }
} else {
std::ptr::null_mut()
}
}
pub fn dc_token_exists(

View File

@@ -1,5 +1,4 @@
use std::borrow::Cow;
use std::ffi::{CStr, CString};
use std::fs;
use std::time::SystemTime;
@@ -177,14 +176,14 @@ pub unsafe fn dc_trim(buf: *mut libc::c_char) {
/* the result must be free()'d */
pub unsafe fn dc_strlower(in_0: *const libc::c_char) -> *mut libc::c_char {
to_cstring(to_string(in_0).to_lowercase())
let raw = to_cstring(to_string(in_0).to_lowercase());
strdup(raw.as_ptr())
}
pub unsafe fn dc_strlower_in_place(in_0: *mut libc::c_char) {
let raw = to_cstring(to_string(in_0).to_lowercase());
assert_eq!(strlen(in_0), strlen(raw));
memcpy(in_0 as *mut _, raw as *const _, strlen(in_0));
free(raw as *mut _);
assert_eq!(strlen(in_0), strlen(raw.as_ptr()));
memcpy(in_0 as *mut _, raw.as_ptr() as *const _, strlen(in_0));
}
pub unsafe fn dc_str_contains(
@@ -232,7 +231,7 @@ pub unsafe fn dc_binary_to_uc_hex(buf: *const uint8_t, bytes: size_t) -> *mut li
let buf = std::slice::from_raw_parts(buf, bytes);
let raw = hex::encode_upper(buf);
to_cstring(raw)
strdup(to_cstring(raw).as_ptr())
}
/* remove all \r characters from string */
@@ -528,7 +527,7 @@ pub unsafe fn dc_str_from_clist(
}
}
to_cstring(res)
strdup(to_cstring(res).as_ptr())
}
pub unsafe fn dc_str_to_clist(
@@ -564,7 +563,7 @@ pub unsafe fn dc_str_to_color(str: *const libc::c_char) -> libc::c_int {
/* the colors must fulfill some criterions as:
- contrast to black and to white
- work as a text-color
- being noticeable on a typical map
- being noticable on a typical map
- harmonize together while being different enough
(therefore, we cannot just use random rgb colors :) */
static mut colors: [uint32_t; 16] = [
@@ -670,7 +669,7 @@ pub unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
/* the return value must be free()'d */
pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char {
let res = dc_timestamp_to_str_safe(wanted);
to_cstring(res)
strdup(to_cstring(res).as_ptr())
}
pub fn dc_timestamp_to_str_safe(wanted: i64) -> String {
@@ -1255,12 +1254,8 @@ pub unsafe fn dc_write_file(
}
pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef<str>, buf: &[u8]) -> bool {
let pathNfilename_abs = unsafe {
let n = to_cstring(pathNfilename.as_ref());
let res = dc_get_abs_path(context, n);
free(n as *mut _);
res
};
let pathNfilename_abs =
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
if pathNfilename_abs.is_null() {
return false;
}
@@ -1304,13 +1299,8 @@ pub unsafe fn dc_read_file(
}
pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef<str>) -> Option<Vec<u8>> {
let pathNfilename_abs = unsafe {
let n = to_cstring(pathNfilename.as_ref());
let p = dc_get_abs_path(context, n);
free(n as *mut _);
p
};
let pathNfilename_abs =
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
if pathNfilename_abs.is_null() {
return None;
}
@@ -1516,20 +1506,20 @@ pub trait OsStrExt {
///
/// On windows when the string contains invalid Unicode
/// `[Err]([CStringError::NotUnicode])` is returned.
fn to_c_string(&self) -> Result<CString, CStringError>;
fn to_c_string(&self) -> Result<std::ffi::CString, CStringError>;
}
impl<T: AsRef<std::ffi::OsStr>> OsStrExt for T {
#[cfg(not(target_os = "windows"))]
fn to_c_string(&self) -> Result<CString, CStringError> {
fn to_c_string(&self) -> Result<std::ffi::CString, CStringError> {
use std::os::unix::ffi::OsStrExt;
CString::new(self.as_ref().as_bytes()).map_err(|err| match err {
std::ffi::CString::new(self.as_ref().as_bytes()).map_err(|err| match err {
std::ffi::NulError { .. } => CStringError::InteriorNullByte,
})
}
#[cfg(target_os = "windows")]
fn to_c_string(&self) -> Result<CString, CStringError> {
fn to_c_string(&self) -> Result<std::ffi::CString, CStringError> {
os_str_to_c_string_unicode(&self)
}
}
@@ -1538,57 +1528,29 @@ impl<T: AsRef<std::ffi::OsStr>> OsStrExt for T {
#[allow(dead_code)]
fn os_str_to_c_string_unicode(
os_str: &dyn AsRef<std::ffi::OsStr>,
) -> Result<CString, CStringError> {
) -> Result<std::ffi::CString, CStringError> {
match os_str.as_ref().to_str() {
Some(val) => CString::new(val.as_bytes()).map_err(|err| match err {
Some(val) => std::ffi::CString::new(val.as_bytes()).map_err(|err| match err {
std::ffi::NulError { .. } => CStringError::InteriorNullByte,
}),
None => Err(CStringError::NotUnicode),
}
}
/// Needs to free the result after use!
pub unsafe fn to_cstring<S: AsRef<str>>(s: S) -> *mut libc::c_char {
let cstr = CString::new(s.as_ref()).expect("invalid string converted");
dc_strdup(cstr.as_ref().as_ptr())
pub fn to_cstring<S: AsRef<str>>(s: S) -> std::ffi::CString {
std::ffi::CString::new(s.as_ref()).unwrap()
}
pub fn to_string(s: *const libc::c_char) -> String {
if s.is_null() {
return "".into();
}
let cstr = unsafe { CStr::from_ptr(s) };
cstr.to_str().map(|s| s.to_string()).unwrap_or_else(|err| {
panic!(
"Non utf8 string: '{:?}' ({:?})",
cstr.to_string_lossy(),
err
);
})
}
pub fn to_string_lossy(s: *const libc::c_char) -> String {
if s.is_null() {
return "".into();
}
let cstr = unsafe { CStr::from_ptr(s) };
cstr.to_str()
.map(|s| s.to_string())
.unwrap_or_else(|_| cstr.to_string_lossy().to_string())
unsafe { std::ffi::CStr::from_ptr(s).to_str().unwrap().to_string() }
}
pub fn as_str<'a>(s: *const libc::c_char) -> &'a str {
assert!(!s.is_null(), "cannot be used on null pointers");
let cstr = unsafe { CStr::from_ptr(s) };
cstr.to_str().unwrap_or_else(|err| {
panic!("Non utf8 string: '{:?}' ({:?})", cstr.to_bytes(), err);
})
unsafe { std::ffi::CStr::from_ptr(s).to_str().unwrap() }
}
/// Convert a C `*char` pointer to a [std::path::Path] slice.
@@ -1620,7 +1582,7 @@ pub fn as_path<'a>(s: *const libc::c_char) -> &'a std::path::Path {
as_path_unicode(s)
}
// Implementation for as_path() on Windows.
// Implmentation for as_path() on Windows.
//
// Having this as a separate function means it can be tested on unix
// too.
@@ -2019,7 +1981,7 @@ mod tests {
let some_dir = std::path::Path::new(&some_str);
assert_eq!(
some_dir.as_os_str().to_c_string().unwrap(),
CString::new("/some/valid/utf8").unwrap()
std::ffi::CString::new("/some/valid/utf8").unwrap()
);
}
@@ -2044,7 +2006,7 @@ mod tests {
let some_dir = std::path::Path::new(&some_str);
assert_eq!(
some_dir.as_os_str().to_c_string().unwrap(),
CString::new("/some/valid/utf8").unwrap()
std::ffi::CString::new("/some/valid/utf8").unwrap()
);
}
@@ -2053,7 +2015,7 @@ mod tests {
let some_str = std::ffi::OsString::from("foo");
assert_eq!(
os_str_to_c_string_unicode(&some_str).unwrap(),
CString::new("foo").unwrap()
std::ffi::CString::new("foo").unwrap()
);
}
@@ -2063,7 +2025,7 @@ mod tests {
let some_path = std::path::Path::new(&some_str);
assert_eq!(
os_str_to_c_string_unicode(&some_path).unwrap(),
CString::new("/some/path").unwrap()
std::ffi::CString::new("/some/path").unwrap()
);
}
@@ -2078,15 +2040,15 @@ mod tests {
#[test]
fn test_as_path() {
let some_path = CString::new("/some/path").unwrap();
let some_path = std::ffi::CString::new("/some/path").unwrap();
let ptr = some_path.as_ptr();
assert_eq!(as_path(ptr), std::ffi::OsString::from("/some/path"))
}
#[test]
fn test_as_path_unicode_fn() {
let some_path = CString::new("/some/path").unwrap();
let some_path = std::ffi::CString::new("/some/path").unwrap();
let ptr = some_path.as_ptr();
assert_eq!(as_path_unicode(ptr), std::ffi::OsString::from("/some/path"));
assert_eq!(as_path_unicode(ptr), std::ffi::OsString::from("/some/path"))
}
}

View File

@@ -14,8 +14,6 @@ pub enum Error {
SqlAlreadyOpen,
#[fail(display = "Sqlite: Failed to open")]
SqlFailedToOpen,
#[fail(display = "{:?}", _0)]
Io(std::io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -37,9 +35,3 @@ impl From<r2d2::Error> for Error {
Error::ConnectionPool(err)
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::Io(err)
}
}

View File

@@ -1,3 +1,4 @@
use std::ffi::CString;
use std::net;
use std::sync::{Arc, Condvar, Mutex, RwLock};
use std::time::{Duration, SystemTime};
@@ -5,10 +6,9 @@ use std::time::{Duration, SystemTime};
use crate::constants::*;
use crate::context::Context;
use crate::dc_loginparam::*;
use crate::dc_tools::{as_str, to_cstring};
use crate::dc_tools::as_str;
use crate::oauth2::dc_get_oauth2_access_token;
use crate::types::*;
use crate::x::free;
pub const DC_IMAP_SEEN: usize = 0x0001;
pub const DC_REGENERATE: usize = 0x01;
@@ -371,9 +371,9 @@ impl Imap {
self.config.read().unwrap().should_reconnect
}
fn setup_handle_if_needed(&self, context: &Context) -> bool {
fn setup_handle_if_needed(&self, context: &Context) -> libc::c_int {
if self.config.read().unwrap().imap_server.is_empty() {
return false;
return 0;
}
if self.should_reconnect() {
@@ -382,7 +382,7 @@ impl Imap {
if self.is_connected() && self.stream.read().unwrap().is_some() {
self.config.write().unwrap().should_reconnect = false;
return true;
return 1;
}
let server_flags = self.config.read().unwrap().server_flags;
@@ -426,7 +426,7 @@ impl Imap {
};
client.authenticate("XOAUTH2", &auth)
} else {
return false;
return 0;
}
} else {
client.login(imap_user, imap_pw)
@@ -447,7 +447,7 @@ impl Imap {
err
);
return false;
return 0;
}
};
@@ -457,37 +457,19 @@ impl Imap {
Ok((session, stream)) => {
*self.session.lock().unwrap() = Some(session);
*self.stream.write().unwrap() = Some(stream);
true
1
}
Err((err, _)) => {
log_event!(context, Event::ERROR_NETWORK, 0, "Cannot login ({})", err);
self.unsetup_handle(context);
false
0
}
}
}
fn unsetup_handle(&self, context: &Context) {
info!(context, 0, "IMAP unsetup_handle starts");
info!(
context,
0, "IMAP unsetup_handle step 1 (closing down stream)."
);
let stream = self.stream.write().unwrap().take();
if stream.is_some() {
match stream.unwrap().shutdown(net::Shutdown::Both) {
Ok(_) => {}
Err(err) => {
eprintln!("failed to shutdown connection: {:?}", err);
}
}
}
info!(
context,
0, "IMAP unsetup_handle step 2 (acquiring session.lock)"
);
let session = self.session.lock().unwrap().take();
if session.is_some() {
match session.unwrap().close() {
@@ -497,11 +479,22 @@ impl Imap {
}
}
}
info!(context, 0, "IMAP unsetup_handle2.");
let stream = self.stream.write().unwrap().take();
if stream.is_some() {
match stream.unwrap().shutdown(net::Shutdown::Both) {
Ok(_) => {}
Err(err) => {
eprintln!("failed to shutdown connection: {:?}", err);
}
}
}
info!(context, 0, "IMAP unsetup_handle step 3 (clearing config).");
self.config.write().unwrap().selected_folder = None;
self.config.write().unwrap().selected_mailbox = None;
info!(context, 0, "IMAP unsetup_handle step 4 (disconnected).",);
info!(context, 0, "IMAP unsetup_handle3.");
let mut cfg = self.config.write().unwrap();
cfg.selected_folder = None;
cfg.selected_mailbox = None;
info!(context, 0, "IMAP disconnected.",);
}
fn free_connect_params(&self) {
@@ -519,13 +512,13 @@ impl Imap {
cfg.watch_folder = None;
}
pub fn connect(&self, context: &Context, lp: &dc_loginparam_t) -> bool {
pub fn connect(&self, context: &Context, lp: &dc_loginparam_t) -> libc::c_int {
if lp.mail_server.is_empty() || lp.mail_user.is_empty() || lp.mail_pw.is_empty() {
return false;
return 0;
}
if self.is_connected() {
return true;
return 1;
}
{
@@ -545,55 +538,49 @@ impl Imap {
config.server_flags = server_flags;
}
if !self.setup_handle_if_needed(context) {
if self.setup_handle_if_needed(context) == 0 {
self.free_connect_params();
return false;
return 0;
}
let teardown: bool;
match &mut *self.session.lock().unwrap() {
Some(ref mut session) => {
if let Ok(caps) = session.capabilities() {
if !context.sql.is_open() {
warn!(context, 0, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
teardown = true;
} else {
let can_idle = caps.has("IDLE");
let has_xlist = caps.has("XLIST");
let caps_list = caps.iter().fold(String::new(), |mut s, c| {
s += " ";
s += c;
s
});
log_event!(
context,
Event::IMAP_CONNECTED,
0,
"IMAP-LOGIN as {}, capabilities: {}",
lp.mail_user,
caps_list,
);
self.config.write().unwrap().can_idle = can_idle;
self.config.write().unwrap().has_xlist = has_xlist;
*self.connected.lock().unwrap() = true;
teardown = false;
}
let can_idle = caps.has("IDLE");
let has_xlist = caps.has("XLIST");
let caps_list = caps.iter().fold(String::new(), |mut s, c| {
s += " ";
s += c;
s
});
log_event!(
context,
Event::IMAP_CONNECTED,
0,
"IMAP-LOGIN as {} ok",
lp.mail_user,
);
info!(context, 0, "IMAP-capabilities:{}", caps_list);
let mut config = self.config.write().unwrap();
config.can_idle = can_idle;
config.has_xlist = has_xlist;
*self.connected.lock().unwrap() = true;
1
} else {
teardown = true;
self.unsetup_handle(context);
self.free_connect_params();
0
}
}
None => {
teardown = true;
self.unsetup_handle(context);
self.free_connect_params();
0
}
}
if teardown {
self.unsetup_handle(context);
self.free_connect_params();
false
} else {
true
}
}
pub fn disconnect(&self, context: &Context) {
@@ -706,19 +693,17 @@ impl Imap {
fn get_config_last_seen_uid<S: AsRef<str>>(&self, context: &Context, folder: S) -> (u32, u32) {
let key = format!("imap.mailbox.{}", folder.as_ref());
let val1 = unsafe {
let key_c = to_cstring(key);
let val = (self.get_config)(context, key_c, 0 as *const libc::c_char);
free(key_c as *mut _);
val
(self.get_config)(
context,
CString::new(key).unwrap().as_ptr(),
0 as *const libc::c_char,
)
};
if val1.is_null() {
return (0, 0);
}
let entry = as_str(val1);
if entry.is_empty() {
return (0, 0);
}
// the entry has the format `imap.mailbox.<folder>=<uidvalidity>:<lastseenuid>`
let mut parts = entry.split(':');
(
@@ -852,11 +837,9 @@ impl Imap {
.message_id
.expect("missing message id");
let message_id_c = CString::new(message_id).unwrap();
if 0 == unsafe {
let message_id_c = to_cstring(message_id);
let res = (self.precheck_imf)(context, message_id_c, folder.as_ref(), cur_uid);
free(message_id_c as *mut _);
res
(self.precheck_imf)(context, message_id_c.as_ptr(), folder.as_ref(), cur_uid)
} {
// check passed, go fetch the rest
if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
@@ -925,11 +908,11 @@ impl Imap {
let val = format!("{}:{}", uidvalidity, lastseenuid);
unsafe {
let key_c = to_cstring(key);
let val_c = to_cstring(val);
(self.set_config)(context, key_c, val_c);
free(key_c as *mut _);
free(val_c as *mut _);
(self.set_config)(
context,
CString::new(key).unwrap().as_ptr(),
CString::new(val).unwrap().as_ptr(),
)
};
}
@@ -1008,12 +991,11 @@ impl Imap {
let flags = if is_seen { DC_IMAP_SEEN } else { 0 };
if !is_deleted && msg.body().is_some() {
let body = msg.body().unwrap();
unsafe {
(self.receive_imf)(
context,
body.as_ptr() as *const libc::c_char,
body.len(),
msg.body().unwrap().as_ptr() as *const libc::c_char,
msg.body().unwrap().len(),
folder.as_ref(),
server_uid,
flags as u32,
@@ -1048,15 +1030,13 @@ impl Imap {
let (sender, receiver) = std::sync::mpsc::channel();
let v = self.watch.clone();
info!(context, 0, "IMAP-IDLE SPAWNING");
std::thread::spawn(move || {
let &(ref lock, ref cvar) = &*v;
if let Some(ref mut session) = &mut *session.lock().unwrap() {
let mut idle = match session.idle() {
Ok(idle) => idle,
Err(err) => {
eprintln!("failed to setup idle: {:?}", err);
return;
panic!("failed to setup idle: {:?}", err);
}
};
@@ -1164,7 +1144,7 @@ impl Imap {
// check for new messages. fetch_from_single_folder() has the side-effect that messages
// are also downloaded, however, typically this would take place in the FETCH command
// following IDLE otherwise, so this seems okay here.
if self.setup_handle_if_needed(context) {
if self.setup_handle_if_needed(context) != 0 {
if let Some(ref watch_folder) = self.config.read().unwrap().watch_folder {
if 0 != self.fetch_from_single_folder(context, watch_folder) {
do_fake_idle = false;

View File

@@ -89,9 +89,6 @@ impl Key {
}
pub fn from_slice(bytes: &[u8], key_type: KeyType) -> Option<Self> {
if 0 == bytes.len() {
return None;
}
let res: Result<Key, _> = match key_type {
KeyType::Public => SignedPublicKey::from_bytes(Cursor::new(bytes)).map(Into::into),
KeyType::Private => SignedSecretKey::from_bytes(Cursor::new(bytes)).map(Into::into),
@@ -309,7 +306,7 @@ pub fn dc_key_save_self_keypair(
sql,
"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);",
params![addr.as_ref(), is_default, public_key.to_bytes(), private_key.to_bytes(), time()],
).is_ok()
)
}
/// Make a fingerprint human-readable, in hex format.

View File

@@ -3,14 +3,11 @@ macro_rules! info {
($ctx:expr, $data1:expr, $msg:expr) => {
info!($ctx, $data1, $msg,)
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
#[allow(unused_unsafe)]
unsafe {
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::INFO, $data1 as libc::uintptr_t,
formatted_c as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void);
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {{
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::INFO, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t)
}};
}
@@ -20,14 +17,11 @@ macro_rules! warn {
warn!($ctx, $data1, $msg,)
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
#[allow(unused_unsafe)]
unsafe {
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t,
formatted_c as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void) ;
}};
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t)
};
}
#[macro_export]
@@ -36,14 +30,11 @@ macro_rules! error {
error!($ctx, $data1, $msg,)
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
#[allow(unused_unsafe)]
unsafe {
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::ERROR, $data1 as libc::uintptr_t,
formatted_c as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void);
}};
formatted_c.as_ptr() as libc::uintptr_t)
};
}
#[macro_export]
@@ -52,12 +43,9 @@ macro_rules! log_event {
log_event!($ctx, $data1, $msg,)
};
($ctx:expr, $event:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
#[allow(unused_unsafe)]
unsafe {
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($event, $data1 as libc::uintptr_t,
formatted_c as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void);
}};
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($event, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t)
};
}

View File

@@ -76,17 +76,19 @@ pub fn dc_get_oauth2_access_token(
// read generated token
if 0 == flags & 0x1 && !is_expired(context) {
let access_token = context.sql.get_config(context, "oauth2_access_token");
let access_token = context.sql.get_config(context, "oauth2_access_token", None);
if access_token.is_some() {
// success
return access_token;
}
}
let refresh_token = context.sql.get_config(context, "oauth2_refresh_token");
let refresh_token = context
.sql
.get_config(context, "oauth2_refresh_token", None);
let refresh_token_for = context
.sql
.get_config(context, "oauth2_refresh_token_for")
.get_config(context, "oauth2_refresh_token_for", None)
.unwrap_or_else(|| "unset".into());
let (redirect_uri, token_url, update_redirect_uri_on_success) =
@@ -98,7 +100,7 @@ pub fn dc_get_oauth2_access_token(
(
context
.sql
.get_config(context, "oauth2_pending_redirect_uri")
.get_config(context, "oauth2_pending_redirect_uri", None)
.unwrap_or_else(|| "unset".into()),
oauth2.init_token,
true,
@@ -111,7 +113,7 @@ pub fn dc_get_oauth2_access_token(
(
context
.sql
.get_config(context, "oauth2_redirect_uri")
.get_config(context, "oauth2_redirect_uri", None)
.unwrap_or_else(|| "unset".into()),
oauth2.refresh_token,
false,
@@ -294,10 +296,10 @@ impl Oauth2 {
}
fn is_expired(context: &Context) -> bool {
let expire_timestamp = context
.sql
.get_config_int64(context, "oauth2_timestamp_expires")
.unwrap_or_default();
let expire_timestamp =
context
.sql
.get_config_int64(context, "oauth2_timestamp_expires", Some(0));
if expire_timestamp <= 0 {
return false;

View File

@@ -387,14 +387,12 @@ impl<'a> Peerstate<'a> {
}
if create {
if sql::execute(
if !sql::execute(
self.context,
sql,
"INSERT INTO acpeerstates (addr) VALUES(?);",
params![self.addr.as_ref().unwrap()],
)
.is_err()
{
) {
return false;
}
}
@@ -421,7 +419,7 @@ impl<'a> Peerstate<'a> {
&self.verified_key_fingerprint,
&self.addr,
],
).is_ok();
);
} else if self.to_save == Some(ToSave::Timestamps) {
success = sql::execute(
self.context,
@@ -434,8 +432,7 @@ impl<'a> Peerstate<'a> {
self.gossip_timestamp,
&self.addr
],
)
.is_ok();
);
}
if self.to_save == Some(ToSave::All) || create {
@@ -462,12 +459,10 @@ mod tests {
use super::*;
use pretty_assertions::assert_eq;
use std::ffi::CStr;
use std::ffi::{CStr, CString};
use tempfile::{tempdir, TempDir};
use crate::context::*;
use crate::dc_tools::to_cstring;
use crate::x::free;
#[test]
fn test_peerstate_save_to_db() {
@@ -522,16 +517,16 @@ mod tests {
unsafe fn create_test_context() -> TestContext {
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
let dir = tempdir().unwrap();
let dbfile = to_cstring(dir.path().join("db.sqlite").to_str().unwrap());
let dbfile = CString::new(dir.path().join("db.sqlite").to_str().unwrap()).unwrap();
assert_eq!(
dc_open(&mut ctx, dbfile, std::ptr::null()),
dc_open(&mut ctx, dbfile.as_ptr(), std::ptr::null()),
1,
"Failed to open {}",
CStr::from_ptr(dbfile as *const _).to_str().unwrap()
CStr::from_ptr(dbfile.as_ptr() as *const libc::c_char)
.to_str()
.unwrap()
);
free(dbfile as *mut _);
TestContext { ctx: ctx, dir: dir }
}
}

View File

@@ -43,10 +43,10 @@ impl Smtp {
}
/// Connect using the provided login params
pub fn connect(&mut self, context: &Context, lp: &dc_loginparam_t) -> bool {
pub fn connect(&mut self, context: &Context, lp: &dc_loginparam_t) -> usize {
if self.is_connected() {
warn!(context, 0, "SMTP already connected.");
return true;
return 1;
}
if lp.send_server.is_empty() || lp.send_port == 0 {
@@ -61,7 +61,7 @@ impl Smtp {
if self.from.is_none() {
// TODO: print error
return false;
return 0;
}
let domain = &lp.send_server;
@@ -82,7 +82,7 @@ impl Smtp {
let send_pw = &lp.send_pw;
let access_token = dc_get_oauth2_access_token(context, addr, send_pw, 0);
if access_token.is_none() {
return false;
return 0;
}
let user = &lp.send_user;
@@ -116,11 +116,11 @@ impl Smtp {
"SMTP-LOGIN as {} ok",
lp.send_user,
);
true
1
}
Err(err) => {
warn!(context, 0, "SMTP: failed to establish connection {:?}", err);
false
0
}
}
}

View File

@@ -1,8 +1,7 @@
use std::collections::HashSet;
use std::sync::{Arc, RwLock};
use std::sync::RwLock;
use rusqlite::{Connection, OpenFlags, Statement, NO_PARAMS};
use thread_local_object::ThreadLocal;
use crate::constants::*;
use crate::context::Context;
@@ -17,14 +16,12 @@ const DC_OPEN_READONLY: usize = 0x01;
/// A wrapper around the underlying Sqlite3 object.
pub struct Sql {
pool: RwLock<Option<r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>>>,
in_use: Arc<ThreadLocal<String>>,
}
impl Sql {
pub fn new() -> Sql {
Sql {
pool: RwLock::new(None),
in_use: Arc::new(ThreadLocal::new()),
}
}
@@ -33,10 +30,11 @@ impl Sql {
}
pub fn close(&self, context: &Context) {
let _ = self.pool.write().unwrap().take();
self.in_use.remove();
// drop closes the connection
let mut pool = self.pool.write().unwrap();
if pool.is_some() {
pool.take();
// drop closes the connection
}
info!(context, 0, "Database closed.");
}
@@ -57,7 +55,6 @@ impl Sql {
P: IntoIterator,
P::Item: rusqlite::ToSql,
{
self.start_stmt(sql.to_string());
self.with_conn(|conn| conn.execute(sql, params).map_err(Into::into))
}
@@ -65,25 +62,22 @@ impl Sql {
where
G: FnOnce(&Connection) -> Result<T>,
{
let res = match &*self.pool.read().unwrap() {
match &*self.pool.read().unwrap() {
Some(pool) => {
let conn = pool.get()?;
g(&conn)
}
None => Err(Error::SqlNoConnection),
};
self.in_use.remove();
res
}
}
pub fn prepare<G, H>(&self, sql: &str, g: G) -> Result<H>
where
G: FnOnce(Statement<'_>, &Connection) -> Result<H>,
G: FnOnce(Statement<'_>) -> Result<H>,
{
self.start_stmt(sql.to_string());
self.with_conn(|conn| {
let stmt = conn.prepare(sql)?;
let res = g(stmt, conn)?;
let res = g(stmt)?;
Ok(res)
})
}
@@ -92,7 +86,6 @@ impl Sql {
where
G: FnOnce(Statement<'_>, Statement<'_>, &Connection) -> Result<H>,
{
self.start_stmt(format!("{} - {}", sql1, sql2));
self.with_conn(|conn| {
let stmt1 = conn.prepare(sql1)?;
let stmt2 = conn.prepare(sql2)?;
@@ -118,8 +111,8 @@ impl Sql {
F: FnMut(&rusqlite::Row) -> rusqlite::Result<T>,
G: FnMut(rusqlite::MappedRows<F>) -> Result<H>,
{
self.start_stmt(sql.as_ref().to_string());
self.with_conn(|conn| {
eprintln!("query_map {}", sql.as_ref());
let mut stmt = conn.prepare(sql.as_ref())?;
let res = stmt.query_map(params, f)?;
g(res)
@@ -133,7 +126,6 @@ impl Sql {
P: IntoIterator,
P::Item: rusqlite::ToSql,
{
self.start_stmt(sql.to_string());
self.with_conn(|conn| {
let mut stmt = conn.prepare(sql)?;
let res = stmt.exists(params)?;
@@ -147,12 +139,11 @@ impl Sql {
P::Item: rusqlite::ToSql,
F: FnOnce(&rusqlite::Row) -> rusqlite::Result<T>,
{
self.start_stmt(sql.as_ref().to_string());
self.with_conn(|conn| conn.query_row(sql.as_ref(), params, f).map_err(Into::into))
}
pub fn table_exists(&self, name: impl AsRef<str>) -> bool {
self.with_conn(|conn| table_exists(conn, name))
self.with_conn(|conn| Ok(table_exists(conn, name)))
.unwrap_or_default()
}
@@ -184,56 +175,63 @@ impl Sql {
}
/// Set private configuration options.
/// Setting `None` deletes the value.
pub fn set_config(
&self,
context: &Context,
key: impl AsRef<str>,
value: Option<&str>,
) -> Result<()> {
) -> libc::c_int {
if !self.is_open() {
error!(context, 0, "set_config(): Database not ready.");
return Err(Error::SqlNoConnection);
return 0;
}
let key = key.as_ref();
let res = if let Some(ref value) = value {
let exists = self.exists("SELECT value FROM config WHERE keyname=?;", params![key])?;
let good;
if let Some(ref value) = value {
let exists = self
.exists("SELECT value FROM config WHERE keyname=?;", params![key])
.unwrap_or_default();
if exists {
execute(
good = execute(
context,
self,
"UPDATE config SET value=? WHERE keyname=?;",
params![value, key],
)
);
} else {
execute(
good = execute(
context,
self,
"INSERT INTO config (keyname, value) VALUES (?, ?);",
params![key, value],
)
);
}
} else {
execute(
good = execute(
context,
self,
"DELETE FROM config WHERE keyname=?;",
params![key],
)
};
match res {
Ok(_) => Ok(()),
Err(err) => {
error!(context, 0, "set_config(): Cannot change value. {:?}", &err);
Err(err.into())
}
);
}
if !good {
error!(context, 0, "set_config(): Cannot change value.",);
return 0;
}
1
}
/// Get configuration options from the database.
pub fn get_config(&self, context: &Context, key: impl AsRef<str>) -> Option<String> {
pub fn get_config(
&self,
context: &Context,
key: impl AsRef<str>,
def: Option<&str>,
) -> Option<String> {
if !self.is_open() || key.as_ref().is_empty() {
return None;
}
@@ -243,6 +241,7 @@ impl Sql {
params![key.as_ref()],
0,
)
.or_else(|| def.map(|s| s.to_string()))
}
pub fn set_config_int(
@@ -250,12 +249,14 @@ impl Sql {
context: &Context,
key: impl AsRef<str>,
value: i32,
) -> Result<()> {
) -> libc::c_int {
self.set_config(context, key, Some(&format!("{}", value)))
}
pub fn get_config_int(&self, context: &Context, key: impl AsRef<str>) -> Option<i32> {
self.get_config(context, key).and_then(|s| s.parse().ok())
pub fn get_config_int(&self, context: &Context, key: impl AsRef<str>, def: i32) -> i32 {
self.get_config(context, key, None)
.and_then(|s| s.parse().ok())
.unwrap_or_else(|| def)
}
pub fn set_config_int64(
@@ -263,36 +264,36 @@ impl Sql {
context: &Context,
key: impl AsRef<str>,
value: i64,
) -> Result<()> {
) -> libc::c_int {
self.set_config(context, key, Some(&format!("{}", value)))
}
pub fn get_config_int64(&self, context: &Context, key: impl AsRef<str>) -> Option<i64> {
self.get_config(context, key).and_then(|r| r.parse().ok())
}
fn start_stmt(&self, stmt: impl AsRef<str>) {
if let Some(query) = self.in_use.get_cloned() {
let bt = backtrace::Backtrace::new();
eprintln!("old query: {}", query);
eprintln!("Connection is already used from this thread: {:?}", bt);
panic!("Connection is already used from this thread");
}
self.in_use.set(stmt.as_ref().to_string());
pub fn get_config_int64(
&self,
context: &Context,
key: impl AsRef<str>,
def: Option<i64>,
) -> i64 {
let ret = self.get_config(context, key, None);
ret.map(|r| r.parse().unwrap_or_default())
.unwrap_or_else(|| def.unwrap_or_default())
}
}
fn table_exists(conn: &Connection, name: impl AsRef<str>) -> Result<bool> {
fn table_exists(conn: &Connection, name: impl AsRef<str>) -> bool {
let mut exists = false;
conn.pragma(None, "table_info", &format!("{}", name.as_ref()), |_row| {
// will only be executed if the info was found
exists = true;
Ok(())
})?;
Ok(exists)
})
.expect("bad sqlite state");
exists
}
// Return 1 -> success
// Return 0 -> failure
fn open(
context: &Context,
sql: &Sql,
@@ -463,7 +464,7 @@ fn open(
}
} else {
exists_before_update = 1;
dbversion_before_update = sql.get_config_int(context, "dbversion").unwrap_or_default();
dbversion_before_update = sql.get_config_int(context, "dbversion", 0);
}
// (1) update low-level database structure.
@@ -789,8 +790,8 @@ fn open(
info!(context, 0, "[open] update file paths");
let repl_from = sql
.get_config(context, "backup_for")
.unwrap_or_else(|| to_string(context.get_blobdir()));
.get_config(context, "backup_for", Some(as_str(context.get_blobdir())))
.unwrap();
let repl_from = dc_ensure_no_slash_safe(&repl_from);
sql.execute(
@@ -818,39 +819,39 @@ fn open(
Ok(())
}
pub fn execute<P>(context: &Context, sql: &Sql, querystr: impl AsRef<str>, params: P) -> Result<()>
pub fn execute<P>(context: &Context, sql: &Sql, querystr: impl AsRef<str>, params: P) -> bool
where
P: IntoIterator,
P::Item: rusqlite::ToSql,
{
match sql.execute(querystr.as_ref(), params) {
Ok(_) => Ok(()),
Ok(_) => true,
Err(err) => {
error!(
context,
0,
"execute failed: {:?} for {}",
&err,
err,
querystr.as_ref()
);
Err(err.into())
false
}
}
}
pub fn try_execute(context: &Context, sql: &Sql, querystr: impl AsRef<str>) -> Result<()> {
pub fn try_execute(context: &Context, sql: &Sql, querystr: impl AsRef<str>) -> libc::c_int {
// same as execute() but does not pass error to ui
match sql.execute(querystr.as_ref(), params![]) {
Ok(_) => Ok(()),
Ok(_) => 1,
Err(err) => {
warn!(
context,
0,
"Try-execute for \"{}\" failed: {}",
querystr.as_ref(),
&err,
err,
);
Err(err)
0
}
}
}
@@ -861,22 +862,10 @@ pub fn get_rowid(
table: impl AsRef<str>,
field: impl AsRef<str>,
value: impl AsRef<str>,
) -> u32 {
sql.start_stmt("get rowid".to_string());
sql.with_conn(|conn| Ok(get_rowid_with_conn(context, conn, table, field, value)))
.unwrap_or_else(|_| 0)
}
pub fn get_rowid_with_conn(
context: &Context,
conn: &Connection,
table: impl AsRef<str>,
field: impl AsRef<str>,
value: impl AsRef<str>,
) -> u32 {
// alternative to sqlite3_last_insert_rowid() which MUST NOT be used due to race conditions, see comment above.
// the ORDER BY ensures, this function always returns the most recent id,
// eg. if a Message-ID is split into different messages.
// eg. if a Message-ID is splitted into different messages.
let query = format!(
"SELECT id FROM {} WHERE {}='{}' ORDER BY id DESC",
table.as_ref(),
@@ -884,7 +873,7 @@ pub fn get_rowid_with_conn(
value.as_ref()
);
match conn.query_row(&query, NO_PARAMS, |row| row.get::<_, u32>(0)) {
match sql.query_row(&query, NO_PARAMS, |row| row.get::<_, u32>(0)) {
Ok(id) => id,
Err(err) => {
error!(
@@ -895,6 +884,7 @@ pub fn get_rowid_with_conn(
}
}
}
pub fn get_rowid2(
context: &Context,
sql: &Sql,
@@ -904,7 +894,6 @@ pub fn get_rowid2(
field2: impl AsRef<str>,
value2: i32,
) -> u32 {
sql.start_stmt("get rowid2".to_string());
sql.with_conn(|conn| {
Ok(get_rowid2_with_conn(
context, conn, table, field, value, field2, value2,
@@ -1004,36 +993,31 @@ pub fn housekeeping(context: &Context) {
}
let entry = entry.unwrap();
let name_f = entry.file_name();
let name_c = unsafe { to_cstring(name_f.to_string_lossy()) };
let name_c = to_cstring(name_f.to_string_lossy());
if unsafe { is_file_in_use(&mut files_in_use, 0 as *const libc::c_char, name_c) }
|| unsafe {
is_file_in_use(
&mut files_in_use,
b".increation\x00" as *const u8 as *const libc::c_char,
name_c,
)
}
|| unsafe {
is_file_in_use(
&mut files_in_use,
b".waveform\x00" as *const u8 as *const libc::c_char,
name_c,
)
}
|| unsafe {
is_file_in_use(
&mut files_in_use,
b"-preview.jpg\x00" as *const u8 as *const libc::c_char,
name_c,
)
}
{
unsafe { free(name_c as *mut _) };
if unsafe {
is_file_in_use(&mut files_in_use, 0 as *const libc::c_char, name_c.as_ptr())
} || unsafe {
is_file_in_use(
&mut files_in_use,
b".increation\x00" as *const u8 as *const libc::c_char,
name_c.as_ptr(),
)
} || unsafe {
is_file_in_use(
&mut files_in_use,
b".waveform\x00" as *const u8 as *const libc::c_char,
name_c.as_ptr(),
)
} || unsafe {
is_file_in_use(
&mut files_in_use,
b"-preview.jpg\x00" as *const u8 as *const libc::c_char,
name_c.as_ptr(),
)
} {
continue;
}
unsafe { free(name_c as *mut _) };
unreferenced_count += 1;
match std::fs::metadata(entry.path()) {
@@ -1065,11 +1049,8 @@ pub fn housekeeping(context: &Context) {
unreferenced_count,
entry.file_name()
);
unsafe {
let path = to_cstring(entry.path().to_str().unwrap());
dc_delete_file(context, path);
free(path as *mut _);
}
let path = to_cstring(entry.path().to_str().unwrap());
unsafe { dc_delete_file(context, path.as_ptr()) };
}
}
Err(err) => {
@@ -1127,16 +1108,14 @@ fn maybe_add_from_param(
context
.sql
.query_row(query, NO_PARAMS, |row| {
let v = to_cstring(row.get::<_, String>(0)?);
unsafe {
let v = to_cstring(row.get::<_, String>(0)?);
dc_param_set_packed(param, v as *const _);
let file = dc_param_get(param, param_id, 0 as *const _);
dc_param_set_packed(param, v.as_ptr() as *const libc::c_char);
let file = dc_param_get(param, param_id, 0 as *const libc::c_char);
if !file.is_null() {
maybe_add_file(files_in_use, as_str(file));
free(file as *mut libc::c_void);
}
free(v as *mut _);
}
Ok(())
})
@@ -1170,6 +1149,7 @@ mod test {
maybe_add_file(&mut files, "$BLOBDIR/world.txt");
maybe_add_file(&mut files, "world2.txt");
println!("{:?}", files);
assert!(unsafe {
is_file_in_use(
&mut files,

View File

@@ -1,29 +0,0 @@
#!/usr/bin/env python3
import os
if __name__ == "__main__":
filestats = []
for fn in os.listdir():
if fn.endswith(".rs"):
s = open(fn).read()
unsafe = s.count("unsafe")
free = s.count("free(")
gotoblocks = s.count("current_block =")
filestats.append((fn, unsafe, free, gotoblocks))
sum_unsafe, sum_free, sum_gotoblocks = 0, 0, 0
for fn, unsafe, free, gotoblocks in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
print("{0: <30} unsafe: {1: >3} free: {2: >3} goto-blocks: {3: >3}".format(fn, unsafe, free, gotoblocks))
sum_unsafe += unsafe
sum_free += free
sum_gotoblocks += gotoblocks
print()
print("total unsafe:", sum_unsafe)
print("total free:", sum_free)
print("total gotoblocks:", sum_gotoblocks)

View File

@@ -1,6 +1,7 @@
//! Stress some functions for testing; if used as a lib, this file is obsolete.
use std::collections::HashSet;
use std::ffi::CString;
use mmime::mailimf_types::*;
use tempfile::{tempdir, TempDir};
@@ -174,7 +175,7 @@ unsafe fn stress_functions(context: &Context) {
"content"
);
free(buf as *mut _);
free(buf);
assert_ne!(
0,
dc_delete_file(
@@ -247,7 +248,7 @@ unsafe fn stress_functions(context: &Context) {
free(fn1 as *mut libc::c_void);
}
let res = context.get_config(config::Config::SysConfigKeys).unwrap();
let res = config::get(context, "sys.config_keys");
assert!(!res.contains(" probably_never_a_key "));
assert!(res.contains(" addr "));
@@ -690,7 +691,7 @@ fn test_encryption_decryption() {
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
let ctext_signed_bytes = ctext.len();
let ctext_signed = to_cstring(ctext);
let ctext_signed = CString::new(ctext).unwrap();
let ctext = dc_pgp_pk_encrypt(
original_text as *const libc::c_void,
@@ -703,7 +704,7 @@ fn test_encryption_decryption() {
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
let ctext_unsigned_bytes = ctext.len();
let ctext_unsigned = to_cstring(ctext);
let ctext_unsigned = CString::new(ctext).unwrap();
let mut keyring = Keyring::default();
keyring.add_owned(private_key);
@@ -717,7 +718,7 @@ fn test_encryption_decryption() {
let mut valid_signatures: HashSet<String> = Default::default();
let plain = dc_pgp_pk_decrypt(
ctext_signed as *const _,
ctext_signed.as_ptr() as *const _,
ctext_signed_bytes,
&keyring,
&public_keyring,
@@ -732,7 +733,7 @@ fn test_encryption_decryption() {
let empty_keyring = Keyring::default();
let plain = dc_pgp_pk_decrypt(
ctext_signed as *const _,
ctext_signed.as_ptr() as *const _,
ctext_signed_bytes,
&keyring,
&empty_keyring,
@@ -745,7 +746,7 @@ fn test_encryption_decryption() {
valid_signatures.clear();
let plain = dc_pgp_pk_decrypt(
ctext_signed as *const _,
ctext_signed.as_ptr() as *const _,
ctext_signed_bytes,
&keyring,
&public_keyring2,
@@ -760,7 +761,7 @@ fn test_encryption_decryption() {
public_keyring2.add_ref(&public_key);
let plain = dc_pgp_pk_decrypt(
ctext_signed as *const _,
ctext_signed.as_ptr() as *const _,
ctext_signed_bytes,
&keyring,
&public_keyring2,
@@ -773,15 +774,13 @@ fn test_encryption_decryption() {
valid_signatures.clear();
let plain = dc_pgp_pk_decrypt(
ctext_unsigned as *const _,
ctext_unsigned.as_ptr() as *const _,
ctext_unsigned_bytes,
&keyring,
&public_keyring,
Some(&mut valid_signatures),
)
.unwrap();
free(ctext_unsigned as *mut _);
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
valid_signatures.clear();
@@ -792,15 +791,13 @@ fn test_encryption_decryption() {
public_keyring.add_ref(&public_key);
let plain = dc_pgp_pk_decrypt(
ctext_signed as *const _,
ctext_signed.as_ptr() as *const _,
ctext_signed_bytes,
&keyring,
&public_keyring,
None,
)
.unwrap();
free(ctext_signed as *mut _);
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
}
}
@@ -823,14 +820,14 @@ struct TestContext {
unsafe fn create_test_context() -> TestContext {
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
let dir = tempdir().unwrap();
let dbfile = to_cstring(dir.path().join("db.sqlite").to_str().unwrap());
let dbfile = CString::new(dir.path().join("db.sqlite").to_str().unwrap()).unwrap();
assert_eq!(
dc_open(&mut ctx, dbfile, std::ptr::null()),
dc_open(&mut ctx, dbfile.as_ptr(), std::ptr::null()),
1,
"Failed to open {}",
as_str(dbfile as *const libc::c_char)
as_str(dbfile.as_ptr() as *const libc::c_char)
);
free(dbfile as *mut _);
TestContext { ctx: ctx, dir: dir }
}
@@ -955,29 +952,24 @@ fn test_stress_tests() {
fn test_get_contacts() {
unsafe {
let context = create_test_context();
let name = to_cstring("some2");
let contacts = dc_get_contacts(&context.ctx, 0, name);
let contacts = dc_get_contacts(&context.ctx, 0, to_cstring("some2").as_ptr());
assert_eq!(dc_array_get_cnt(contacts), 0);
dc_array_unref(contacts);
free(name as *mut _);
let name = to_cstring("bob");
let email = to_cstring("bob@mail.de");
let id = dc_create_contact(&context.ctx, name, email);
let id = dc_create_contact(
&context.ctx,
to_cstring("bob").as_ptr(),
to_cstring("bob@mail.de").as_ptr(),
);
assert_ne!(id, 0);
let contacts = dc_get_contacts(&context.ctx, 0, name);
let contacts = dc_get_contacts(&context.ctx, 0, to_cstring("bob").as_ptr());
assert_eq!(dc_array_get_cnt(contacts), 1);
dc_array_unref(contacts);
let name2 = to_cstring("alice");
let contacts = dc_get_contacts(&context.ctx, 0, name2);
let contacts = dc_get_contacts(&context.ctx, 0, to_cstring("alice").as_ptr());
assert_eq!(dc_array_get_cnt(contacts), 0);
dc_array_unref(contacts);
free(name as *mut _);
free(name2 as *mut _);
free(email as *mut _);
}
}
@@ -985,12 +977,11 @@ fn test_get_contacts() {
fn test_chat() {
unsafe {
let context = create_test_context();
let name = to_cstring("bob");
let email = to_cstring("bob@mail.de");
let contact1 = dc_create_contact(&context.ctx, name, email);
free(name as *mut _);
free(email as *mut _);
let contact1 = dc_create_contact(
&context.ctx,
to_cstring("bob").as_ptr(),
to_cstring("bob@mail.de").as_ptr(),
);
assert_ne!(contact1, 0);
let chat_id = dc_create_chat_by_contact_id(&context.ctx, contact1);
@@ -1007,21 +998,6 @@ fn test_chat() {
}
}
#[test]
fn test_wrong_db() {
unsafe {
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
let dir = tempdir().unwrap();
let dbfile = dir.path().join("db.sqlite");
std::fs::write(&dbfile, b"123").unwrap();
let dbfile_c = to_cstring(dbfile.to_str().unwrap());
let res = dc_open(&mut ctx, dbfile_c, std::ptr::null());
free(dbfile_c as *mut _);
assert_eq!(res, 0);
}
}
#[test]
fn test_arr_to_string() {
let arr2: [uint32_t; 4] = [