Compare commits

..

47 Commits

Author SHA1 Message Date
jikstra
1ab014f96f Start implementing Ui config on top of the Config enum 2019-09-14 21:44:59 +02:00
B. Petersen
70a69d5313 cargo fmt 2019-09-13 11:02:34 +02:00
B. Petersen
056faad029 Implement set/get_ui_config and use those methods if config string starts with 'ui.' 2019-09-12 21:53:37 +02:00
Floris Bruynooghe
aefddf7f5e Remove context refrence from Contact struct
This will allow the Rust Context API to be refactored without breaking
the C API.  Full details in #476 aka
a0b5e32f98
2019-09-11 23:53:48 +02:00
Floris Bruynooghe
5ce27b16f1 Remove context refernce from Chatlist
See #476 aka a0b5e32f98 for full
rationale.  Tl;dr it allows us to evolve the Rust API while keeping
the FFI API identical.
2019-09-11 23:53:48 +02:00
Floris Bruynooghe
8302d6833d Remove context ref from Chat struct
Leaving the C API untouched.  See #476 aka
a0b5e32f98 for more extensive rationale.
2019-09-11 23:53:48 +02:00
holger krekel
649c2eb676 try running qr tests in a new process instead of with all the other tests 2019-09-11 22:42:51 +02:00
Floris Bruynooghe
a0b5e32f98 Remove the context reference from Message struct
The Message struct had a reference to the context which made a few
APIs a little easier.  However it has surprising consequences a long
way down the line as shown in #335: it means any object which has such
a reference needs to keep open a lock if we want to do this refactor
of no longer having a "closed" Context struct on the Rust API (which
has many benefits which will simply that Context struct and is more
the Rust way - RAII etc).

By refactoring away the context reference on the rust API as done in
here however, we push this behaviour of how these references are
handled back to the C-API pointer behaviour: that is unsafe but just
works in a C-like way.  The resulting complexity in the FFI layer is
also notably less than in the #335 alternative.

As a consequence all APIs which require the context, now explicitly
need to get the context passed in as an argument.  It looks like this
is certainly no downside and maybe even beneficial for further API
refactors.

For this strategy to work out the same should be done to
dc_chatlist_t, dc_chat_t and dc_contact_t.  But this working for
dc_msg_t give a reasonable confidence that this is a good approach.
2019-09-11 21:48:40 +02:00
björn petersen
e73671a6ff Merge pull request #485 from deltachat/really-fix-477
do not panic on bad-utf-8
2019-09-11 20:14:48 +02:00
björn petersen
9503aca78d Merge branch 'master' into really-fix-477 2019-09-11 19:52:13 +02:00
björn petersen
dfaa8e4529 Merge pull request #490 from deltachat/fix/location-sql
fix(location): do not sql recurse in location sending
2019-09-11 19:40:46 +02:00
björn petersen
cbc3579e9a Merge pull request #489 from deltachat/no-recursive-delete
do not recursive delete folders
2019-09-11 19:39:15 +02:00
dignifiedquire
dd2e3d35fd fix(location): another nesting 2019-09-11 18:13:21 +02:00
dignifiedquire
ca9dccfcd7 fix(location): another nested sql 2019-09-11 17:57:59 +02:00
dignifiedquire
64b00fce7d fix(location): do not sql recurse in location sending 2019-09-11 17:46:05 +02:00
B. Petersen
177ab0229a do not call fs::remove_dir_all() implicitly on non-files; deleting folders is not needed and calling remove_dir_all() is considered harmful 2019-09-11 17:02:27 +02:00
Alexander Krotov
68b5e34fed Merge pull request #488 from KAction/transfer
Reduce indentation in dc_continue_key_transfer
2019-09-11 05:36:02 +00:00
Dmitry Bogatov
2eda839303 cargo-fmt 2019-09-11 02:21:39 +00:00
Dmitry Bogatov
71a01d3002 Reduce indentation in dc_continue_key_transfer
Replace `if (ok) { }` pattern with `if (!ok) return` to reduce
indentation level.

Note: This commit fails CI due incorrect formatting. It is done
deliberately to simplify review process.
2019-09-11 02:21:39 +00:00
Alexander Krotov
995548002b Merge pull request #484 from link2xt/safe_test_encryption_decryption
Safe test encryption decryption
2019-09-11 00:43:21 +00:00
Alexander Krotov
38ad16887b Merge pull request #487 from KAction/top_evil
Minor refactoring
2019-09-11 00:42:48 +00:00
Dmitry Bogatov
c20e8f7613 Use safe version of dc_decode_header_words on one call site 2019-09-10 23:31:29 +00:00
Dmitry Bogatov
5bd4606854 Implement safe version of `dc_decode_header_words' 2019-09-10 23:26:08 +00:00
Dmitry Bogatov
e7b198849d Copy comment for dc_encode_headers_words from C code 2019-09-10 22:49:53 +00:00
Dmitry Bogatov
3ab0d74af2 Remove unused `unsafe' block in log_event! macro 2019-09-10 22:35:54 +00:00
Dmitry Bogatov
7ed5a8e72f Reimplement logging macros in terms of log_event!
Avoid copy-paste message formatting code in src/log.rs, forwarding all
arguments of info! warn! error! macros to generic log_event! macro.
2019-09-10 22:34:38 +00:00
Dmitry Bogatov
57daa0f7f0 Remove useless argument of logging macros
Previously, logging macros (info! warn! error!) accepted integer
argument (data1), that was passed to callback function verbatim. In all
call sites this argument was 0.

With this change, that data1 argument is no longer part of macro
interface, 0 is always passed to callback in internals of these macros.
2019-09-10 22:26:47 +00:00
Dmitry Bogatov
2dd3f169db Use set_config_bool instead of set_config_int in boolean context 2019-09-10 22:26:47 +00:00
Dmitry Bogatov
b97b618b4b Use sql.get_config_bool to simplify dc_is_configured 2019-09-10 22:26:47 +00:00
Dmitry Bogatov
bb12488200 Add Sql.{set,get}_config_bool methods
Previously, boolean configurations were implemented on top of i32
(get_config_int, set_config_it) at call sites.

Having one canonical location, containing boolean <-> database
conversion may help to avoid serialization issues.
2019-09-10 22:26:47 +00:00
Alexander Krotov
706a97b013 Move part of test_encryption_decryption to key.rs 2019-09-11 00:40:46 +03:00
Dmitry Bogatov
1cdb9c733a Change return type of `dc_is_configured' to bool 2019-09-10 19:08:55 +00:00
holger krekel
ffc525af9e pragmatismatic: run flaky tests three times to see if we can get more "green" CI runs this way ...
thanks to @the-compiler also modernize plugin usage
2019-09-10 20:51:52 +02:00
Dmitry Bogatov
1576dc1d13 top_evil_rs: check for all-caps version of ok_to_continue pattern 2019-09-10 17:34:17 +00:00
Dmitry Bogatov
4fbb5fbb25 Make it easier to run src/top_evil_rs.py from git root
Currently, `src/top_evil_rs.py' script recursively scans current
directory for Rust sources and print statistics about them.

When run from git root, it also scans target/ directory, which is
useless.

This commit add cludge that checks if script is run from git root
directory, and `chdir' into `src/' before performing actions.

Unprincipled, but convenient.
2019-09-10 17:34:16 +00:00
B. Petersen
e9da21a02e cargo fmt 2019-09-10 19:14:51 +02:00
B. Petersen
6c4d7ad8cc do not panic on bad-utf-8 2019-09-10 16:48:54 +02:00
Alexander Krotov
f1c026c5ec Pass passphrase to dc_pgp_symm_{en,de}crypt as &str 2019-09-10 15:58:42 +02:00
björn petersen
3d61c06ea9 Merge pull request #478 from deltachat/fix477
fix crash when msg_raw is None
2019-09-10 15:50:33 +02:00
Alexander Krotov
22c1ee1f55 cargo fmt 2019-09-10 16:29:41 +03:00
Alexander Krotov
971960a242 key.rs: remove unsafe Key.from_binary 2019-09-10 16:29:24 +03:00
Alexander Krotov
69f8973339 test_encryption_decryption: use safe from_slice instead of from_binary 2019-09-10 16:29:24 +03:00
B. Petersen
bf1d9b6d06 fix crash when msg_raw is None 2019-09-10 15:20:38 +02:00
Alexander Krotov
6a2368f83c Return bool from dc_continue_key_transfer 2019-09-10 15:15:48 +02:00
Alexander Krotov
d0960f7f7f Merge pull request #483 from link2xt/dc_msg_exists_safe
Make dc_msg_exists safe and rusty
2019-09-10 15:15:33 +03:00
Alexander Krotov
e5ad697466 Make dc_msg_exists safe and rusty 2019-09-10 14:21:27 +03:00
Alexander Krotov
188eab5faf Fix test_encryption_decryption
It is broken since 28cae607a4
2019-09-10 12:00:59 +02:00
37 changed files with 1060 additions and 1164 deletions

View File

@@ -41,7 +41,8 @@ if [ -n "$TESTS" ]; then
# see https://github.com/deltachat/deltachat-core-rust/issues/331
# unset DCC_PY_LIVECONFIG
tox --workdir "$TOXWORKDIR" -e lint,py35,py36,py37,auditwheels
tox --workdir "$TOXWORKDIR" -e lint,py35,py36,py37,auditwheels -- -k "not qr"
tox --workdir "$TOXWORKDIR" -e py35,py36,py37 -- -k "qr"
popd
fi

File diff suppressed because it is too large Load Diff

View File

@@ -28,10 +28,10 @@ use num_traits::FromPrimitive;
/// Argument is a bitmask, executing single or multiple actions in one call.
/// e.g. bitmask 7 triggers actions definded with bits 1, 2 and 4.
pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
info!(context, 0, "Resetting tables ({})...", bits);
info!(context, "Resetting tables ({})...", bits);
if 0 != bits & 1 {
sql::execute(context, &context.sql, "DELETE FROM jobs;", params![]).unwrap();
info!(context, 0, "(1) Jobs reset.");
info!(context, "(1) Jobs reset.");
}
if 0 != bits & 2 {
sql::execute(
@@ -41,11 +41,11 @@ pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
params![],
)
.unwrap();
info!(context, 0, "(2) Peerstates reset.");
info!(context, "(2) Peerstates reset.");
}
if 0 != bits & 4 {
sql::execute(context, &context.sql, "DELETE FROM keypairs;", params![]).unwrap();
info!(context, 0, "(4) Private keypairs reset.");
info!(context, "(4) Private keypairs reset.");
}
if 0 != bits & 8 {
sql::execute(
@@ -84,7 +84,7 @@ pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
)
.unwrap();
sql::execute(context, &context.sql, "DELETE FROM leftgrps;", params![]).unwrap();
info!(context, 0, "(8) Rest but server config reset.");
info!(context, "(8) Rest but server config reset.");
}
context.call_cb(Event::MSGS_CHANGED, 0, 0);
@@ -122,7 +122,7 @@ unsafe fn dc_poke_eml_file(context: &Context, filename: *const libc::c_char) ->
/// @return 1=success, 0=error.
unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int {
if !context.sql.is_open() {
error!(context, 0, "Import: Database not opened.");
error!(context, "Import: Database not opened.");
return 0;
}
@@ -143,7 +143,7 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
} else {
let rs = context.sql.get_config(context, "import_spec");
if rs.is_none() {
error!(context, 0, "Import: No file or folder given.");
error!(context, "Import: No file or folder given.");
ok_to_continue = false;
} else {
ok_to_continue = true;
@@ -166,7 +166,6 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
if dir.is_err() {
error!(
context,
0,
"Import: Cannot open directory \"{}\".",
as_str(real_spec),
);
@@ -182,7 +181,7 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
let name = name_f.to_string_lossy();
if name.ends_with(".eml") {
let path_plus_name = format!("{}/{}", as_str(real_spec), name);
info!(context, 0, "Import: {}", path_plus_name);
info!(context, "Import: {}", path_plus_name);
let path_plus_name_c = CString::yolo(path_plus_name);
if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
read_cnt += 1
@@ -195,7 +194,6 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
if ok_to_continue2 {
info!(
context,
0,
"Import: {} items read from \"{}\".",
read_cnt,
as_str(real_spec)
@@ -228,7 +226,6 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
let msgtext = dc_msg_get_text(msg);
info!(
context,
0,
"{}#{}{}{}: {} (Contact#{}): {} {}{}{}{} [{}]",
prefix.as_ref(),
dc_msg_get_id(msg) as libc::c_int,
@@ -268,7 +265,6 @@ unsafe fn log_msglist(context: &Context, msglist: &Vec<u32>) -> Result<(), Error
if msg_id == 9 as libc::c_uint {
info!(
context,
0,
"--------------------------------------------------------------------------------"
);
@@ -276,7 +272,7 @@ unsafe fn log_msglist(context: &Context, msglist: &Vec<u32>) -> Result<(), Error
} else if msg_id > 0 {
if lines_out == 0 {
info!(
context, 0,
context,
"--------------------------------------------------------------------------------",
);
lines_out += 1
@@ -288,7 +284,7 @@ unsafe fn log_msglist(context: &Context, msglist: &Vec<u32>) -> Result<(), Error
if lines_out > 0 {
info!(
context,
0, "--------------------------------------------------------------------------------"
"--------------------------------------------------------------------------------"
);
}
Ok(())
@@ -305,7 +301,7 @@ unsafe fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
if let Ok(contact) = Contact::get_by_id(context, contact_id) {
let name = contact.get_name();
let addr = contact.get_addr();
let verified_state = contact.is_verified();
let verified_state = contact.is_verified(context);
let verified_str = if VerifiedStatus::Unverified != verified_state {
if verified_state == VerifiedStatus::BidirectVerified {
" √√"
@@ -337,7 +333,7 @@ unsafe fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
);
}
info!(context, 0, "Contact#{}: {}{}", contact_id, line, line2);
info!(context, "Contact#{}: {}{}", contact_id, line, line2);
}
}
}
@@ -480,7 +476,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let msg_id: u32 = arg1.parse()?;
let msg = dc_get_msg(context, msg_id)?;
if dc_msg_is_setupmessage(&msg) {
let setupcodebegin = dc_msg_get_setupcodebegin(&msg);
let setupcodebegin = dc_msg_get_setupcodebegin(context, &msg);
println!(
"The setup code for setup message Msg#{} starts with: {}",
msg_id,
@@ -496,7 +492,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()?, arg2_c) {
if !dc_continue_key_transfer(context, arg1.parse()?, arg2_c) {
bail!("Continue key transfer failed");
}
}
@@ -554,9 +550,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
"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 = context.get_config_from_str(&arg1);
println!("{}={:?}", &arg1.to_string(), val);
}
"info" => {
println!("{}", to_string(dc_get_info(context)));
@@ -579,17 +574,16 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let cnt = chatlist.len();
if cnt > 0 {
info!(
context, 0,
context,
"================================================================================"
);
for i in (0..cnt).rev() {
let chat = Chat::load_from_db(context, chatlist.get_chat_id(i))?;
let temp_subtitle = chat.get_subtitle();
let temp_subtitle = chat.get_subtitle(context);
let temp_name = chat.get_name();
info!(
context,
0,
"{}#{}: {} [{}] [{} fresh]",
chat_prefix(&chat),
chat.get_id(),
@@ -597,7 +591,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
temp_subtitle,
chat::get_fresh_msg_cnt(context, chat.get_id()),
);
let lot = chatlist.get_summary(i, Some(&chat));
let lot = chatlist.get_summary(context, i, Some(&chat));
let statestr = if chat.is_archived() {
" [Archived]"
} else {
@@ -614,7 +608,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let text2 = lot.get_text2();
info!(
context,
0,
"{}{}{}{} [{}]{}",
text1.unwrap_or(""),
if text1.is_some() { ": " } else { "" },
@@ -628,13 +621,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
},
);
info!(
context, 0,
context,
"================================================================================"
);
}
}
if location::is_sending_locations_to_chat(context, 0 as uint32_t) {
info!(context, 0, "Location streaming enabled.");
info!(context, "Location streaming enabled.");
}
println!("{} chats", cnt);
}
@@ -653,11 +646,10 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let sel_chat = sel_chat.as_ref().unwrap();
let msglist = chat::get_chat_msgs(context, sel_chat.get_id(), 0x1, 0);
let temp2 = sel_chat.get_subtitle();
let temp2 = sel_chat.get_subtitle(context);
let temp_name = sel_chat.get_name();
info!(
context,
0,
"{}#{}: {} [{}]{}",
chat_prefix(sel_chat),
sel_chat.get_id(),
@@ -753,7 +745,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(sel_chat.is_some(), "No chat selected.");
let contacts = chat::get_chat_contacts(context, sel_chat.as_ref().unwrap().get_id());
info!(context, 0, "Memberlist:");
info!(context, "Memberlist:");
log_contactlist(context, &contacts);
println!(
@@ -781,7 +773,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let marker = location.marker.as_ref().unwrap_or(&default_marker);
info!(
context,
0,
"Loc#{}: {}: lat={} lng={} acc={} Chat#{} Contact#{} Msg#{} {}",
location.location_id,
dc_timestamp_to_str(location.timestamp),
@@ -795,7 +786,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
);
}
if locations.is_empty() {
info!(context, 0, "No locations.");
info!(context, "No locations.");
}
}
"sendlocations" => {
@@ -844,14 +835,11 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(sel_chat.is_some(), "No chat selected.");
ensure!(!arg1.is_empty(), "No file given.");
let mut msg = dc_msg_new(
context,
if arg0 == "sendimage" {
Viewtype::Image
} else {
Viewtype::File
},
);
let mut msg = dc_msg_new(if arg0 == "sendimage" {
Viewtype::Image
} else {
Viewtype::File
});
dc_msg_set_file(&mut msg, arg1_c, ptr::null());
if !arg2.is_empty() {
dc_msg_set_text(&mut msg, arg2_c);
@@ -876,7 +864,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(sel_chat.is_some(), "No chat selected.");
if !arg1.is_empty() {
let mut draft = dc_msg_new(context, Viewtype::Text);
let mut draft = dc_msg_new(Viewtype::Text);
dc_msg_set_text(&mut draft, arg1_c);
chat::set_draft(
context,

View File

@@ -495,7 +495,7 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
configure(&ctx.read().unwrap());
}
"oauth2" => {
if let Some(addr) = ctx.read().unwrap().get_config(config::Config::Addr) {
if let Some(addr) = ctx.read().unwrap().get_config(&config::Config::Addr) {
let oauth2_url = dc_get_oauth2_url(
&ctx.read().unwrap(),
&addr,

View File

@@ -101,7 +101,7 @@ fn main() {
let chats = Chatlist::try_load(&ctx, 0, None, None).unwrap();
for i in 0..chats.len() {
let summary = chats.get_summary(0, None);
let summary = chats.get_summary(&ctx, 0, None);
let text1 = summary.get_text1();
let text2 = summary.get_text2();
println!("chat: {} - {:?} - {:?}", i, text1, text2,);

View File

@@ -65,7 +65,7 @@ Afterwards ``which python`` tells you that it comes out of the "venv"
directory that contains all python install artifacts. Let's first
install test tools::
pip install pytest pytest-timeout requests
pip install pytest pytest-timeout pytest-rerunfailures requests
then cargo-build and install the deltachat bindings::

View File

@@ -16,7 +16,10 @@ passenv =
DCC_PY_LIVECONFIG
deps =
pytest
pytest-faulthandler
pytest-rerunfailures
pytest-timeout
pytest-xdist
auditwheel
pdbpp
requests
@@ -51,11 +54,12 @@ commands =
[pytest]
addopts = -v -rs
addopts = -v -rs --reruns 3 --reruns-delay 2
python_files = tests/test_*.py
norecursedirs = .tox
xfail_strict=true
timeout = 60
timeout = 60
timeout_method = thread
[flake8]
max-line-length = 120

View File

@@ -21,8 +21,7 @@ use std::ptr;
/// and are not updated on database changes;
/// if you want an update, you have to recreate the object.
#[derive(Clone)]
pub struct Chat<'a> {
pub context: &'a Context,
pub struct Chat {
pub id: u32,
pub typ: Chattype,
pub name: String,
@@ -34,8 +33,8 @@ pub struct Chat<'a> {
is_sending_locations: bool,
}
impl<'a> Chat<'a> {
pub fn load_from_db(context: &'a Context, chat_id: u32) -> Result<Self, Error> {
impl Chat {
pub fn load_from_db(context: &Context, chat_id: u32) -> Result<Self, Error> {
let res = context.sql.query_row(
"SELECT c.id,c.type,c.name, c.grpid,c.param,c.archived, \
c.blocked, c.gossiped_timestamp, c.locations_send_until \
@@ -43,7 +42,6 @@ impl<'a> Chat<'a> {
params![chat_id as i32],
|row| {
let c = Chat {
context,
id: row.get(0)?,
typ: row.get(1)?,
name: row.get::<_, String>(2)?,
@@ -65,7 +63,7 @@ impl<'a> Chat<'a> {
_ => {
error!(
context,
0, "chat: failed to load from db {}: {:?}", chat_id, err
"chat: failed to load from db {}: {:?}", chat_id, err
);
Err(err)
}
@@ -73,23 +71,23 @@ impl<'a> Chat<'a> {
Ok(mut chat) => {
match chat.id {
DC_CHAT_ID_DEADDROP => {
chat.name = chat.context.stock_str(StockMessage::DeadDrop).into();
chat.name = context.stock_str(StockMessage::DeadDrop).into();
}
DC_CHAT_ID_ARCHIVED_LINK => {
let tempname = chat.context.stock_str(StockMessage::ArchivedChats);
let cnt = dc_get_archived_cnt(chat.context);
let tempname = context.stock_str(StockMessage::ArchivedChats);
let cnt = dc_get_archived_cnt(context);
chat.name = format!("{} ({})", tempname, cnt);
}
DC_CHAT_ID_STARRED => {
chat.name = chat.context.stock_str(StockMessage::StarredMsgs).into();
chat.name = context.stock_str(StockMessage::StarredMsgs).into();
}
_ => {
if chat.typ == Chattype::Single {
let contacts = get_chat_contacts(chat.context, chat.id);
let contacts = get_chat_contacts(context, chat.id);
let mut chat_name = "Err [Name not found]".to_owned();
if !(*contacts).is_empty() {
if let Ok(contact) = Contact::get_by_id(chat.context, contacts[0]) {
if let Ok(contact) = Contact::get_by_id(context, contacts[0]) {
chat_name = contact.get_display_name().to_owned();
}
}
@@ -98,7 +96,7 @@ impl<'a> Chat<'a> {
}
if chat.param.exists(Param::Selftalk) {
chat.name = chat.context.stock_str(StockMessage::SelfMsg).into();
chat.name = context.stock_str(StockMessage::SelfMsg).into();
}
}
}
@@ -111,10 +109,10 @@ impl<'a> Chat<'a> {
self.param.exists(Param::Selftalk)
}
pub fn update_param(&mut self) -> Result<(), Error> {
pub fn update_param(&mut self, context: &Context) -> Result<(), Error> {
sql::execute(
self.context,
&self.context.sql,
context,
&context.sql,
"UPDATE chats SET param=? WHERE id=?",
params![self.param.to_string(), self.id as i32],
)
@@ -132,22 +130,18 @@ impl<'a> Chat<'a> {
&self.name
}
pub fn get_subtitle(&self) -> String {
pub fn get_subtitle(&self, context: &Context) -> String {
// returns either the address or the number of chat members
if self.typ == Chattype::Single && self.param.exists(Param::Selftalk) {
return self
.context
.stock_str(StockMessage::SelfTalkSubTitle)
.into();
return context.stock_str(StockMessage::SelfTalkSubTitle).into();
}
if self.typ == Chattype::Single {
return self
.context
return context
.sql
.query_row_col(
self.context,
context,
"SELECT c.addr FROM chats_contacts cc \
LEFT JOIN contacts c ON c.id=cc.contact_id \
WHERE cc.chat_id=?;",
@@ -159,11 +153,10 @@ impl<'a> Chat<'a> {
if self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup {
if self.id == 1 {
return self.context.stock_str(StockMessage::DeadDrop).into();
return context.stock_str(StockMessage::DeadDrop).into();
}
let cnt = get_chat_contact_cnt(self.context, self.id);
return self
.context
let cnt = get_chat_contact_cnt(context, self.id);
return context
.stock_string_repl_int(StockMessage::Member, cnt)
.into();
}
@@ -171,10 +164,10 @@ impl<'a> Chat<'a> {
return "Err".into();
}
pub fn get_parent_mime_headers(&self) -> Option<(String, String, String)> {
pub fn get_parent_mime_headers(&self, context: &Context) -> Option<(String, String, String)> {
let collect = |row: &rusqlite::Row| Ok((row.get(0)?, row.get(1)?, row.get(2)?));
let params = params![self.id as i32, DC_CONTACT_ID_SELF as i32];
let sql = &self.context.sql;
let sql = &context.sql;
let main_query = "SELECT rfc724_mid, mime_in_reply_to, mime_references \
FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT max(timestamp) \
FROM msgs WHERE chat_id=?1 AND from_id!=?2);";
@@ -187,16 +180,16 @@ impl<'a> Chat<'a> {
.ok()
}
pub fn get_profile_image(&self) -> Option<PathBuf> {
pub fn get_profile_image(&self, context: &Context) -> Option<PathBuf> {
if let Some(image_rel) = self.param.get(Param::ProfileImage) {
if !image_rel.is_empty() {
return Some(dc_get_abs_path_safe(self.context, image_rel));
return Some(dc_get_abs_path_safe(context, image_rel));
}
} else if self.typ == Chattype::Single {
let contacts = get_chat_contacts(self.context, self.id);
let contacts = get_chat_contacts(context, self.id);
if !contacts.is_empty() {
if let Ok(contact) = Contact::get_by_id(self.context, contacts[0]) {
return contact.get_profile_image();
if let Ok(contact) = Contact::get_by_id(context, contacts[0]) {
return contact.get_profile_image(context);
}
}
}
@@ -204,13 +197,13 @@ impl<'a> Chat<'a> {
None
}
pub fn get_color(&self) -> u32 {
pub fn get_color(&self, context: &Context) -> u32 {
let mut color = 0;
if self.typ == Chattype::Single {
let contacts = get_chat_contacts(self.context, self.id);
let contacts = get_chat_contacts(context, self.id);
if !contacts.is_empty() {
if let Ok(contact) = Contact::get_by_id(self.context, contacts[0]) {
if let Ok(contact) = Contact::get_by_id(context, contacts[0]) {
color = contact.get_color();
}
}
@@ -260,7 +253,7 @@ impl<'a> Chat<'a> {
|| self.typ == Chattype::Group
|| self.typ == Chattype::VerifiedGroup)
{
error!(context, 0, "Cannot send to chat type #{}.", self.typ,);
error!(context, "Cannot send to chat type #{}.", self.typ,);
return Ok(0);
}
@@ -296,7 +289,7 @@ impl<'a> Chat<'a> {
} else {
error!(
context,
0, "Cannot send message, contact for chat #{} not found.", self.id,
"Cannot send message, contact for chat #{} not found.", self.id,
);
return Ok(0);
}
@@ -304,7 +297,7 @@ impl<'a> Chat<'a> {
if self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup {
if self.param.get_int(Param::Unpromoted).unwrap_or_default() == 1 {
self.param.remove(Param::Unpromoted);
self.update_param().unwrap();
self.update_param(context).unwrap();
}
}
}
@@ -338,7 +331,6 @@ impl<'a> Chat<'a> {
if prefer_encrypted != 1 {
info!(
context,
0,
"[autocrypt] peerstate for {} is {}",
state,
if prefer_encrypted == 0 {
@@ -350,7 +342,7 @@ impl<'a> Chat<'a> {
all_mutual = 0;
}
} else {
info!(context, 0, "[autocrypt] no peerstate for {}", state,);
info!(context, "[autocrypt] no peerstate for {}", state,);
can_encrypt = 0;
all_mutual = 0;
}
@@ -360,7 +352,7 @@ impl<'a> Chat<'a> {
match res {
Ok(_) => {}
Err(err) => {
warn!(context, 0, "chat: failed to load peerstates: {:?}", err);
warn!(context, "chat: failed to load peerstates: {:?}", err);
}
}
@@ -378,7 +370,7 @@ impl<'a> Chat<'a> {
msg.param.remove(Param::ErroneousE2ee);
if !self.is_self_talk() {
if let Some((parent_rfc724_mid, parent_in_reply_to, parent_references)) =
self.get_parent_mime_headers()
self.get_parent_mime_headers(context)
{
if !parent_rfc724_mid.is_empty() {
new_in_reply_to = parent_rfc724_mid.clone();
@@ -464,13 +456,12 @@ impl<'a> Chat<'a> {
} else {
error!(
context,
0,
"Cannot send message, cannot insert to database (chat #{}).",
self.id,
);
}
} else {
error!(context, 0, "Cannot send message, not configured.",);
error!(context, "Cannot send message, not configured.",);
}
Ok(msg_id)
@@ -541,7 +532,7 @@ pub fn create_by_contact_id(context: &Context, contact_id: u32) -> Result<u32, E
{
warn!(
context,
0, "Cannot create chat, contact {} does not exist.", contact_id,
"Cannot create chat, contact {} does not exist.", contact_id,
);
return Err(err);
} else {
@@ -637,7 +628,7 @@ pub fn get_by_contact_id(context: &Context, contact_id: u32) -> Result<u32, Erro
pub fn prepare_msg<'a>(
context: &'a Context,
chat_id: u32,
msg: &mut Message<'a>,
msg: &mut Message,
) -> Result<u32, Error> {
ensure!(
chat_id > DC_CHAT_ID_LAST_SPECIAL,
@@ -667,13 +658,8 @@ pub fn msgtype_has_file(msgtype: Viewtype) -> bool {
}
}
fn prepare_msg_common<'a>(
context: &'a Context,
chat_id: u32,
msg: &mut Message<'a>,
) -> Result<u32, Error> {
fn prepare_msg_common(context: &Context, chat_id: u32, msg: &mut Message) -> Result<u32, Error> {
msg.id = 0;
msg.context = context;
if msg.type_0 == Viewtype::Text {
// the caller should check if the message text is empty
@@ -718,7 +704,7 @@ fn prepare_msg_common<'a>(
}
info!(
context,
0, "Attaching \"{}\" for message type #{}.", &path_filename, msg.type_0
"Attaching \"{}\" for message type #{}.", &path_filename, msg.type_0
);
} else {
bail!("Cannot send messages of type #{}.", msg.type_0);
@@ -751,7 +737,7 @@ fn last_msg_in_chat_encrypted(context: &Context, sql: &Sql, chat_id: u32) -> boo
match packed.parse::<Params>() {
Ok(param) => param.exists(Param::GuranteeE2ee),
Err(err) => {
error!(context, 0, "invalid params stored: '{}', {:?}", packed, err);
error!(context, "invalid params stored: '{}', {:?}", packed, err);
false
}
}
@@ -789,11 +775,7 @@ pub fn unarchive(context: &Context, chat_id: u32) -> Result<(), Error> {
/// However, this does not imply, the message really reached the recipient -
/// sending may be delayed eg. due to network problems. However, from your
/// view, you're done with the message. Sooner or later it will find its way.
pub fn send_msg<'a>(
context: &'a Context,
chat_id: u32,
msg: &mut Message<'a>,
) -> Result<u32, Error> {
pub fn send_msg(context: &Context, chat_id: u32, msg: &mut Message) -> Result<u32, Error> {
if msg.state != MessageState::OutPreparing {
// automatically prepare normal messages
prepare_msg_common(context, chat_id, msg)?;
@@ -837,7 +819,7 @@ pub fn send_msg<'a>(
}
}
msg.param.remove(Param::PrepForwards);
dc_msg_save_param_to_disk(msg);
dc_msg_save_param_to_disk(context, msg);
}
}
@@ -855,7 +837,7 @@ pub unsafe fn send_text_msg(
chat_id
);
let mut msg = dc_msg_new(context, Viewtype::Text);
let mut msg = dc_msg_new(Viewtype::Text);
msg.text = Some(text_to_send);
send_msg(context, chat_id, &mut msg)
}
@@ -1297,7 +1279,7 @@ pub unsafe fn create_group_chat(
if chat_id != 0 {
if 0 != add_to_chat_contacts_table(context, chat_id, 1) {
let mut draft_msg = dc_msg_new(context, Viewtype::Text);
let mut draft_msg = dc_msg_new(Viewtype::Text);
dc_msg_set_text(&mut draft_msg, draft_txt.as_ptr());
set_draft_raw(context, chat_id, Some(&mut draft_msg));
}
@@ -1342,7 +1324,7 @@ pub fn add_contact_to_chat_ex(
if contact.is_err() || chat_id <= DC_CHAT_ID_LAST_SPECIAL {
return 0;
}
let mut msg = unsafe { dc_msg_new_untyped(context) };
let mut msg = dc_msg_new_untyped();
reset_gossiped_timestamp(context, chat_id);
let contact = contact.unwrap();
@@ -1365,7 +1347,7 @@ pub fn add_contact_to_chat_ex(
&& chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 1
{
chat.param.remove(Param::Unpromoted);
chat.update_param().unwrap();
chat.update_param(context).unwrap();
}
let self_addr = context
.sql
@@ -1383,9 +1365,9 @@ pub fn add_contact_to_chat_ex(
} else {
// else continue and send status mail
if chat.typ == Chattype::VerifiedGroup {
if contact.is_verified() != VerifiedStatus::BidirectVerified {
if contact.is_verified(context) != VerifiedStatus::BidirectVerified {
error!(
context, 0,
context,
"Only bidirectional verified contacts can be added to verified groups."
);
OK_TO_CONTINUE = false;
@@ -1451,7 +1433,7 @@ pub fn set_gossiped_timestamp(context: &Context, chat_id: u32, timestamp: i64) {
if 0 != chat_id {
info!(
context,
0, "set gossiped_timestamp for chat #{} to {}.", chat_id, timestamp,
"set gossiped_timestamp for chat #{} to {}.", chat_id, timestamp,
);
sql::execute(
@@ -1464,7 +1446,7 @@ pub fn set_gossiped_timestamp(context: &Context, chat_id: u32, timestamp: i64) {
} else {
info!(
context,
0, "set gossiped_timestamp for all chats to {}.", timestamp,
"set gossiped_timestamp for all chats to {}.", timestamp,
);
sql::execute(
context,
@@ -1491,7 +1473,7 @@ pub unsafe fn remove_contact_from_chat(
"Cannot remove special contact"
);
let mut msg = dc_msg_new_untyped(context);
let mut msg = dc_msg_new_untyped();
let mut success = false;
/* we do not check if "contact_id" exists but just delete all records with the id from chats_contacts */
@@ -1590,7 +1572,7 @@ pub unsafe fn set_chat_name(
ensure!(chat_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat ID");
let chat = Chat::load_from_db(context, chat_id)?;
let mut msg = dc_msg_new_untyped(context);
let mut msg = dc_msg_new_untyped();
if real_group_exists(context, chat_id) {
if &chat.name == new_name.as_ref() {
@@ -1684,9 +1666,9 @@ pub fn set_chat_profile_image(
}
chat.param.set(Param::ProfileImage, &new_image_rel);
if chat.update_param().is_ok() {
if chat.update_param(context).is_ok() {
if chat.is_promoted() {
let mut msg = unsafe { dc_msg_new_untyped(context) };
let mut msg = dc_msg_new_untyped();
msg.param.set_int(Param::Cmd, DC_CMD_GROUPIMAGE_CHANGED);
msg.type_0 = Viewtype::Text;
msg.text = Some(context.stock_system_msg(
@@ -1781,7 +1763,7 @@ pub unsafe fn forward_msgs(
msg.param.set(Param::PrepForwards, new_msg_id.to_string());
}
dc_msg_save_param_to_disk(&mut msg);
dc_msg_save_param_to_disk(context, &mut msg);
msg.param = save_param;
} else {
msg.state = MessageState::OutPending;

View File

@@ -31,17 +31,12 @@ use crate::stock::StockMessage;
/// first entry and only present on new messages, there is the rough idea that it can be optionally always
/// present and sorted into the list by date. Rendering the deaddrop in the described way
/// would not add extra work in the UI then.
pub struct Chatlist<'a> {
context: &'a Context,
pub struct Chatlist {
/// Stores pairs of `chat_id, message_id`
ids: Vec<(u32, u32)>,
}
impl<'a> Chatlist<'a> {
pub fn get_context(&self) -> &Context {
self.context
}
impl Chatlist {
/// Get a list of chats.
/// The list can be filtered by query parameters.
///
@@ -85,7 +80,7 @@ impl<'a> Chatlist<'a> {
/// `query_contact_id`: An optional contact ID for filtering the list. Only chats including this contact ID
/// are returned.
pub fn try_load(
context: &'a Context,
context: &Context,
listflags: usize,
query: Option<&str>,
query_contact_id: Option<u32>,
@@ -200,7 +195,7 @@ impl<'a> Chatlist<'a> {
ids.push((DC_CHAT_ID_ARCHIVED_LINK, 0));
}
Ok(Chatlist { context, ids })
Ok(Chatlist { ids })
}
/// Find out the number of chats.
@@ -247,7 +242,7 @@ impl<'a> Chatlist<'a> {
/// - dc_lot_t::timestamp: the timestamp of the message. 0 if not applicable.
/// - dc_lot_t::state: The state of the message as one of the DC_STATE_* constants (see #dc_msg_get_state()).
// 0 if not applicable.
pub fn get_summary(&self, index: usize, chat: Option<&Chat<'a>>) -> Lot {
pub fn get_summary(&self, context: &Context, index: usize, chat: Option<&Chat>) -> Lot {
// The summary is created by the chat, not by the last message.
// This is because we may want to display drafts here or stuff as
// "is typing".
@@ -263,7 +258,7 @@ impl<'a> Chatlist<'a> {
let chat = if let Some(chat) = chat {
chat
} else {
if let Ok(chat) = Chat::load_from_db(self.context, self.ids[index].0) {
if let Ok(chat) = Chat::load_from_db(context, self.ids[index].0) {
chat_loaded = chat;
&chat_loaded
} else {
@@ -275,11 +270,11 @@ impl<'a> Chatlist<'a> {
let mut lastcontact = None;
let lastmsg = if 0 != lastmsg_id {
if let Ok(lastmsg) = dc_msg_load_from_db(self.context, lastmsg_id) {
if let Ok(lastmsg) = dc_msg_load_from_db(context, lastmsg_id) {
if lastmsg.from_id != 1 as libc::c_uint
&& (chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup)
{
lastcontact = Contact::load_from_db(self.context, lastmsg.from_id).ok();
lastcontact = Contact::load_from_db(context, lastmsg.from_id).ok();
}
Some(lastmsg)
@@ -294,14 +289,9 @@ impl<'a> Chatlist<'a> {
ret.text2 = None;
} else if lastmsg.is_none() || lastmsg.as_ref().unwrap().from_id == DC_CONTACT_ID_UNDEFINED
{
ret.text2 = Some(self.context.stock_str(StockMessage::NoMessages).to_string());
ret.text2 = Some(context.stock_str(StockMessage::NoMessages).to_string());
} else {
ret.fill(
&mut lastmsg.unwrap(),
chat,
lastcontact.as_ref(),
self.context,
);
ret.fill(&mut lastmsg.unwrap(), chat, lastcontact.as_ref(), context);
}
ret

View File

@@ -1,3 +1,5 @@
use std::str::FromStr;
use strum::{EnumProperty, IntoEnumIterator};
use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
@@ -8,9 +10,11 @@ use crate::error::Error;
use crate::job::*;
use crate::stock::StockMessage;
pub const CONFIG_UI_PREFIX: &str = "ui.";
/// The available configuration keys.
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Display, EnumString, AsRefStr, EnumIter, EnumProperty,
Debug, Clone, PartialEq, Eq, Display, EnumString, AsRefStr, EnumIter, EnumProperty,
)]
#[strum(serialize_all = "snake_case")]
pub enum Config {
@@ -65,11 +69,17 @@ pub enum Config {
SysMsgsizeMaxRecommended,
#[strum(serialize = "sys.config_keys")]
SysConfigKeys,
Ui(String)
}
impl Context {
pub fn get_config_from_str(&self, key: &str) -> Option<String> {
self.get_config(&config_from_str(key))
}
/// 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> {
pub fn get_config(&self, key: &Config) -> Option<String> {
let value = match key {
Config::Selfavatar => {
let rel_path = self.sql.get_config(self, key);
@@ -78,6 +88,7 @@ impl Context {
Config::SysVersion => Some((&*DC_VERSION_STR).clone()),
Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)),
Config::SysConfigKeys => Some(get_config_keys_string()),
Config::Ui(key) => self.sql.get_config(self, format!("{}{}", CONFIG_UI_PREFIX, key)),
_ => self.sql.get_config(self, key),
};
@@ -92,6 +103,13 @@ impl Context {
}
}
pub fn set_config_from_str(&self, key: &str, value: Option<&str>) -> Result<(), &str> {
if self.sql.set_config(self, config_from_str(key), value).is_err() {
return Err("Sql error");
}
Ok(())
}
/// 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> {
@@ -125,7 +143,11 @@ impl Context {
};
self.sql.set_config(self, key, val)
}
},
Config::Ui(key) => {
let key = format!("{}{}", CONFIG_UI_PREFIX, key);
self.sql.set_config(self, key, value)
},
_ => self.sql.set_config(self, key, value),
}
}
@@ -142,12 +164,23 @@ fn get_config_keys_string() -> String {
format!(" {} ", keys)
}
fn config_from_str(key: &str) -> Result<Config, &str> {
if key.starts_with(CONFIG_UI_PREFIX) {
Config::Ui(key[CONFIG_UI_PREFIX.len()-1..].to_string())
} else {
if let Ok(config) = Config::from_str(key) {
config
} else {
Err("invalid key")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use std::string::ToString;
use crate::test_utils::*;
#[test]
fn test_to_string() {
@@ -165,4 +198,20 @@ mod tests {
fn test_default_prop() {
assert_eq!(Config::ImapFolder.get_str("default"), Some("INBOX"));
}
#[test]
fn test_config_from_str() {
assert_eq!(config_from_str("addr"), Config::Addr);
assert_eq!(config_from_str("addrxyz"), None);
}
#[test]
fn test_get_config_from_str() {
let t = dummy_context();
assert_eq!(t.ctx.set_config_from_str("addr", Some("foo@bar.bar")), Ok(()));
assert_eq!(t.ctx.get_config_from_str("addr").unwrap(), "foo@bar.bar");
assert_eq!(t.ctx.set_config_from_str("ui.desktop.some_string", Some("foobar")), Ok(()));
assert_eq!(t.ctx.get_config_from_str("ui.desktop.some_string").unwrap(), "foobar");
}
}

View File

@@ -69,7 +69,6 @@ pub unsafe fn moz_autoconfigure(
Err(e) => {
error!(
context,
0,
"Configure xml: Error at position {}: {:?}",
reader.buffer_position(),
e
@@ -87,7 +86,7 @@ pub unsafe fn moz_autoconfigure(
|| moz_ac.out.send_port == 0
{
let r = moz_ac.out.to_string();
warn!(context, 0, "Bad or incomplete autoconfig: {}", r,);
warn!(context, "Bad or incomplete autoconfig: {}", r,);
free(xml_raw as *mut libc::c_void);
return None;
}

View File

@@ -75,7 +75,6 @@ pub unsafe fn outlk_autodiscover(
Err(e) => {
error!(
context,
0,
"Configure xml: Error at position {}: {:?}",
reader.buffer_position(),
e
@@ -109,7 +108,7 @@ pub unsafe fn outlk_autodiscover(
|| outlk_ad.out.send_port == 0
{
let r = outlk_ad.out.to_string();
warn!(context, 0, "Bad or incomplete autoconfig: {}", r,);
warn!(context, "Bad or incomplete autoconfig: {}", r,);
free(url as *mut libc::c_void);
free(xml_raw as *mut libc::c_void);
outlk_clean_config(&mut outlk_ad);

View File

@@ -34,10 +34,7 @@ macro_rules! progress {
// connect
pub unsafe fn configure(context: &Context) {
if dc_has_ongoing(context) {
warn!(
context,
0, "There is already another ongoing process running.",
);
warn!(context, "There is already another ongoing process running.",);
return;
}
job_kill_action(context, Action::ConfigureImap);
@@ -45,17 +42,8 @@ pub unsafe fn configure(context: &Context) {
}
/// Check if the context is already configured.
pub fn dc_is_configured(context: &Context) -> libc::c_int {
if context
.sql
.get_config_int(context, "configured")
.unwrap_or_default()
> 0
{
1
} else {
0
}
pub fn dc_is_configured(context: &Context) -> bool {
context.sql.get_config_bool(context, "configured")
}
/*******************************************************************************
@@ -73,7 +61,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
if dc_alloc_ongoing(context) {
ongoing_allocated_here = true;
if !context.sql.is_open() {
error!(context, 0, "Cannot configure, database not opened.",);
error!(context, "Cannot configure, database not opened.",);
} else {
context.inbox.read().unwrap().disconnect(context);
context
@@ -89,7 +77,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
.imap
.disconnect(context);
context.smtp.clone().lock().unwrap().disconnect();
info!(context, 0, "Configure ...",);
info!(context, "Configure ...",);
let s_a = context.running_state.clone();
let s = s_a.read().unwrap();
@@ -113,7 +101,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
1 => {
progress!(context, 1);
if param.addr.is_empty() {
error!(context, 0, "Please enter an email address.",);
error!(context, "Please enter an email address.",);
}
!param.addr.is_empty()
}
@@ -146,7 +134,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
utf8_percent_encode(&param.addr, NON_ALPHANUMERIC).to_string();
true
} else {
error!(context, 0, "Bad email-address.");
error!(context, "Bad email-address.");
false
}
}
@@ -256,7 +244,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
12 => {
progress!(context, 500);
if let Some(ref cfg) = param_autoconfig {
info!(context, 0, "Got autoconfig: {}", &cfg);
info!(context, "Got autoconfig: {}", &cfg);
if !cfg.mail_user.is_empty() {
param.mail_user = cfg.mail_user.clone();
}
@@ -340,7 +328,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
|| param.send_pw.is_empty()
|| param.server_flags == 0
{
error!(context, 0, "Account settings incomplete.");
error!(context, "Account settings incomplete.");
false
} else {
true
@@ -357,7 +345,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
ok_to_continue8 = true;
break;
}
info!(context, 0, "Trying: {}", &param);
info!(context, "Trying: {}", &param);
if context.inbox.read().unwrap().connect(context, &param) {
ok_to_continue8 = true;
@@ -375,7 +363,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
progress!(context, 650 + username_variation * 30);
param.server_flags &= !(0x100 | 0x200 | 0x400);
param.server_flags |= 0x100;
info!(context, 0, "Trying: {}", &param);
info!(context, "Trying: {}", &param);
if context.inbox.read().unwrap().connect(context, &param) {
ok_to_continue8 = true;
@@ -388,7 +376,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
}
progress!(context, 660 + username_variation * 30);
param.mail_port = 143;
info!(context, 0, "Trying: {}", &param);
info!(context, "Trying: {}", &param);
if context.inbox.read().unwrap().connect(context, &param) {
ok_to_continue8 = true;
@@ -443,7 +431,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
param.server_flags &= !(0x10000 | 0x20000 | 0x40000);
param.server_flags |= 0x10000;
param.send_port = 587;
info!(context, 0, "Trying: {}", &param);
info!(context, "Trying: {}", &param);
if !context
.smtp
@@ -459,7 +447,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
param.server_flags &= !(0x10000 | 0x20000 | 0x40000);
param.server_flags |= 0x10000;
param.send_port = 25;
info!(context, 0, "Trying: {}", &param);
info!(context, "Trying: {}", &param);
if !context
.smtp
@@ -518,7 +506,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
)
.ok();
context.sql.set_config_int(context, "configured", 1).ok();
context.sql.set_config_bool(context, "configured", true);
true
}
18 => {
@@ -528,13 +516,13 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
// (~30 seconds on a Moto G4 play) and might looks as if message sending is always that slow.
e2ee::ensure_secret_key_exists(context);
success = true;
info!(context, 0, "Configure completed.");
info!(context, "Configure completed.");
progress!(context, 940);
break; // We are done here
}
_ => {
error!(context, 0, "Internal error: step counter out of bound",);
error!(context, "Internal error: step counter out of bound",);
break;
}
};
@@ -582,10 +570,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
pub fn dc_alloc_ongoing(context: &Context) -> bool {
if dc_has_ongoing(context) {
warn!(
context,
0, "There is already another ongoing process running.",
);
warn!(context, "There is already another ongoing process running.",);
false
} else {
@@ -628,7 +613,7 @@ pub fn dc_connect_to_configured_imap(context: &Context, imap: &Imap) -> libc::c_
.unwrap_or_default()
== 0
{
warn!(context, 0, "Not configured, cannot connect.",);
warn!(context, "Not configured, cannot connect.",);
} else {
let param = LoginParam::from_database(context, "configured_");
// the trailing underscore is correct
@@ -651,15 +636,15 @@ pub fn dc_stop_ongoing_process(context: &Context) {
let mut s = s_a.write().unwrap();
if s.ongoing_running && !s.shall_stop_ongoing {
info!(context, 0, "Signaling the ongoing process to stop ASAP.",);
info!(context, "Signaling the ongoing process to stop ASAP.",);
s.shall_stop_ongoing = true;
} else {
info!(context, 0, "No ongoing process to stop.",);
info!(context, "No ongoing process to stop.",);
};
}
pub fn read_autoconf_file(context: &Context, url: &str) -> *mut libc::c_char {
info!(context, 0, "Testing {} ...", url);
info!(context, "Testing {} ...", url);
match reqwest::Client::new()
.get(url)
@@ -668,7 +653,7 @@ pub fn read_autoconf_file(context: &Context, url: &str) -> *mut libc::c_char {
{
Ok(res) => unsafe { res.strdup() },
Err(_err) => {
info!(context, 0, "Can\'t read file.",);
info!(context, "Can\'t read file.",);
std::ptr::null_mut()
}

View File

@@ -31,8 +31,7 @@ const DC_ORIGIN_MIN_CONTACT_LIST: i32 = 0x100;
/// For this purpose, internally, two names are tracked -
/// authorized-name and given-name.
/// By default, these names are equal, but functions working with contact names
pub struct Contact<'a> {
context: &'a Context,
pub struct Contact {
/// The contact ID.
///
/// Special message IDs:
@@ -139,16 +138,15 @@ pub enum VerifiedStatus {
BidirectVerified = 2,
}
impl<'a> Contact<'a> {
pub fn load_from_db(context: &'a Context, contact_id: u32) -> Result<Self> {
impl Contact {
pub fn load_from_db(context: &Context, contact_id: u32) -> Result<Self> {
if contact_id == DC_CONTACT_ID_SELF {
let contact = Contact {
context,
id: contact_id,
name: context.stock_str(StockMessage::SelfMsg).into(),
authname: "".into(),
addr: context
.get_config(Config::ConfiguredAddr)
.get_config(&Config::ConfiguredAddr)
.unwrap_or_default(),
blocked: false,
origin: Origin::Unknown,
@@ -162,7 +160,6 @@ impl<'a> Contact<'a> {
params![contact_id as i32],
|row| {
let contact = Self {
context,
id: contact_id,
name: row.get::<_, String>(0)?,
authname: row.get::<_, String>(4)?,
@@ -181,7 +178,7 @@ impl<'a> Contact<'a> {
}
/// Check if a contact is blocked.
pub fn is_blocked_load(context: &'a Context, id: u32) -> bool {
pub fn is_blocked_load(context: &Context, id: u32) -> bool {
Self::load_from_db(context, id)
.map(|contact| contact.blocked)
.unwrap_or_default()
@@ -260,7 +257,7 @@ impl<'a> Contact<'a> {
let addr_normalized = addr_normalize(addr.as_ref());
let addr_self = context
.get_config(Config::ConfiguredAddr)
.get_config(&Config::ConfiguredAddr)
.unwrap_or_default();
if addr_normalized == addr_self {
@@ -298,7 +295,7 @@ impl<'a> Contact<'a> {
let addr = addr_normalize(addr.as_ref());
let addr_self = context
.get_config(Config::ConfiguredAddr)
.get_config(&Config::ConfiguredAddr)
.unwrap_or_default();
if addr == addr_self {
@@ -308,7 +305,6 @@ impl<'a> Contact<'a> {
if !may_be_valid_addr(&addr) {
warn!(
context,
0,
"Bad address \"{}\" for contact \"{}\".",
addr,
if !name.as_ref().is_empty() {
@@ -404,7 +400,7 @@ impl<'a> Contact<'a> {
row_id = sql::get_rowid(context, &context.sql, "contacts", "addr", addr);
sth_modified = Modifier::Created;
} else {
error!(context, 0, "Cannot add contact.");
error!(context, "Cannot add contact.");
}
}
@@ -460,7 +456,7 @@ impl<'a> Contact<'a> {
query: Option<impl AsRef<str>>,
) -> Result<Vec<u32>> {
let self_addr = context
.get_config(Config::ConfiguredAddr)
.get_config(&Config::ConfiguredAddr)
.unwrap_or_default();
let mut add_self = false;
@@ -503,7 +499,7 @@ impl<'a> Contact<'a> {
},
)?;
let self_name = context.get_config(Config::Displayname).unwrap_or_default();
let self_name = context.get_config(&Config::Displayname).unwrap_or_default();
let self_name2 = context.stock_str(StockMessage::SelfMsg);
if let Some(query) = query {
@@ -683,7 +679,7 @@ impl<'a> Contact<'a> {
return Ok(());
}
Err(err) => {
error!(context, 0, "delete_contact {} failed ({})", contact_id, err);
error!(context, "delete_contact {} failed ({})", contact_id, err);
return Err(err);
}
}
@@ -691,7 +687,7 @@ impl<'a> Contact<'a> {
info!(
context,
0, "could not delete contact {}, there are {} messages with it", contact_id, count_msgs
"could not delete contact {}, there are {} messages with it", contact_id, count_msgs
);
bail!("Could not delete contact with messages in it");
}
@@ -767,9 +763,9 @@ impl<'a> Contact<'a> {
/// Get the contact's profile image.
/// This is the image set by each remote user on their own
/// using dc_set_config(context, "selfavatar", image).
pub fn get_profile_image(&self) -> Option<PathBuf> {
pub fn get_profile_image(&self, context: &Context) -> Option<PathBuf> {
if self.id == DC_CONTACT_ID_SELF {
if let Some(p) = self.context.get_config(Config::Selfavatar) {
if let Some(p) = context.get_config(&Config::Selfavatar) {
return Some(PathBuf::from(p));
}
}
@@ -790,14 +786,18 @@ impl<'a> Contact<'a> {
///
/// The UI may draw a checkbox or something like that beside verified contacts.
///
pub fn is_verified(&self) -> VerifiedStatus {
self.is_verified_ex(None)
pub fn is_verified(&self, context: &Context) -> VerifiedStatus {
self.is_verified_ex(context, None)
}
/// Same as `Contact::is_verified` but allows speeding up things
/// by adding the peerstate belonging to the contact.
/// If you do not have the peerstate available, it is loaded automatically.
pub fn is_verified_ex(&self, peerstate: Option<&Peerstate<'a>>) -> VerifiedStatus {
pub fn is_verified_ex(
&self,
context: &Context,
peerstate: Option<&Peerstate>,
) -> VerifiedStatus {
// We're always sort of secured-verified as we could verify the key on this device any time with the key
// on this device
if self.id == DC_CONTACT_ID_SELF {
@@ -810,7 +810,7 @@ impl<'a> Contact<'a> {
}
}
let peerstate = Peerstate::from_addr(self.context, &self.context.sql, &self.addr);
let peerstate = Peerstate::from_addr(context, &context.sql, &self.addr);
if let Some(ps) = peerstate {
if ps.verified_key().is_some() {
return VerifiedStatus::BidirectVerified;
@@ -1026,7 +1026,7 @@ pub fn addr_cmp(addr1: impl AsRef<str>, addr2: impl AsRef<str>) -> bool {
pub fn addr_equals_self(context: &Context, addr: impl AsRef<str>) -> bool {
if !addr.as_ref().is_empty() {
let normalized_addr = addr_normalize(addr.as_ref());
if let Some(self_addr) = context.get_config(Config::ConfiguredAddr) {
if let Some(self_addr) = context.get_config(&Config::ConfiguredAddr) {
return normalized_addr == self_addr;
}
}

View File

@@ -208,17 +208,11 @@ unsafe fn cb_precheck_imf(
if *old_server_folder.offset(0isize) as libc::c_int == 0i32
&& old_server_uid == 0i32 as libc::c_uint
{
info!(
context,
0,
"[move] detected bbc-self {}",
as_str(rfc724_mid),
);
info!(context, "[move] detected bbc-self {}", as_str(rfc724_mid),);
mark_seen = 1i32
} else if as_str(old_server_folder) != server_folder {
info!(
context,
0,
"[move] detected moved message {}",
as_str(rfc724_mid),
);
@@ -258,16 +252,16 @@ fn cb_get_config(context: &Context, key: &str) -> Option<String> {
}
pub unsafe fn dc_close(context: &Context) {
info!(context, 0, "disconnecting INBOX-watch",);
info!(context, "disconnecting INBOX-watch",);
context.inbox.read().unwrap().disconnect(context);
info!(context, 0, "disconnecting sentbox-thread",);
info!(context, "disconnecting sentbox-thread",);
context
.sentbox_thread
.read()
.unwrap()
.imap
.disconnect(context);
info!(context, 0, "disconnecting mvbox-thread",);
info!(context, "disconnecting mvbox-thread",);
context
.mvbox_thread
.read()
@@ -275,7 +269,7 @@ pub unsafe fn dc_close(context: &Context) {
.imap
.disconnect(context);
info!(context, 0, "disconnecting SMTP");
info!(context, "disconnecting SMTP");
context.smtp.clone().lock().unwrap().disconnect();
context.sql.close(context);

View File

@@ -58,7 +58,6 @@ pub unsafe fn dc_imex_has_backup(
if dir_iter.is_err() {
info!(
context,
0,
"Backup check: Cannot open directory \"{}\".\x00",
dir_name.display(),
);
@@ -92,7 +91,7 @@ pub unsafe fn dc_imex_has_backup(
Some(path) => match path.to_c_string() {
Ok(cstr) => dc_strdup(cstr.as_ptr()),
Err(err) => {
error!(context, 0, "Invalid backup filename: {}", err);
error!(context, "Invalid backup filename: {}", err);
std::ptr::null_mut()
}
},
@@ -139,7 +138,7 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
))
{
if let Ok(chat_id) = chat::create_by_contact_id(context, 1) {
msg = dc_msg_new_untyped(context);
msg = dc_msg_new_untyped();
msg.type_0 = Viewtype::File;
msg.param.set(Param::File, as_str(setup_file_name));
@@ -156,7 +155,7 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
.shall_stop_ongoing
{
if let Ok(msg_id) = chat::send_msg(context, chat_id, &mut msg) {
info!(context, 0, "Wait for setup message being sent ...",);
info!(context, "Wait for setup message being sent ...",);
loop {
if context
.running_state
@@ -170,7 +169,7 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
std::thread::sleep(std::time::Duration::from_secs(1));
if let Ok(msg) = dc_get_msg(context, msg_id) {
if 0 != dc_msg_is_sent(&msg) {
info!(context, 0, "... setup message sent.",);
info!(context, "... setup message sent.",);
break;
}
}
@@ -208,12 +207,8 @@ pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result<Strin
_ => Some(("Autocrypt-Prefer-Encrypt", "mutual")),
};
let private_key_asc = private_key.to_asc(ac_headers);
let encr = {
let private_key_asc_c = CString::yolo(private_key_asc);
let passphrase_c = CString::yolo(passphrase);
dc_pgp_symm_encrypt(passphrase_c.as_ptr(), private_key_asc_c.as_bytes())
.ok_or(format_err!("Failed to encrypt private key."))?
};
let encr = dc_pgp_symm_encrypt(&passphrase, private_key_asc.as_bytes())
.ok_or(format_err!("Failed to encrypt private key."))?;
let replacement = format!(
concat!(
"-----BEGIN PGP MESSAGE-----\r\n",
@@ -268,56 +263,57 @@ pub fn dc_create_setup_code(_context: &Context) -> String {
ret
}
// TODO should return bool /rtn
pub unsafe fn dc_continue_key_transfer(
context: &Context,
msg_id: uint32_t,
setup_code: *const libc::c_char,
) -> libc::c_int {
let mut success: libc::c_int = 0i32;
) -> bool {
let mut success = false;
let mut filename: *mut libc::c_char = ptr::null_mut();
let mut filecontent: *mut libc::c_char = ptr::null_mut();
let mut filebytes: size_t = 0i32 as size_t;
let mut armored_key: *mut libc::c_char = ptr::null_mut();
let mut norm_sc: *mut libc::c_char = ptr::null_mut();
if !(msg_id <= 9i32 as libc::c_uint || setup_code.is_null()) {
let msg = dc_get_msg(context, msg_id);
if msg.is_err()
|| !dc_msg_is_setupmessage(msg.as_ref().unwrap())
|| {
filename = dc_msg_get_file(msg.as_ref().unwrap());
filename.is_null()
}
|| *filename.offset(0isize) as libc::c_int == 0i32
{
error!(context, 0, "Message is no Autocrypt Setup Message.",);
} else if 0
== dc_read_file(
context,
filename,
&mut filecontent as *mut *mut libc::c_char as *mut *mut libc::c_void,
&mut filebytes,
)
|| filecontent.is_null()
|| filebytes <= 0
{
error!(context, 0, "Cannot read Autocrypt Setup Message file.",);
if msg_id <= 9i32 as libc::c_uint || setup_code.is_null() {
return false;
}
let msg = dc_get_msg(context, msg_id);
if msg.is_err()
|| !dc_msg_is_setupmessage(msg.as_ref().unwrap())
|| {
filename = dc_msg_get_file(context, msg.as_ref().unwrap());
filename.is_null()
}
|| *filename.offset(0isize) as libc::c_int == 0i32
{
error!(context, "Message is no Autocrypt Setup Message.",);
} else if 0
== dc_read_file(
context,
filename,
&mut filecontent as *mut *mut libc::c_char as *mut *mut libc::c_void,
&mut filebytes,
)
|| filecontent.is_null()
|| filebytes <= 0
{
error!(context, "Cannot read Autocrypt Setup Message file.",);
} else {
norm_sc = dc_normalize_setup_code(context, setup_code);
if norm_sc.is_null() {
warn!(context, "Cannot normalize Setup Code.",);
} else {
norm_sc = dc_normalize_setup_code(context, setup_code);
if norm_sc.is_null() {
warn!(context, 0, "Cannot normalize Setup Code.",);
} else {
armored_key = dc_decrypt_setup_file(context, norm_sc, filecontent);
if armored_key.is_null() {
warn!(context, 0, "Cannot decrypt Autocrypt Setup Message.",);
} else if set_self_key(context, armored_key, 1) {
/*set default*/
/* error already logged */
success = 1i32
}
armored_key = dc_decrypt_setup_file(context, norm_sc, filecontent);
if armored_key.is_null() {
warn!(context, "Cannot decrypt Autocrypt Setup Message.",);
} else if set_self_key(context, armored_key, 1) {
/*set default*/
/* error already logged */
success = true
}
}
}
free(armored_key as *mut libc::c_void);
free(filecontent as *mut libc::c_void);
free(filename as *mut libc::c_void);
@@ -339,7 +335,7 @@ fn set_self_key(
.and_then(|(k, h)| k.split_key().map(|pub_key| (k, pub_key, h)));
if keys.is_none() {
error!(context, 0, "File does not contain a valid private key.",);
error!(context, "File does not contain a valid private key.",);
return false;
}
@@ -369,13 +365,13 @@ fn set_self_key(
return false;
}
} else {
error!(context, 0, "File does not contain a private key.",);
error!(context, "File does not contain a private key.",);
}
let self_addr = context.sql.get_config(context, "configured_addr");
if self_addr.is_none() {
error!(context, 0, "Missing self addr");
error!(context, "Missing self addr");
return false;
}
@@ -387,7 +383,7 @@ fn set_self_key(
set_default,
&context.sql,
) {
error!(context, 0, "Cannot save keypair.");
error!(context, "Cannot save keypair.");
return false;
}
@@ -446,7 +442,7 @@ pub unsafe fn dc_decrypt_setup_file(
{
/* decrypt symmetrically */
if let Some(plain) = dc_pgp_symm_decrypt(
passphrase,
as_str(passphrase),
std::slice::from_raw_parts(binary as *const u8, binary_bytes),
) {
let payload_c = CString::new(plain).unwrap();
@@ -508,19 +504,18 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) {
let _param2 = CString::yolo(job.param.get(Param::Arg2).unwrap_or_default());
if strlen(param1.as_ptr()) == 0 {
error!(context, 0, "No Import/export dir/file given.",);
error!(context, "No Import/export dir/file given.",);
} else {
info!(context, 0, "Import/export process started.",);
info!(context, "Import/export process started.",);
context.call_cb(Event::IMEX_PROGRESS, 10 as uintptr_t, 0 as uintptr_t);
if !context.sql.is_open() {
error!(context, 0, "Import/export: Database not opened.",);
error!(context, "Import/export: Database not opened.",);
} else {
if what == 1 || what == 11 {
/* before we export anything, make sure the private key exists */
if e2ee::ensure_secret_key_exists(context).is_err() {
error!(
context,
0,
"Import/export: Cannot create private key or private key not available.",
);
ok_to_continue = false;
@@ -532,25 +527,25 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) {
match what {
1 => {
if 0 != export_self_keys(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
info!(context, "Import/export completed.",);
success = 1
}
}
2 => {
if 0 != import_self_keys(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
info!(context, "Import/export completed.",);
success = 1
}
}
11 => {
if 0 != export_backup(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
info!(context, "Import/export completed.",);
success = 1
}
}
12 => {
if 0 != import_backup(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
info!(context, "Import/export completed.",);
success = 1
}
}
@@ -577,7 +572,6 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) {
unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char) -> libc::c_int {
info!(
context,
0,
"Import \"{}\" to \"{}\".",
as_str(backup_to_import),
context
@@ -586,8 +580,8 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
.map_or("<<None>>", |p| p.to_str().unwrap())
);
if 0 != dc_is_configured(context) {
error!(context, 0, "Cannot import backups to accounts in use.");
if dc_is_configured(context) {
error!(context, "Cannot import backups to accounts in use.");
return 0;
}
&context.sql.close(&context);
@@ -595,7 +589,7 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
if dc_file_exist(context, context.get_dbfile().unwrap()) {
error!(
context,
0, "Cannot import backups: Cannot delete the old file.",
"Cannot import backups: Cannot delete the old file.",
);
return 0;
}
@@ -622,7 +616,7 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
.unwrap_or_default() as usize;
info!(
context,
0, "***IMPORT-in-progress: total_files_cnt={:?}", total_files_cnt,
"***IMPORT-in-progress: total_files_cnt={:?}", total_files_cnt,
);
let res = context.sql.query_map(
@@ -670,7 +664,6 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
}
error!(
context,
0,
"Storage full? Cannot write file {} with {} bytes.",
&pathNfilename,
file_blob.len(),
@@ -717,7 +710,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
let buffer = CString::yolo(res);
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.",);
error!(context, "Cannot get backup file name.",);
return success;
}
@@ -729,7 +722,6 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
let mut closed = true;
info!(
context,
0,
"Backup \"{}\" to \"{}\".",
context
.get_dbfile()
@@ -773,7 +765,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
if let Ok(dir_handle) = std::fs::read_dir(dir) {
total_files_cnt += dir_handle.filter(|r| r.is_ok()).count();
info!(context, 0, "EXPORT: total_files_cnt={}", total_files_cnt);
info!(context, "EXPORT: total_files_cnt={}", total_files_cnt);
if total_files_cnt > 0 {
// scan directory, pass 2: copy files
if let Ok(dir_handle) = std::fs::read_dir(dir) {
@@ -819,7 +811,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
{
continue;
} else {
info!(context, 0, "EXPORTing filename={}", name);
info!(context, "EXPORTing filename={}", name);
let curr_pathNfilename = format!(
"{}/{}",
as_str(context.get_blobdir()),
@@ -835,7 +827,6 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
if stmt.execute(params![name, buf]).is_err() {
error!(
context,
0,
"Disk full? Cannot add file \"{}\" to backup.",
&curr_pathNfilename,
);
@@ -855,13 +846,12 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
} else {
error!(
context,
0,
"Backup: Cannot copy from blob-directory \"{}\".",
as_str(context.get_blobdir()),
);
}
} else {
info!(context, 0, "Backup: No files to copy.",);
info!(context, "Backup: No files to copy.",);
ok_to_continue = true;
}
if ok_to_continue {
@@ -880,7 +870,6 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
} else {
error!(
context,
0,
"Backup: Cannot get info for blob-directory \"{}\".",
as_str(context.get_blobdir())
);
@@ -945,7 +934,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
dir_name,
name_c.as_ptr(),
);
info!(context, 0, "Checking: {}", as_str(path_plus_name));
info!(context, "Checking: {}", as_str(path_plus_name));
free(buf as *mut libc::c_void);
buf = ptr::null_mut();
if 0 == dc_read_file(
@@ -989,7 +978,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
{
info!(
context,
0,
"Treating \"{}\" as a legacy private key.",
as_str(path_plus_name),
);
@@ -1003,7 +991,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
if imported_cnt == 0i32 {
error!(
context,
0,
"No private keys found in \"{}\".",
as_str(dir_name),
);
@@ -1011,7 +998,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
} else {
error!(
context,
0,
"Import: Cannot open directory \"{}\".",
as_str(dir_name),
);
@@ -1111,10 +1097,10 @@ unsafe fn export_key_to_asc_file(
id,
)
}
info!(context, 0, "Exporting key {}", as_str(file_name),);
info!(context, "Exporting key {}", as_str(file_name),);
dc_delete_file(context, as_path(file_name));
if !key.write_asc_to_file(file_name, context) {
error!(context, 0, "Cannot write key to {}", as_str(file_name),);
error!(context, "Cannot write key to {}", as_str(file_name),);
} else {
context.call_cb(
Event::IMEX_FILE_WRITTEN,

View File

@@ -37,8 +37,8 @@ pub struct dc_mimefactory_t<'a> {
pub timestamp: i64,
pub rfc724_mid: *mut libc::c_char,
pub loaded: dc_mimefactory_loaded_t,
pub msg: Message<'a>,
pub chat: Option<Chat<'a>>,
pub msg: Message,
pub chat: Option<Chat>,
pub increation: libc::c_int,
pub in_reply_to: *mut libc::c_char,
pub references: *mut libc::c_char,
@@ -225,7 +225,7 @@ pub unsafe fn dc_mimefactory_load_msg(
Err(err) => {
error!(
context,
0, "mimefactory: failed to load mime_in_reply_to: {:?}", err
"mimefactory: failed to load mime_in_reply_to: {:?}", err
);
}
}
@@ -335,7 +335,10 @@ pub unsafe fn dc_mimefactory_load_mdn<'a>(
}
// TODO should return bool /rtn
pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_int {
pub unsafe fn dc_mimefactory_render(
context: &Context,
factory: &mut dc_mimefactory_t,
) -> libc::c_int {
let subject: *mut mailimf_subject;
let mut ok_to_continue = true;
let imf_fields: *mut mailimf_fields;
@@ -586,8 +589,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
}
if 0 != msg.param.get_int(Param::Arg2).unwrap_or_default() & 0x1 {
info!(
msg.context,
0,
context,
"sending secure-join message \'{}\' >>>>>>>>>>>>>>>>>>>>>>>>>",
"vg-member-added",
);
@@ -655,8 +657,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
let step = msg.param.get(Param::Arg).unwrap_or_default().strdup();
if strlen(step) > 0 {
info!(
msg.context,
0,
context,
"sending secure-join message \'{}\' >>>>>>>>>>>>>>>>>>>>>>>>>",
as_str(step),
);
@@ -726,13 +727,14 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
}
}
if let Some(grpimage) = grpimage {
info!(factory.context, 0, "setting group image '{}'", grpimage);
let mut meta = dc_msg_new_untyped(factory.context);
info!(factory.context, "setting group image '{}'", grpimage);
let mut meta = dc_msg_new_untyped();
meta.type_0 = Viewtype::Image;
meta.param.set(Param::File, grpimage);
let mut filename_as_sent = ptr::null_mut();
meta_part = build_body_file(
context,
&meta,
b"group-image\x00" as *const u8 as *const libc::c_char,
&mut filename_as_sent,
@@ -835,7 +837,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
/* add attachment part */
if chat::msgtype_has_file(factory.msg.type_0) {
if !is_file_size_okay(&factory.msg) {
if !is_file_size_okay(context, &factory.msg) {
let error: *mut libc::c_char = dc_mprintf(
b"Message exceeds the recommended %i MB.\x00" as *const u8
as *const libc::c_char,
@@ -846,7 +848,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
ok_to_continue = false;
} else {
let file_part: *mut mailmime =
build_body_file(&factory.msg, ptr::null(), ptr::null_mut());
build_body_file(context, &factory.msg, ptr::null(), ptr::null_mut());
if !file_part.is_null() {
mailmime_smart_add_part(message, file_part);
parts += 1
@@ -894,12 +896,9 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
mailmime_smart_add_part(message, kml_mime_part);
}
if location::is_sending_locations_to_chat(
factory.msg.context,
factory.msg.chat_id,
) {
if location::is_sending_locations_to_chat(context, factory.msg.chat_id) {
if let Ok((kml_file, last_added_location_id)) =
location::get_kml(factory.msg.context, factory.msg.chat_id)
location::get_kml(context, factory.msg.chat_id)
{
let content_type = mailmime_content_new_with_str(
b"application/vnd.google-earth.kml+xml\x00" as *const u8
@@ -952,7 +951,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
.stock_str(StockMessage::EncryptedMsg)
.into_owned()
} else {
to_string(dc_msg_get_summarytext(&mut factory.msg, 32))
to_string(dc_msg_get_summarytext(context, &mut factory.msg, 32))
};
let p2 = factory
.context
@@ -996,7 +995,8 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
e.as_ptr(),
);
} else {
subject_str = get_subject(factory.chat.as_ref(), &mut factory.msg, afwd_email)
subject_str =
get_subject(context, factory.chat.as_ref(), &mut factory.msg, afwd_email)
}
subject = mailimf_subject_new(dc_encode_header_words(subject_str));
mailimf_fields_add(
@@ -1062,6 +1062,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
}
unsafe fn get_subject(
context: &Context,
chat: Option<&Chat>,
msg: &mut Message,
afwd_email: libc::c_int,
@@ -1071,7 +1072,6 @@ unsafe fn get_subject(
}
let chat = chat.unwrap();
let context = chat.context;
let ret: *mut libc::c_char;
let raw_subject = {
@@ -1136,6 +1136,7 @@ unsafe fn build_body_text(text: *mut libc::c_char) -> *mut mailmime {
#[allow(non_snake_case)]
unsafe fn build_body_file(
context: &Context,
msg: &Message,
mut base_name: *const libc::c_char,
ret_file_name_as_sent: *mut *mut libc::c_char,
@@ -1288,7 +1289,7 @@ unsafe fn build_body_file(
) as *mut libc::c_void,
);
mime_sub = mailmime_new_empty(content, mime_fields);
mailmime_set_body_file(mime_sub, dc_get_abs_path(msg.context, path_filename));
mailmime_set_body_file(mime_sub, dc_get_abs_path(context, path_filename));
if !ret_file_name_as_sent.is_null() {
*ret_file_name_as_sent = dc_strdup(filename_to_send)
}
@@ -1305,10 +1306,10 @@ unsafe fn build_body_file(
/*******************************************************************************
* Render
******************************************************************************/
unsafe fn is_file_size_okay(msg: &Message) -> bool {
unsafe fn is_file_size_okay(context: &Context, msg: &Message) -> bool {
let mut file_size_okay = true;
let path = msg.param.get(Param::File).unwrap_or_default();
let bytes = dc_get_filebytes(msg.context, &path);
let bytes = dc_get_filebytes(context, &path);
if bytes > (49 * 1024 * 1024 / 4 * 3) {
file_size_okay = false;

View File

@@ -132,15 +132,9 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
dc_mimeparser_parse_mime_recursive(mimeparser_ref, mimeparser_ref.mimeroot);
let field: *mut mailimf_field = dc_mimeparser_lookup_field(&mimeparser, "Subject");
if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
let decoded = dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value);
if decoded.is_null()
/* XXX: can it happen? */
{
mimeparser.subject = None
} else {
mimeparser.subject = Some(to_string(decoded));
free(decoded.cast());
}
let subj = (*(*field).fld_data.fld_subject).sbj_value;
mimeparser.subject = as_opt_str(subj).map(dc_decode_header_words_safe);
}
if !dc_mimeparser_lookup_optional_field(&mut mimeparser, "Chat-Version").is_null() {
mimeparser.is_send_by_messenger = true
@@ -257,7 +251,7 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
msg_c,
);
free(msg_c.cast());
part.msg = Some(to_string(new_txt));
part.msg = Some(to_string_lossy(new_txt));
free(new_txt.cast());
break;
}
@@ -460,7 +454,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
{
info!(
mimeparser.context,
0, "Protected headers found in text/rfc822-headers attachment: Will be ignored.",
"Protected headers found in text/rfc822-headers attachment: Will be ignored.",
);
return 0i32;
}
@@ -474,7 +468,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
) != MAILIMF_NO_ERROR as libc::c_int
|| mimeparser.header_protected.is_null()
{
warn!(mimeparser.context, 0, "Protected headers parsing error.",);
warn!(mimeparser.context, "Protected headers parsing error.",);
} else {
hash_header(
&mut mimeparser.header,
@@ -485,7 +479,6 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
} else {
info!(
mimeparser.context,
0,
"Protected headers found in MIME header: Will be ignored as we already found an outer one."
);
}
@@ -667,7 +660,6 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
if plain_cnt == 1i32 && html_cnt == 1i32 {
warn!(
mimeparser.context,
0i32,
"HACK: multipart/mixed message found with PLAIN and HTML, we\'ll skip the HTML part as this seems to be unwanted."
);
skip_part = html_part
@@ -1072,7 +1064,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
);
let (res, _, _) = encoding.decode(data);
info!(mimeparser.context, 0, "decoded message: '{}'", res);
info!(mimeparser.context, "decoded message: '{}'", res);
if res.is_empty() {
/* no error - but nothing to add */
ok_to_continue = false;
@@ -1085,7 +1077,6 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
} else {
warn!(
mimeparser.context,
0,
"Cannot convert {} bytes from \"{}\" to \"utf-8\".",
decoded_data_bytes as libc::c_int,
as_str(charset),
@@ -1117,7 +1108,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
part.msg_raw = {
let raw_c =
strndup(decoded_data, decoded_data_bytes as libc::c_ulong);
let raw = to_string(raw_c);
let raw = to_string_lossy(raw_c);
free(raw_c.cast());
Some(raw)
};
@@ -1175,7 +1166,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
9,
) == 0i32
{
filename_parts += &to_string(
filename_parts += &to_string_lossy(
(*(*dsp_param).pa_data.pa_parameter).pa_value,
);
} else if (*dsp_param).pa_type
@@ -1649,7 +1640,7 @@ pub unsafe fn dc_mimeparser_repl_msg_by_error(
}
let part = &mut mimeparser.parts[0];
part.type_0 = Viewtype::Text;
part.msg = Some(format!("[{}]", to_string(error_msg)));
part.msg = Some(format!("[{}]", to_string_lossy(error_msg)));
mimeparser.parts.truncate(1);
assert_eq!(mimeparser.parts.len(), 1);
}

View File

@@ -41,7 +41,6 @@ pub unsafe fn dc_receive_imf(
) {
info!(
context,
0,
"Receiving message {}/{}...",
if !server_folder.as_ref().is_empty() {
server_folder.as_ref()
@@ -61,7 +60,7 @@ pub unsafe fn dc_receive_imf(
if mime_parser.header.is_empty() {
// Error - even adding an empty record won't help as we do not know the message ID
info!(context, 0, "No header.");
info!(context, "No header.");
return;
}
@@ -189,7 +188,7 @@ pub unsafe fn dc_receive_imf(
&mut created_db_entries,
&mut create_event_to_send,
) {
info!(context, 0, "{}", err);
info!(context, "{}", err);
cleanup(
context,
@@ -243,7 +242,6 @@ pub unsafe fn dc_receive_imf(
info!(
context,
0,
"received message {} has Message-Id: {}",
server_uid,
to_string(rfc724_mid)
@@ -447,10 +445,7 @@ unsafe fn add_parts(
// check if the message belongs to a mailing list
if dc_mimeparser_is_mailinglist_message(mime_parser) {
*chat_id = 3;
info!(
context,
0, "Message belongs to a mailing list and is ignored.",
);
info!(context, "Message belongs to a mailing list and is ignored.",);
}
}
@@ -482,7 +477,7 @@ unsafe fn add_parts(
Contact::scaleup_origin_by_id(context, *from_id, Origin::IncomingReplyTo);
info!(
context,
0, "Message is a reply to a known message, mark sender as known.",
"Message is a reply to a known message, mark sender as known.",
);
if !incoming_origin.is_verified() {
*incoming_origin = Origin::IncomingReplyTo;
@@ -642,7 +637,8 @@ unsafe fn add_parts(
}
}
if part.type_0 == Viewtype::Text {
let msg_raw = CString::yolo(part.msg_raw.as_ref().unwrap().clone());
let msg_raw =
CString::yolo(part.msg_raw.as_ref().cloned().unwrap_or_default());
let subject_c = CString::yolo(
mime_parser
.subject
@@ -723,7 +719,7 @@ unsafe fn add_parts(
info!(
context,
0, "Message has {} parts and is assigned to chat #{}.", icnt, *chat_id,
"Message has {} parts and is assigned to chat #{}.", icnt, *chat_id,
);
// check event to send
@@ -961,7 +957,7 @@ fn save_locations(
insert_msg_id,
newest_location_id,
) {
error!(context, 0, "Failed to set msg_location_id: {:?}", err);
error!(context, "Failed to set msg_location_id: {:?}", err);
}
}
send_event = true;
@@ -1316,7 +1312,7 @@ unsafe fn create_or_lookup_group(
if !X_MrAddToGrp.is_null() || !X_MrRemoveFromGrp.is_null() {
recreate_member_list = 1;
} else if 0 != X_MrGrpNameChanged && !grpname.is_null() && strlen(grpname) < 200 {
info!(context, 0, "updating grpname for chat {}", chat_id);
info!(context, "updating grpname for chat {}", chat_id);
if sql::execute(
context,
&context.sql,
@@ -1331,7 +1327,7 @@ unsafe fn create_or_lookup_group(
if !X_MrGrpImageChanged.is_empty() {
info!(
context,
0, "grp-image-change {} chat {}", X_MrGrpImageChanged, chat_id
"grp-image-change {} chat {}", X_MrGrpImageChanged, chat_id
);
let mut changed = false;
let mut grpimage = "".to_string();
@@ -1345,20 +1341,20 @@ unsafe fn create_or_lookup_group(
.get(Param::File)
.map(|s| s.to_string())
.unwrap_or_else(|| "".to_string());
info!(context, 0, "found image {:?}", grpimage);
info!(context, "found image {:?}", grpimage);
changed = true;
}
}
}
if changed {
info!(context, 0, "New group image set to '{}'.", grpimage);
info!(context, "New group image set to '{}'.", grpimage);
if let Ok(mut chat) = Chat::load_from_db(context, chat_id) {
if grpimage.is_empty() {
chat.param.remove(Param::ProfileImage);
} else {
chat.param.set(Param::ProfileImage, grpimage);
}
chat.update_param().unwrap();
chat.update_param(context).unwrap();
send_EVENT_CHAT_MODIFIED = 1;
}
}
@@ -1740,7 +1736,7 @@ unsafe fn check_verified_properties(
) -> libc::c_int {
let verify_fail = |reason: String| {
*failure_reason = format!("{}. See \"Info\" for details.", reason).strdup();
warn!(context, 0, "{}", reason);
warn!(context, "{}", reason);
};
let contact = match Contact::load_from_db(context, from_id) {
@@ -1764,7 +1760,8 @@ unsafe fn check_verified_properties(
let peerstate = Peerstate::from_addr(context, &context.sql, contact.get_addr());
if peerstate.is_none()
|| contact.is_verified_ex(peerstate.as_ref()) != VerifiedStatus::BidirectVerified
|| contact.is_verified_ex(context, peerstate.as_ref())
!= VerifiedStatus::BidirectVerified
{
verify_fail("The sender of this message is not verified.".into());
return 0;
@@ -1811,13 +1808,7 @@ unsafe fn check_verified_properties(
|| peerstate.verified_key_fingerprint != peerstate.public_key_fingerprint
&& peerstate.verified_key_fingerprint != peerstate.gossip_key_fingerprint
{
info!(
context,
0,
"{} has verfied {}.",
contact.get_addr(),
to_addr,
);
info!(context, "{} has verfied {}.", contact.get_addr(), to_addr,);
let fp = peerstate.gossip_key_fingerprint.clone();
if let Some(fp) = fp {
peerstate.set_verified(0, &fp, 2);

View File

@@ -12,6 +12,20 @@ use crate::dc_tools::*;
use crate::types::*;
use crate::x::*;
/**
* Encode non-ascii-strings as `=?UTF-8?Q?Bj=c3=b6rn_Petersen?=`.
* Belongs to RFC 2047: https://tools.ietf.org/html/rfc2047
*
* We do not fold at position 72; this would result in empty words as `=?utf-8?Q??=` which are correct,
* but cannot be displayed by some mail programs (eg. Android Stock Mail).
* however, this is not needed, as long as _one_ word is not longer than 72 characters.
* _if_ it is, the display may get weird. This affects the subject only.
* the best solution wor all this would be if libetpan encodes the line as only libetpan knowns when a header line is full.
*
* @param to_encode Null-terminated UTF-8-string to encode.
* @return Returns the encoded string which must be free()'d when no longed needed.
* On errors, NULL is returned.
*/
pub unsafe fn dc_encode_header_words(to_encode: *const libc::c_char) -> *mut libc::c_char {
let mut ok_to_continue = true;
let mut ret_str: *mut libc::c_char = ptr::null_mut();
@@ -224,6 +238,31 @@ pub unsafe fn dc_decode_header_words(in_0: *const libc::c_char) -> *mut libc::c_
out
}
pub fn dc_decode_header_words_safe(input: &str) -> String {
static FROM_ENCODING: &[u8] = b"iso-8859-1\x00";
static TO_ENCODING: &[u8] = b"utf-8\x00";
let mut out = ptr::null_mut();
let mut cur_token = 0;
let input_c = CString::yolo(input);
unsafe {
let r = mailmime_encoded_phrase_parse(
FROM_ENCODING.as_ptr().cast(),
input_c.as_ptr(),
input.len(),
&mut cur_token,
TO_ENCODING.as_ptr().cast(),
&mut out,
);
if r as u32 != MAILIMF_NO_ERROR || out.is_null() {
input.to_string()
} else {
let res = to_string(out);
free(out.cast());
res
}
}
}
pub fn dc_needs_ext_header(to_check: impl AsRef<str>) -> bool {
let to_check = to_check.as_ref();

View File

@@ -843,16 +843,19 @@ pub fn dc_get_filebytes(context: &Context, path: impl AsRef<std::path::Path>) ->
pub fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
let path_abs = dc_get_abs_path_safe(context, &path);
let res = if path_abs.is_file() {
fs::remove_file(path_abs)
} else {
fs::remove_dir_all(path_abs)
};
if !path_abs.is_file() {
warn!(
context,
"Will not delete directory \"{}\".",
path.as_ref().display()
);
return false;
}
match res {
match fs::remove_file(path_abs) {
Ok(_) => true,
Err(_err) => {
warn!(context, 0, "Cannot delete \"{}\".", path.as_ref().display());
warn!(context, "Cannot delete \"{}\".", path.as_ref().display());
false
}
}
@@ -870,7 +873,6 @@ pub fn dc_copy_file(
Err(_) => {
error!(
context,
0,
"Cannot copy \"{}\" to \"{}\".",
src.as_ref().display(),
dest.as_ref().display(),
@@ -888,7 +890,6 @@ pub fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Path>) ->
Err(_err) => {
warn!(
context,
0,
"Cannot create directory \"{}\".",
path.as_ref().display(),
);
@@ -921,7 +922,6 @@ pub fn dc_write_file_safe<P: AsRef<std::path::Path>>(
if let Err(_err) = fs::write(&path_abs, buf) {
warn!(
context,
0,
"Cannot write {} bytes to \"{}\".",
buf.len(),
path.as_ref().display(),
@@ -959,7 +959,6 @@ pub fn dc_read_file_safe<P: AsRef<std::path::Path>>(context: &Context, path: P)
Err(_err) => {
warn!(
context,
0,
"Cannot read \"{}\" or file is empty.",
path.as_ref().display()
);

View File

@@ -91,7 +91,7 @@ impl E2eeHelper {
if let Some(addr) = addr {
let pubkey_ret = load_or_generate_self_public_key(context, &addr).map_err(|err| {
error!(context, 0, "Failed to load public key: {}", err);
error!(context, "Failed to load public key: {}", err);
err
});
if let Ok(public_key) = pubkey_ret {
@@ -113,7 +113,7 @@ impl E2eeHelper {
let peerstate = peerstate.unwrap();
info!(
context,
0, "dc_e2ee_encrypt {} has peerstate", recipient_addr
"dc_e2ee_encrypt {} has peerstate", recipient_addr
);
if let Some(key) = peerstate.peek_key(min_verified as usize) {
keyring.add_owned(key.clone());
@@ -122,7 +122,6 @@ impl E2eeHelper {
} else {
info!(
context,
0,
"dc_e2ee_encrypt {} HAS NO peerstate {}",
recipient_addr,
peerstate.is_some()
@@ -608,7 +607,7 @@ fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str
let start = std::time::Instant::now();
info!(
context,
0, "Generating keypair with {} bits, e={} ...", 2048, 65537,
"Generating keypair with {} bits, e={} ...", 2048, 65537,
);
match dc_pgp_create_keypair(&self_addr) {
Some((public_key, private_key)) => {
@@ -623,7 +622,6 @@ fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str
true => {
info!(
context,
0,
"Keypair generated in {:.3}s.",
start.elapsed().as_secs()
);
@@ -691,7 +689,6 @@ unsafe fn update_gossip_peerstates(
} else {
info!(
context,
0,
"Ignoring gossipped \"{}\" as the address is not in To/Cc list.",
&header.addr,
);
@@ -1028,7 +1025,7 @@ unsafe fn contains_report(mime: *mut mailmime) -> bool {
/// [Config::ConfiguredAddr] is configured, this address is returned.
pub fn ensure_secret_key_exists(context: &Context) -> Result<String> {
let self_addr = context
.get_config(Config::ConfiguredAddr)
.get_config(&Config::ConfiguredAddr)
.ok_or(format_err!(concat!(
"Failed to get self address, ",
"cannot ensure secret key if not configured."

View File

@@ -472,12 +472,9 @@ impl Imap {
}
fn unsetup_handle(&self, context: &Context) {
info!(context, 0, "IMAP unsetup_handle starts");
info!(context, "IMAP unsetup_handle starts");
info!(
context,
0, "IMAP unsetup_handle step 1 (closing down stream)."
);
info!(context, "IMAP unsetup_handle step 1 (closing down stream).");
let stream = self.stream.write().unwrap().take();
if let Some(stream) = stream {
if let Err(err) = stream.shutdown(net::Shutdown::Both) {
@@ -487,7 +484,7 @@ impl Imap {
info!(
context,
0, "IMAP unsetup_handle step 2 (acquiring session.lock)"
"IMAP unsetup_handle step 2 (acquiring session.lock)"
);
if let Some(mut session) = self.session.lock().unwrap().take() {
if let Err(err) = session.close() {
@@ -495,10 +492,10 @@ impl Imap {
}
}
info!(context, 0, "IMAP unsetup_handle step 3 (clearing config).");
info!(context, "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, "IMAP unsetup_handle step 4 (disconnected).",);
}
fn free_connect_params(&self) {
@@ -551,7 +548,7 @@ impl Imap {
Some(ref mut session) => match session.capabilities() {
Ok(caps) => {
if !context.sql.is_open() {
warn!(context, 0, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
warn!(context, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
(true, false, false)
} else {
let can_idle = caps.has_str("IDLE");
@@ -571,7 +568,7 @@ impl Imap {
}
}
Err(err) => {
info!(context, 0, "CAPABILITY command error: {}", err);
info!(context, "CAPABILITY command error: {}", err);
(true, false, false)
}
},
@@ -647,7 +644,7 @@ impl Imap {
// deselect existing folder, if needed (it's also done implicitly by SELECT, however, without EXPUNGE then)
if self.config.read().unwrap().selected_folder_needs_expunge {
if let Some(ref folder) = self.config.read().unwrap().selected_folder {
info!(context, 0, "Expunge messages in \"{}\".", folder);
info!(context, "Expunge messages in \"{}\".", folder);
// A CLOSE-SELECT is considerably faster than an EXPUNGE-SELECT, see
// https://tools.ietf.org/html/rfc3501#section-6.4.2
@@ -677,7 +674,6 @@ impl Imap {
Err(err) => {
info!(
context,
0,
"Cannot select folder: {}; {:?}.",
folder.as_ref(),
err
@@ -714,7 +710,6 @@ impl Imap {
if !self.is_connected() {
info!(
context,
0,
"Cannot fetch from \"{}\" - not connected.",
folder.as_ref()
);
@@ -725,7 +720,6 @@ impl Imap {
if self.select_folder(context, Some(&folder)) == 0 {
info!(
context,
0,
"Cannot select folder \"{}\" for fetching.",
folder.as_ref()
);
@@ -742,7 +736,6 @@ impl Imap {
if mailbox.uid_validity.is_none() {
error!(
context,
0,
"Cannot get UIDVALIDITY for folder \"{}\".",
folder.as_ref(),
);
@@ -754,7 +747,7 @@ impl Imap {
// first time this folder is selected or UIDVALIDITY has changed, init lastseenuid and save it to config
if mailbox.exists == 0 {
info!(context, 0, "Folder \"{}\" is empty.", folder.as_ref());
info!(context, "Folder \"{}\" is empty.", folder.as_ref());
// set lastseenuid=0 for empty folders.
// id we do not do this here, we'll miss the first message
@@ -773,7 +766,6 @@ impl Imap {
self.should_reconnect.store(true, Ordering::Relaxed);
info!(
context,
0,
"No result returned for folder \"{}\".",
folder.as_ref()
);
@@ -796,7 +788,6 @@ impl Imap {
self.set_config_last_seen_uid(context, &folder, uid_validity, last_seen_uid);
info!(
context,
0,
"lastseenuid initialized to {} for {}@{}",
last_seen_uid,
folder.as_ref(),
@@ -815,7 +806,7 @@ impl Imap {
match session.uid_fetch(set, PREFETCH_FLAGS) {
Ok(list) => list,
Err(err) => {
warn!(context, 0, "failed to fetch uids: {}", err);
warn!(context, "failed to fetch uids: {}", err);
return 0;
}
}
@@ -843,7 +834,6 @@ impl Imap {
if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
info!(
context,
0,
"Read error for message {} from \"{}\", trying over later.",
message_id,
folder.as_ref()
@@ -855,7 +845,6 @@ impl Imap {
// check failed
info!(
context,
0,
"Skipping message {} from \"{}\" by precheck.",
message_id,
folder.as_ref(),
@@ -876,7 +865,6 @@ impl Imap {
if read_errors > 0 {
warn!(
context,
0,
"{} mails read from \"{}\" with {} errors.",
read_cnt,
folder.as_ref(),
@@ -885,7 +873,6 @@ impl Imap {
} else {
info!(
context,
0,
"{} mails read from \"{}\".",
read_cnt,
folder.as_ref()
@@ -930,7 +917,6 @@ impl Imap {
self.should_reconnect.store(true, Ordering::Relaxed);
warn!(
context,
0,
"Error on fetching message #{} from folder \"{}\"; retry={}; error={}.",
server_uid,
folder.as_ref(),
@@ -947,7 +933,6 @@ impl Imap {
if msgs.is_empty() {
warn!(
context,
0,
"Message #{} does not exist in folder \"{}\".",
server_uid,
folder.as_ref()
@@ -1001,7 +986,7 @@ impl Imap {
let watch_folder = self.config.read().unwrap().watch_folder.clone();
if self.select_folder(context, watch_folder.as_ref()) == 0 {
warn!(context, 0, "IMAP-IDLE not setup.",);
warn!(context, "IMAP-IDLE not setup.",);
return self.fake_idle(context);
}
@@ -1011,7 +996,7 @@ impl Imap {
let (sender, receiver) = std::sync::mpsc::channel();
let v = self.watch.clone();
info!(context, 0, "IMAP-IDLE SPAWNING");
info!(context, "IMAP-IDLE SPAWNING");
std::thread::spawn(move || {
let &(ref lock, ref cvar) = &*v;
if let Some(ref mut session) = &mut *session.lock().unwrap() {
@@ -1046,18 +1031,15 @@ impl Imap {
let handle_res = |res| match res {
Ok(()) => {
info!(context, 0, "IMAP-IDLE has data.");
info!(context, "IMAP-IDLE has data.");
}
Err(err) => match err {
imap::error::Error::ConnectionLost => {
info!(
context,
0, "IMAP-IDLE wait cancelled, we will reconnect soon."
);
info!(context, "IMAP-IDLE wait cancelled, we will reconnect soon.");
self.should_reconnect.store(true, Ordering::Relaxed);
}
_ => {
warn!(context, 0, "IMAP-IDLE returns unknown value: {}", err);
warn!(context, "IMAP-IDLE returns unknown value: {}", err);
}
},
};
@@ -1073,7 +1055,7 @@ impl Imap {
if let Ok(res) = worker.as_ref().unwrap().try_recv() {
handle_res(res);
} else {
info!(context, 0, "IMAP-IDLE interrupted");
info!(context, "IMAP-IDLE interrupted");
}
drop(worker.take());
@@ -1091,7 +1073,7 @@ impl Imap {
let fake_idle_start_time = SystemTime::now();
let mut wait_long = false;
info!(context, 0, "IMAP-fake-IDLEing...");
info!(context, "IMAP-fake-IDLEing...");
let mut do_fake_idle = true;
while do_fake_idle {
@@ -1167,7 +1149,6 @@ impl Imap {
} else if folder.as_ref() == dest_folder.as_ref() {
info!(
context,
0,
"Skip moving message; message {}/{} is already in {}...",
folder.as_ref(),
uid,
@@ -1178,7 +1159,6 @@ impl Imap {
} else {
info!(
context,
0,
"Moving message {}/{} to {}...",
folder.as_ref(),
uid,
@@ -1188,7 +1168,6 @@ impl Imap {
if self.select_folder(context, Some(folder.as_ref())) == 0 {
warn!(
context,
0,
"Cannot select folder {} for moving message.",
folder.as_ref()
);
@@ -1202,7 +1181,6 @@ impl Imap {
Err(err) => {
info!(
context,
0,
"Cannot move message, fallback to COPY/DELETE {}/{} to {}: {}",
folder.as_ref(),
uid,
@@ -1223,7 +1201,7 @@ impl Imap {
Ok(_) => true,
Err(err) => {
eprintln!("error copy: {:?}", err);
info!(context, 0, "Cannot copy message.",);
info!(context, "Cannot copy message.",);
false
}
@@ -1234,7 +1212,7 @@ impl Imap {
if copied {
if self.add_flag(context, uid, "\\Deleted") == 0 {
warn!(context, 0, "Cannot mark message as \"Deleted\".",);
warn!(context, "Cannot mark message as \"Deleted\".",);
}
self.config.write().unwrap().selected_folder_needs_expunge = true;
res = DC_SUCCESS;
@@ -1271,7 +1249,7 @@ impl Imap {
Err(err) => {
warn!(
context,
0, "IMAP failed to store: ({}, {}) {:?}", set, query, err
"IMAP failed to store: ({}, {}) {:?}", set, query, err
);
}
}
@@ -1294,7 +1272,6 @@ impl Imap {
} else if self.is_connected() {
info!(
context,
0,
"Marking message {}/{} as seen...",
folder.as_ref(),
uid,
@@ -1303,12 +1280,11 @@ impl Imap {
if self.select_folder(context, Some(folder.as_ref())) == 0 {
warn!(
context,
0,
"Cannot select folder {} for setting SEEN flag.",
folder.as_ref(),
);
} else if self.add_flag(context, uid, "\\Seen") == 0 {
warn!(context, 0, "Cannot mark message as seen.",);
warn!(context, "Cannot mark message as seen.",);
} else {
res = DC_SUCCESS
}
@@ -1335,7 +1311,6 @@ impl Imap {
} else if self.is_connected() {
info!(
context,
0,
"Marking message {}/{} as $MDNSent...",
folder.as_ref(),
uid,
@@ -1344,7 +1319,6 @@ impl Imap {
if self.select_folder(context, Some(folder.as_ref())) == 0 {
warn!(
context,
0,
"Cannot select folder {} for setting $MDNSent flag.",
folder.as_ref()
);
@@ -1411,16 +1385,16 @@ impl Imap {
};
if res == DC_SUCCESS {
info!(context, 0, "$MDNSent just set and MDN will be sent.");
info!(context, "$MDNSent just set and MDN will be sent.");
} else {
info!(context, 0, "$MDNSent already set and MDN already sent.");
info!(context, "$MDNSent already set and MDN already sent.");
}
}
} else {
res = DC_SUCCESS;
info!(
context,
0, "Cannot store $MDNSent flags, risk sending duplicate MDN.",
"Cannot store $MDNSent flags, risk sending duplicate MDN.",
);
}
}
@@ -1451,7 +1425,6 @@ impl Imap {
} else {
info!(
context,
0,
"Marking message \"{}\", {}/{} for deletion...",
message_id.as_ref(),
folder.as_ref(),
@@ -1461,7 +1434,6 @@ impl Imap {
if self.select_folder(context, Some(&folder)) == 0 {
warn!(
context,
0,
"Cannot select folder {} for deleting message.",
folder.as_ref()
);
@@ -1482,7 +1454,6 @@ impl Imap {
{
warn!(
context,
0,
"Cannot delete on IMAP, {}/{} does not match {}.",
folder.as_ref(),
server_uid,
@@ -1496,7 +1467,6 @@ impl Imap {
warn!(
context,
0,
"Cannot delete on IMAP, {}/{} not found.",
folder.as_ref(),
server_uid,
@@ -1508,7 +1478,7 @@ impl Imap {
// mark the message for deletion
if self.add_flag(context, *server_uid, "\\Deleted") == 0 {
warn!(context, 0, "Cannot mark message as \"Deleted\".");
warn!(context, "Cannot mark message as \"Deleted\".");
} else {
self.config.write().unwrap().selected_folder_needs_expunge = true;
success = true
@@ -1528,7 +1498,7 @@ impl Imap {
return;
}
info!(context, 0, "Configuring IMAP-folders.");
info!(context, "Configuring IMAP-folders.");
let folders = self.list_folders(context).unwrap();
let delimiter = self.config.read().unwrap().imap_delimiter;
@@ -1547,21 +1517,19 @@ impl Imap {
});
if mvbox_folder.is_none() && 0 != (flags as usize & DC_CREATE_MVBOX) {
info!(context, 0, "Creating MVBOX-folder \"DeltaChat\"...",);
info!(context, "Creating MVBOX-folder \"DeltaChat\"...",);
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
match session.create("DeltaChat") {
Ok(_) => {
mvbox_folder = Some("DeltaChat".into());
info!(context, 0, "MVBOX-folder created.",);
info!(context, "MVBOX-folder created.",);
}
Err(err) => {
warn!(
context,
0,
"Cannot create MVBOX-folder, using trying INBOX subfolder. ({})",
err
"Cannot create MVBOX-folder, using trying INBOX subfolder. ({})", err
);
match session.create(&fallback_folder) {
@@ -1569,11 +1537,11 @@ impl Imap {
mvbox_folder = Some(fallback_folder);
info!(
context,
0, "MVBOX-folder created as INBOX subfolder. ({})", err
"MVBOX-folder created as INBOX subfolder. ({})", err
);
}
Err(err) => {
warn!(context, 0, "Cannot create MVBOX-folder. ({})", err);
warn!(context, "Cannot create MVBOX-folder. ({})", err);
}
}
}
@@ -1619,13 +1587,13 @@ impl Imap {
match session.list(Some(""), Some("*")) {
Ok(list) => {
if list.is_empty() {
warn!(context, 0, "Folder list is empty.",);
warn!(context, "Folder list is empty.",);
}
Some(list)
}
Err(err) => {
eprintln!("list error: {:?}", err);
warn!(context, 0, "Cannot get folder list.",);
warn!(context, "Cannot get folder list.",);
None
}

View File

@@ -156,12 +156,10 @@ impl Job {
/* if there is a msg-id and it does not exist in the db, cancel sending.
this happends if dc_delete_msgs() was called
before the generated mime was sent out */
if 0 != self.foreign_id
&& 0 == unsafe { dc_msg_exists(context, self.foreign_id) }
{
if 0 != self.foreign_id && !dc_msg_exists(context, self.foreign_id) {
warn!(
context,
0, "Message {} for job {} does not exist", self.foreign_id, self.job_id,
"Message {} for job {} does not exist", self.foreign_id, self.job_id,
);
return;
};
@@ -199,7 +197,7 @@ impl Job {
}
}
} else {
warn!(context, 0, "Missing recipients for job {}", self.job_id,);
warn!(context, "Missing recipients for job {}", self.job_id,);
}
}
}
@@ -279,7 +277,7 @@ impl Job {
if dc_rfc724_mid_cnt(context, msg.rfc724_mid) != 1 {
info!(
context,
0, "The message is deleted from the server when all parts are deleted.",
"The message is deleted from the server when all parts are deleted.",
);
delete_from_server = 0i32
}
@@ -442,18 +440,17 @@ pub fn perform_imap_fetch(context: &Context) {
.unwrap_or_else(|| 1)
== 0
{
info!(context, 0, "INBOX-watch disabled.",);
info!(context, "INBOX-watch disabled.",);
return;
}
info!(context, 0, "INBOX-fetch started...",);
info!(context, "INBOX-fetch started...",);
inbox.fetch(context);
if inbox.should_reconnect() {
info!(context, 0, "INBOX-fetch aborted, starting over...",);
info!(context, "INBOX-fetch aborted, starting over...",);
inbox.fetch(context);
}
info!(
context,
0,
"INBOX-fetch done in {:.4} ms.",
start.elapsed().as_nanos() as f64 / 1000.0,
);
@@ -467,13 +464,13 @@ pub fn perform_imap_idle(context: &Context) {
if *context.perform_inbox_jobs_needed.clone().read().unwrap() {
info!(
context,
0, "INBOX-IDLE will not be started because of waiting jobs."
"INBOX-IDLE will not be started because of waiting jobs."
);
return;
}
info!(context, 0, "INBOX-IDLE started...");
info!(context, "INBOX-IDLE started...");
inbox.idle(context);
info!(context, 0, "INBOX-IDLE ended.");
info!(context, "INBOX-IDLE ended.");
}
pub fn perform_mvbox_fetch(context: &Context) {
@@ -550,16 +547,16 @@ pub fn perform_smtp_jobs(context: &Context) {
state.perform_jobs_needed = 0;
if state.suspended {
info!(context, 0, "SMTP-jobs suspended.",);
info!(context, "SMTP-jobs suspended.",);
return;
}
state.doing_jobs = true;
probe_smtp_network
};
info!(context, 0, "SMTP-jobs started...",);
info!(context, "SMTP-jobs started...",);
job_perform(context, Thread::Smtp, probe_smtp_network);
info!(context, 0, "SMTP-jobs ended.");
info!(context, "SMTP-jobs ended.");
{
let &(ref lock, _) = &*context.smtp_state.clone();
@@ -570,7 +567,7 @@ pub fn perform_smtp_jobs(context: &Context) {
}
pub fn perform_smtp_idle(context: &Context) {
info!(context, 0, "SMTP-idle started...",);
info!(context, "SMTP-idle started...",);
{
let &(ref lock, ref cvar) = &*context.smtp_state.clone();
let mut state = lock.lock().unwrap();
@@ -578,7 +575,7 @@ pub fn perform_smtp_idle(context: &Context) {
if state.perform_jobs_needed == 1 {
info!(
context,
0, "SMTP-idle will not be started because of waiting jobs.",
"SMTP-idle will not be started because of waiting jobs.",
);
} else {
let dur = get_next_wakeup_time(context, Thread::Smtp);
@@ -596,7 +593,7 @@ pub fn perform_smtp_idle(context: &Context) {
}
}
info!(context, 0, "SMTP-idle ended.",);
info!(context, "SMTP-idle ended.",);
}
fn get_next_wakeup_time(context: &Context, thread: Thread) -> Duration {
@@ -655,7 +652,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
if mimefactory.is_err() || mimefactory.as_ref().unwrap().from_addr.is_null() {
warn!(
context,
0, "Cannot load data to send, maybe the message is deleted in between.",
"Cannot load data to send, maybe the message is deleted in between.",
);
} else {
let mut mimefactory = mimefactory.unwrap();
@@ -680,12 +677,12 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
mimefactory.msg.param.set_int(Param::Height, height as i32);
}
}
dc_msg_save_param_to_disk(&mut mimefactory.msg);
dc_msg_save_param_to_disk(context, &mut mimefactory.msg);
}
}
}
/* create message */
if 0 == dc_mimefactory_render(&mut mimefactory) {
if 0 == dc_mimefactory_render(context, &mut mimefactory) {
dc_set_msg_failed(context, msg_id, as_opt_str(mimefactory.error));
} else if 0
!= mimefactory
@@ -697,7 +694,6 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
{
warn!(
context,
0,
"e2e encryption unavailable {} - {:?}",
msg_id,
mimefactory.msg.param.get_int(Param::GuranteeE2ee),
@@ -728,7 +724,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
if let Err(err) =
location::set_kml_sent_timestamp(context, mimefactory.msg.chat_id, time())
{
error!(context, 0, "Failed to set kml sent_timestamp: {:?}", err);
error!(context, "Failed to set kml sent_timestamp: {:?}", err);
}
if !mimefactory.msg.hidden {
if let Err(err) = location::set_msg_location_id(
@@ -736,7 +732,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
mimefactory.msg.id,
mimefactory.out_last_added_location_id,
) {
error!(context, 0, "Failed to set msg_location_id: {:?}", err);
error!(context, "Failed to set msg_location_id: {:?}", err);
}
}
}
@@ -749,7 +745,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
== 0
{
mimefactory.msg.param.set_int(Param::GuranteeE2ee, 1);
dc_msg_save_param_to_disk(&mut mimefactory.msg);
dc_msg_save_param_to_disk(context, &mut mimefactory.msg);
}
success = add_smtp_job(context, Action::SendMsgToSmtp, &mut mimefactory);
}
@@ -759,14 +755,14 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
}
pub fn perform_imap_jobs(context: &Context) {
info!(context, 0, "dc_perform_imap_jobs starting.",);
info!(context, "dc_perform_imap_jobs starting.",);
let probe_imap_network = *context.probe_imap_network.clone().read().unwrap();
*context.probe_imap_network.write().unwrap() = false;
*context.perform_inbox_jobs_needed.write().unwrap() = false;
job_perform(context, Thread::Imap, probe_imap_network);
info!(context, 0, "dc_perform_imap_jobs ended.",);
info!(context, "dc_perform_imap_jobs ended.",);
}
fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
@@ -814,14 +810,13 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
match jobs {
Ok(ref _res) => {}
Err(ref err) => {
info!(context, 0, "query failed: {:?}", err);
info!(context, "query failed: {:?}", err);
}
}
for mut job in jobs.unwrap_or_default() {
info!(
context,
0,
"{}-job #{}, action {} started...",
if thread == Thread::Imap {
"INBOX"
@@ -860,7 +855,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
match job.action {
Action::Unknown => {
warn!(context, 0, "Unknown job id found");
warn!(context, "Unknown job id found");
}
Action::SendMsgToSmtp => job.do_DC_JOB_SEND(context),
Action::DeleteMsgOnImap => job.do_DC_JOB_DELETE_MSG_ON_IMAP(context),
@@ -904,7 +899,6 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
// just try over next loop unconditionally, the ui typically interrupts idle when the file (video) is ready
info!(
context,
0,
"{}-job #{} not yet ready and will be delayed.",
if thread == Thread::Imap {
"INBOX"
@@ -922,7 +916,6 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
job.update(context);
info!(
context,
0,
"{}-job #{} not succeeded on try #{}, retry in ADD_TIME+{} (in {} seconds).",
if thread == Thread::Imap {
"INBOX"
@@ -999,7 +992,7 @@ fn connect_to_inbox(context: &Context, inbox: &Imap) -> libc::c_int {
fn send_mdn(context: &Context, msg_id: uint32_t) {
if let Ok(mut mimefactory) = unsafe { dc_mimefactory_load_mdn(context, msg_id) } {
if 0 != unsafe { dc_mimefactory_render(&mut mimefactory) } {
if 0 != unsafe { dc_mimefactory_render(context, &mut mimefactory) } {
add_smtp_job(context, Action::SendMdn, &mut mimefactory);
}
}
@@ -1021,7 +1014,6 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_
if pathNfilename.is_null() {
error!(
context,
0,
"Could not find free file name for message with ID <{}>.",
to_string(mimefactory.rfc724_mid),
);
@@ -1037,7 +1029,6 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_
{
error!(
context,
0,
"Could not write message <{}> to \"{}\".",
to_string(mimefactory.rfc724_mid),
as_str(pathNfilename),
@@ -1081,7 +1072,7 @@ pub fn job_add(
delay_seconds: i64,
) {
if action == Action::Unknown {
error!(context, 0, "Invalid action passed to job_add");
error!(context, "Invalid action passed to job_add");
return;
}
@@ -1110,7 +1101,7 @@ pub fn job_add(
}
pub fn interrupt_smtp_idle(context: &Context) {
info!(context, 0, "Interrupting SMTP-idle...",);
info!(context, "Interrupting SMTP-idle...",);
let &(ref lock, ref cvar) = &*context.smtp_state.clone();
let mut state = lock.lock().unwrap();
@@ -1121,7 +1112,7 @@ pub fn interrupt_smtp_idle(context: &Context) {
}
pub fn interrupt_imap_idle(context: &Context) {
info!(context, 0, "Interrupting IMAP-IDLE...",);
info!(context, "Interrupting IMAP-IDLE...",);
*context.perform_inbox_jobs_needed.write().unwrap() = true;
context.inbox.read().unwrap().interrupt_idle();

View File

@@ -30,7 +30,7 @@ impl JobThread {
}
pub fn suspend(&self, context: &Context) {
info!(context, 0, "Suspending {}-thread.", self.name,);
info!(context, "Suspending {}-thread.", self.name,);
{
self.state.0.lock().unwrap().suspended = true;
}
@@ -45,7 +45,7 @@ impl JobThread {
}
pub fn unsuspend(&self, context: &Context) {
info!(context, 0, "Unsuspending {}-thread.", self.name);
info!(context, "Unsuspending {}-thread.", self.name);
let &(ref lock, ref cvar) = &*self.state.clone();
let mut state = lock.lock().unwrap();
@@ -60,7 +60,7 @@ impl JobThread {
self.state.0.lock().unwrap().jobs_needed = 1;
}
info!(context, 0, "Interrupting {}-IDLE...", self.name);
info!(context, "Interrupting {}-IDLE...", self.name);
self.imap.interrupt_idle();
@@ -86,16 +86,15 @@ impl JobThread {
if use_network {
let start = std::time::Instant::now();
if self.connect_to_imap(context) {
info!(context, 0, "{}-fetch started...", self.name);
info!(context, "{}-fetch started...", self.name);
self.imap.fetch(context);
if self.imap.should_reconnect() {
info!(context, 0, "{}-fetch aborted, starting over...", self.name,);
info!(context, "{}-fetch aborted, starting over...", self.name,);
self.imap.fetch(context);
}
info!(
context,
0,
"{}-fetch done in {:.3} ms.",
self.name,
start.elapsed().as_millis(),
@@ -142,7 +141,6 @@ impl JobThread {
if 0 != state.jobs_needed {
info!(
context,
0,
"{}-IDLE will not be started as it was interrupted while not ideling.",
self.name,
);
@@ -172,9 +170,9 @@ impl JobThread {
}
self.connect_to_imap(context);
info!(context, 0, "{}-IDLE started...", self.name,);
info!(context, "{}-IDLE started...", self.name,);
self.imap.idle(context);
info!(context, 0, "{}-IDLE ended.", self.name);
info!(context, "{}-IDLE ended.", self.name);
self.state.0.lock().unwrap().using_handle = false;
}

View File

@@ -1,7 +1,6 @@
use std::collections::BTreeMap;
use std::ffi::{CStr, CString};
use std::io::Cursor;
use std::slice;
use libc;
use pgp::composed::{Deserializable, SignedPublicKey, SignedSecretKey};
@@ -106,15 +105,6 @@ impl Key {
}
}
pub fn from_binary(data: *const u8, len: libc::c_int, key_type: KeyType) -> Option<Self> {
if data.is_null() || len == 0 {
return None;
}
let bytes = unsafe { slice::from_raw_parts(data, len as usize) };
Self::from_slice(bytes, key_type)
}
pub fn from_armored_string(
data: &str,
key_type: KeyType,
@@ -245,7 +235,7 @@ impl Key {
file_content_c.as_bytes().len(),
)
} {
error!(context, 0, "Cannot write key to {}", to_string(file));
error!(context, "Cannot write key to {}", to_string(file));
false
} else {
true
@@ -449,6 +439,27 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
assert_eq!(private_key, private_key2);
}
#[test]
fn test_from_slice_bad_data() {
let mut bad_data: [u8; 4096] = [0; 4096];
for i in 0..4096 {
bad_data[i] = (i & 0xff) as u8;
}
for j in 0..(4096 / 40) {
let bad_key = Key::from_slice(
&bad_data[j..j + 4096 / 2 + j],
if 0 != j & 1 {
KeyType::Public
} else {
KeyType::Private
},
);
assert!(bad_key.is_none());
}
}
#[test]
#[ignore] // is too expensive
fn test_ascii_roundtrip() {

View File

@@ -84,7 +84,6 @@ impl Kml {
Err(e) => {
error!(
context,
0,
"Location parsing: Error at position {}: {:?}",
reader.buffer_position(),
e
@@ -216,7 +215,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
.is_ok()
{
if 0 != seconds && !is_sending_locations_before {
msg = dc_msg_new(context, Viewtype::Text);
msg = dc_msg_new(Viewtype::Text);
msg.text =
Some(context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0));
msg.param.set_int(Param::Cmd, 8);
@@ -266,16 +265,16 @@ pub fn set(context: &Context, latitude: f64, longitude: f64, accuracy: f64) -> l
if latitude == 0.0 && longitude == 0.0 {
return 1;
}
let mut continue_streaming = false;
context.sql.query_map(
if let Ok(chats) = context.sql.query_map(
"SELECT id FROM chats WHERE locations_send_until>?;",
params![time()], |row| row.get::<_, i32>(0),
|chats| {
let mut continue_streaming = false;
for chat in chats {
let chat_id = chat?;
context.sql.execute(
params![time()],
|row| row.get::<_, i32>(0),
|chats| chats.collect::<Result<Vec<_>, _>>().map_err(Into::into),
) {
for chat_id in chats {
if let Err(err) = context.sql.execute(
"INSERT INTO locations \
(latitude, longitude, accuracy, timestamp, chat_id, from_id) VALUES (?,?,?,?,?,?);",
params![
@@ -286,16 +285,19 @@ pub fn set(context: &Context, latitude: f64, longitude: f64, accuracy: f64) -> l
chat_id,
1,
]
)?;
) {
warn!(context, "failed to store location {:?}", err);
} else {
continue_streaming = true;
}
if continue_streaming {
context.call_cb(Event::LOCATION_CHANGED, 1, 0);
};
schedule_MAYBE_SEND_LOCATIONS(context, 0);
Ok(continue_streaming as libc::c_int)
}
).unwrap_or_default()
if continue_streaming {
context.call_cb(Event::LOCATION_CHANGED, 1, 0);
};
schedule_MAYBE_SEND_LOCATIONS(context, 0);
}
continue_streaming as libc::c_int
}
pub fn get_range(
@@ -546,76 +548,81 @@ pub fn job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: &Job) {
let mut continue_streaming: libc::c_int = 1;
info!(
context,
0, " ----------------- MAYBE_SEND_LOCATIONS -------------- ",
" ----------------- MAYBE_SEND_LOCATIONS -------------- ",
);
context
.sql
.query_map(
"SELECT id, locations_send_begin, locations_last_sent \
FROM chats \
WHERE locations_send_until>?;",
params![now],
|row| {
let chat_id: i32 = row.get(0)?;
let locations_send_begin: i64 = row.get(1)?;
let locations_last_sent: i64 = row.get(2)?;
continue_streaming = 1;
if let Ok(rows) = context.sql.query_map(
"SELECT id, locations_send_begin, locations_last_sent \
FROM chats \
WHERE locations_send_until>?;",
params![now],
|row| {
let chat_id: i32 = row.get(0)?;
let locations_send_begin: i64 = row.get(1)?;
let locations_last_sent: i64 = row.get(2)?;
continue_streaming = 1;
// be a bit tolerant as the timer may not align exactly with time(NULL)
if now - locations_last_sent < (60 - 3) {
Ok(None)
} else {
Ok(Some((chat_id, locations_send_begin, locations_last_sent)))
}
},
|rows| {
context.sql.prepare(
"SELECT id \
FROM locations \
WHERE from_id=? \
AND timestamp>=? \
AND timestamp>? \
AND independent=0 \
ORDER BY timestamp;",
|mut stmt_locations, _| {
for (chat_id, locations_send_begin, locations_last_sent) in
rows.filter_map(|r| match r {
Ok(Some(v)) => Some(v),
_ => None,
})
{
// TODO: do I need to reset?
// be a bit tolerant as the timer may not align exactly with time(NULL)
if now - locations_last_sent < (60 - 3) {
Ok(None)
} else {
Ok(Some((chat_id, locations_send_begin, locations_last_sent)))
}
},
|rows| {
rows.filter_map(|v| v.transpose())
.collect::<Result<Vec<_>, _>>()
.map_err(Into::into)
},
) {
let msgs = context
.sql
.prepare(
"SELECT id \
FROM locations \
WHERE from_id=? \
AND timestamp>=? \
AND timestamp>? \
AND independent=0 \
ORDER BY timestamp;",
|mut stmt_locations, _| {
let msgs = rows
.into_iter()
.filter_map(|(chat_id, locations_send_begin, locations_last_sent)| {
if !stmt_locations
.exists(params![1, locations_send_begin, locations_last_sent,])
.unwrap_or_default()
{
// if there is no new location, there's nothing to send.
// however, maybe we want to bypass this test eg. 15 minutes
continue;
None
} else {
// pending locations are attached automatically to every message,
// so also to this empty text message.
// DC_CMD_LOCATION is only needed to create a nicer subject.
//
// for optimisation and to avoid flooding the sending queue,
// we could sending these messages only if we're really online.
// the easiest way to determine this, is to check for an empty message queue.
// (might not be 100%, however, as positions are sent combined later
// and dc_set_location() is typically called periodically, this is ok)
let mut msg = dc_msg_new(Viewtype::Text);
msg.hidden = true;
msg.param.set_int(Param::Cmd, 9);
Some((chat_id, msg))
}
// pending locations are attached automatically to every message,
// so also to this empty text message.
// DC_CMD_LOCATION is only needed to create a nicer subject.
//
// for optimisation and to avoid flooding the sending queue,
// we could sending these messages only if we're really online.
// the easiest way to determine this, is to check for an empty message queue.
// (might not be 100%, however, as positions are sent combined later
// and dc_set_location() is typically called periodically, this is ok)
let mut msg = dc_msg_new(context, Viewtype::Text);
msg.hidden = true;
msg.param.set_int(Param::Cmd, 9);
// TODO: handle cleanup on error
chat::send_msg(context, chat_id as u32, &mut msg).unwrap();
}
Ok(())
},
)
},
)
.unwrap(); // TODO: Better error handling
})
.collect::<Vec<_>>();
Ok(msgs)
},
)
.unwrap_or_default(); // TODO: Better error handling
for (chat_id, mut msg) in msgs.into_iter() {
// TODO: better error handling
chat::send_msg(context, chat_id as u32, &mut msg).unwrap();
}
}
if 0 != continue_streaming {
schedule_MAYBE_SEND_LOCATIONS(context, 0x1);
}

View File

@@ -1,46 +1,31 @@
#[macro_export]
macro_rules! info {
($ctx:expr, $data1:expr, $msg:expr) => {
info!($ctx, $data1, $msg,)
($ctx:expr, $msg:expr) => {
info!($ctx, $msg,)
};
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {
log_event!($ctx, $crate::constants::Event::INFO, 0, $msg, $($args),*);
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
#[allow(unused_unsafe)]
unsafe {
let formatted = format!($msg, $($args),*);
let formatted_c = std::ffi::CString::new(formatted).unwrap();
$ctx.call_cb($crate::constants::Event::INFO, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t);
}};
}
#[macro_export]
macro_rules! warn {
($ctx:expr, $data1:expr, $msg:expr) => {
warn!($ctx, $data1, $msg,)
($ctx:expr, $msg:expr) => {
warn!($ctx, $msg,)
};
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {
log_event!($ctx, $crate::constants::Event::WARNING, 0, $msg, $($args),*);
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
#[allow(unused_unsafe)]
unsafe {
let formatted = format!($msg, $($args),*);
let formatted_c = std::ffi::CString::new(formatted).unwrap();
$ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t);
}};
}
#[macro_export]
macro_rules! error {
($ctx:expr, $data1:expr, $msg:expr) => {
error!($ctx, $data1, $msg,)
($ctx:expr, $msg:expr) => {
error!($ctx, $msg,)
};
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {
log_event!($ctx, $crate::constants::Event::ERROR, 0, $msg, $($args),*);
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
#[allow(unused_unsafe)]
unsafe {
let formatted = format!($msg, $($args),*);
let formatted_c = std::ffi::CString::new(formatted).unwrap();
$ctx.call_cb($crate::constants::Event::ERROR, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t);
}};
}
#[macro_export]
@@ -49,13 +34,11 @@ 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 = std::ffi::CString::new(formatted).unwrap();
$ctx.call_cb($event, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t);
}};
let formatted = format!($msg, $($args),*);
let formatted_c = std::ffi::CString::new(formatted).unwrap();
$ctx.call_cb($event, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t);
};
}
#[macro_export]

View File

@@ -137,7 +137,7 @@ impl Lot {
/// approx. max. length returned by dc_msg_get_text()
/// approx. max. length returned by dc_get_msg_info()
#[derive(Clone)]
pub struct Message<'a> {
pub struct Message {
pub id: u32,
pub from_id: u32,
pub to_id: u32,
@@ -150,7 +150,6 @@ pub struct Message<'a> {
pub timestamp_sent: i64,
pub timestamp_rcvd: i64,
pub text: Option<String>,
pub context: &'a Context,
pub rfc724_mid: *mut libc::c_char,
pub in_reply_to: *mut libc::c_char,
pub server_folder: Option<String>,
@@ -270,7 +269,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
_ => {}
}
let p = dc_msg_get_file(&msg);
let p = dc_msg_get_file(context, &msg);
if !p.is_null() && 0 != *p.offset(0isize) as libc::c_int {
ret += &format!(
"\nFile: {}, {}, bytes\n",
@@ -310,11 +309,11 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
ret.strdup()
}
pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> Message<'a> {
dc_msg_new(context, Viewtype::Unknown)
pub fn dc_msg_new_untyped() -> Message {
dc_msg_new(Viewtype::Unknown)
}
pub fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> Message<'a> {
pub fn dc_msg_new(viewtype: Viewtype) -> Message {
Message {
id: 0,
from_id: 0,
@@ -328,7 +327,6 @@ pub fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> Message<'a> {
timestamp_sent: 0,
timestamp_rcvd: 0,
text: None,
context,
rfc724_mid: std::ptr::null_mut(),
in_reply_to: std::ptr::null_mut(),
server_folder: None,
@@ -341,7 +339,7 @@ pub fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> Message<'a> {
}
}
impl<'a> Drop for Message<'a> {
impl Drop for Message {
fn drop(&mut self) {
unsafe {
free(self.rfc724_mid.cast());
@@ -380,11 +378,11 @@ pub fn dc_msg_guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)>
KNOWN.get(extension).map(|x| *x)
}
pub unsafe fn dc_msg_get_file(msg: &Message) -> *mut libc::c_char {
pub unsafe fn dc_msg_get_file(context: &Context, msg: &Message) -> *mut libc::c_char {
let mut file_abs = ptr::null_mut();
if let Some(file_rel) = msg.param.get(Param::File) {
file_abs = dc_get_abs_path(msg.context, file_rel);
file_abs = dc_get_abs_path(context, file_rel);
}
if !file_abs.is_null() {
file_abs
@@ -440,7 +438,7 @@ pub fn dc_msg_get_timestamp(msg: &Message) -> i64 {
}
}
pub fn dc_msg_load_from_db<'a>(context: &'a Context, id: u32) -> Result<Message<'a>, Error> {
pub fn dc_msg_load_from_db(context: &Context, id: u32) -> Result<Message, Error> {
context.sql.query_row(
"SELECT \
m.id,rfc724_mid,m.mime_in_reply_to,m.server_folder,m.server_uid,m.move_state,m.chat_id, \
@@ -451,8 +449,7 @@ pub fn dc_msg_load_from_db<'a>(context: &'a Context, id: u32) -> Result<Message<
params![id as i32],
|row| {
unsafe {
let mut msg = dc_msg_new_untyped(context);
msg.context = context;
let mut msg = dc_msg_new_untyped();
msg.id = row.get::<_, i32>(0)? as u32;
msg.rfc724_mid = row.get::<_, String>(1)?.strdup();
msg.in_reply_to = match row.get::<_, Option<String>>(2)? {
@@ -477,7 +474,7 @@ pub fn dc_msg_load_from_db<'a>(context: &'a Context, id: u32) -> Result<Message<
if let Ok(t) = String::from_utf8(buf.to_vec()) {
text = t;
} else {
warn!(context, 0, "dc_msg_load_from_db: could not get text column as non-lossy utf8 id {}", id);
warn!(context, "dc_msg_load_from_db: could not get text column as non-lossy utf8 id {}", id);
text = String::from_utf8_lossy(buf).into_owned();
}
} else {
@@ -579,7 +576,7 @@ pub fn dc_markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize)
);
if msgs.is_err() {
warn!(context, 0, "markseen_msgs failed: {:?}", msgs);
warn!(context, "markseen_msgs failed: {:?}", msgs);
return false;
}
let mut send_event = false;
@@ -589,7 +586,7 @@ pub fn dc_markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize)
if curr_blocked == Blocked::Not {
if curr_state == MessageState::InFresh || curr_state == MessageState::InNoticed {
dc_update_msg_state(context, id, MessageState::InSeen);
info!(context, 0, "Seen message #{}.", id);
info!(context, "Seen message #{}.", id);
job_add(
context,
@@ -643,7 +640,7 @@ pub fn dc_star_msgs(
.is_ok()
}
pub fn dc_get_msg<'a>(context: &'a Context, msg_id: u32) -> Result<Message<'a>, Error> {
pub fn dc_get_msg(context: &Context, msg_id: u32) -> Result<Message, Error> {
dc_msg_load_from_db(context, msg_id)
}
@@ -701,11 +698,10 @@ pub unsafe fn dc_msg_get_filename(msg: &Message) -> *mut libc::c_char {
}
}
pub unsafe fn dc_msg_get_filebytes(msg: &Message) -> uint64_t {
pub fn dc_msg_get_filebytes(context: &Context, msg: &Message) -> uint64_t {
if let Some(file) = msg.param.get(Param::File) {
return dc_get_filebytes(msg.context, &file);
return dc_get_filebytes(context, &file);
}
0
}
@@ -730,14 +726,14 @@ pub fn dc_msg_get_showpadlock(msg: &Message) -> libc::c_int {
0
}
pub unsafe fn dc_msg_get_summary<'a>(msg: &mut Message<'a>, chat: Option<&Chat<'a>>) -> Lot {
pub fn dc_msg_get_summary(context: &Context, msg: &mut Message, chat: Option<&Chat>) -> Lot {
let mut ret = Lot::new();
let chat_loaded: Chat;
let chat = if let Some(chat) = chat {
chat
} else {
if let Ok(chat) = Chat::load_from_db(msg.context, msg.chat_id) {
if let Ok(chat) = Chat::load_from_db(context, msg.chat_id) {
chat_loaded = chat;
&chat_loaded
} else {
@@ -748,17 +744,18 @@ pub unsafe fn dc_msg_get_summary<'a>(msg: &mut Message<'a>, chat: Option<&Chat<'
let contact = if msg.from_id != DC_CONTACT_ID_SELF as libc::c_uint
&& ((*chat).typ == Chattype::Group || (*chat).typ == Chattype::VerifiedGroup)
{
Contact::get_by_id((*chat).context, msg.from_id).ok()
Contact::get_by_id(context, msg.from_id).ok()
} else {
None
};
ret.fill(msg, chat, contact.as_ref(), msg.context);
ret.fill(msg, chat, contact.as_ref(), context);
ret
}
pub unsafe fn dc_msg_get_summarytext(
context: &Context,
msg: &mut Message,
approx_characters: usize,
) -> *mut libc::c_char {
@@ -767,7 +764,7 @@ pub unsafe fn dc_msg_get_summarytext(
msg.text.as_ref(),
&mut msg.param,
approx_characters,
msg.context,
context,
)
.strdup()
}
@@ -898,7 +895,7 @@ pub fn dc_msg_is_setupmessage(msg: &Message) -> bool {
msg.param.get_int(Param::Cmd) == Some(6)
}
pub unsafe fn dc_msg_get_setupcodebegin(msg: &Message) -> *mut libc::c_char {
pub unsafe fn dc_msg_get_setupcodebegin(context: &Context, msg: &Message) -> *mut libc::c_char {
let mut filename: *mut libc::c_char = ptr::null_mut();
let mut buf: *mut libc::c_char = ptr::null_mut();
let mut buf_bytes: size_t = 0i32 as size_t;
@@ -908,11 +905,11 @@ pub unsafe fn dc_msg_get_setupcodebegin(msg: &Message) -> *mut libc::c_char {
let mut buf_setupcodebegin: *const libc::c_char = ptr::null();
let mut ret: *mut libc::c_char = ptr::null_mut();
if dc_msg_is_setupmessage(msg) {
filename = dc_msg_get_file(msg);
filename = dc_msg_get_file(context, msg);
if !(filename.is_null() || *filename.offset(0isize) as libc::c_int == 0i32) {
if !(0
== dc_read_file(
msg.context,
context,
filename,
&mut buf as *mut *mut libc::c_char as *mut *mut libc::c_void,
&mut buf_bytes,
@@ -977,6 +974,7 @@ pub fn dc_msg_set_duration(msg: &mut Message, duration: libc::c_int) {
}
pub fn dc_msg_latefiling_mediasize(
context: &Context,
msg: &mut Message,
width: libc::c_int,
height: libc::c_int,
@@ -989,20 +987,20 @@ pub fn dc_msg_latefiling_mediasize(
if duration > 0 {
msg.param.set_int(Param::Duration, duration);
}
dc_msg_save_param_to_disk(msg);
dc_msg_save_param_to_disk(context, msg);
}
pub fn dc_msg_save_param_to_disk(msg: &mut Message) -> bool {
pub fn dc_msg_save_param_to_disk(context: &Context, msg: &mut Message) -> bool {
sql::execute(
msg.context,
&msg.context.sql,
context,
&context.sql,
"UPDATE msgs SET param=? WHERE id=?;",
params![msg.param.to_string(), msg.id as i32],
)
.is_ok()
}
pub fn dc_msg_new_load<'a>(context: &'a Context, msg_id: u32) -> Result<Message<'a>, Error> {
pub fn dc_msg_new_load(context: &Context, msg_id: u32) -> Result<Message, Error> {
dc_msg_load_from_db(context, msg_id)
}
@@ -1032,25 +1030,23 @@ The value is also used for CC:-summaries */
// Context functions to work with messages
pub unsafe fn dc_msg_exists(context: &Context, msg_id: u32) -> libc::c_int {
if msg_id <= 9 {
return 0;
pub fn dc_msg_exists(context: &Context, msg_id: u32) -> bool {
if msg_id <= DC_CHAT_ID_LAST_SPECIAL {
return false;
}
let chat_id: Option<i32> = context.sql.query_row_col(
let chat_id: Option<u32> = context.sql.query_row_col(
context,
"SELECT chat_id FROM msgs WHERE id=?;",
params![msg_id as i32],
params![msg_id],
0,
);
if let Some(chat_id) = chat_id {
if chat_id != 3 {
return 1;
}
chat_id != DC_CHAT_ID_TRASH
} else {
false
}
0
}
pub fn dc_update_msg_move_state(
@@ -1076,7 +1072,7 @@ pub fn dc_set_msg_failed(context: &Context, msg_id: u32, error: Option<impl AsRe
}
if let Some(error) = error {
msg.param.set(Param::Error, error.as_ref());
error!(context, 0, "{}", error.as_ref());
error!(context, "{}", error.as_ref());
}
if sql::execute(
@@ -1205,7 +1201,7 @@ pub fn dc_get_real_msg_cnt(context: &Context) -> libc::c_int {
) {
Ok(res) => res,
Err(err) => {
error!(context, 0, "dc_get_real_msg_cnt() failed. {}", err);
error!(context, "dc_get_real_msg_cnt() failed. {}", err);
0
}
}
@@ -1221,7 +1217,7 @@ pub fn dc_get_deaddrop_msg_cnt(context: &Context) -> size_t {
) {
Ok(res) => res as size_t,
Err(err) => {
error!(context, 0, "dc_get_deaddrop_msg_cnt() failed. {}", err);
error!(context, "dc_get_deaddrop_msg_cnt() failed. {}", err);
0
}
}
@@ -1236,7 +1232,7 @@ pub fn dc_rfc724_mid_cnt(context: &Context, rfc724_mid: *const libc::c_char) ->
) {
Ok(res) => res,
Err(err) => {
error!(context, 0, "dc_get_rfc724_mid_cnt() failed. {}", err);
error!(context, "dc_get_rfc724_mid_cnt() failed. {}", err);
0
}
}
@@ -1290,7 +1286,7 @@ pub fn dc_update_server_uid(
) {
Ok(_) => {}
Err(err) => {
warn!(context, 0, "msg: failed to update server_uid: {}", err);
warn!(context, "msg: failed to update server_uid: {}", err);
}
}
}
@@ -1323,7 +1319,7 @@ mod tests {
let chat = chat::create_by_contact_id(ctx, contact).unwrap();
let mut msg = dc_msg_new(ctx, Viewtype::Text);
let mut msg = dc_msg_new(Viewtype::Text);
let msg_id = chat::prepare_msg(ctx, chat, &mut msg).unwrap();

View File

@@ -97,10 +97,7 @@ pub fn dc_get_oauth2_access_token(
let (redirect_uri, token_url, update_redirect_uri_on_success) =
if refresh_token.is_none() || refresh_token_for != code.as_ref() {
info!(
context,
0, "Generate OAuth2 refresh_token and access_token...",
);
info!(context, "Generate OAuth2 refresh_token and access_token...",);
(
context
.sql
@@ -112,7 +109,7 @@ pub fn dc_get_oauth2_access_token(
} else {
info!(
context,
0, "Regenerate OAuth2 access_token by refresh_token...",
"Regenerate OAuth2 access_token by refresh_token...",
);
(
context
@@ -134,7 +131,7 @@ pub fn dc_get_oauth2_access_token(
if response.is_err() {
warn!(
context,
0, "Error calling OAuth2 at {}: {:?}", token_url, response
"Error calling OAuth2 at {}: {:?}", token_url, response
);
return None;
}
@@ -142,7 +139,6 @@ pub fn dc_get_oauth2_access_token(
if !response.status().is_success() {
warn!(
context,
0,
"Error calling OAuth2 at {}: {:?}",
token_url,
response.status()
@@ -154,7 +150,7 @@ pub fn dc_get_oauth2_access_token(
if parsed.is_err() {
warn!(
context,
0, "Failed to parse OAuth2 JSON response from {}: error: {:?}", token_url, parsed
"Failed to parse OAuth2 JSON response from {}: error: {:?}", token_url, parsed
);
return None;
}
@@ -195,12 +191,12 @@ pub fn dc_get_oauth2_access_token(
.ok();
}
} else {
warn!(context, 0, "Failed to find OAuth2 access token");
warn!(context, "Failed to find OAuth2 access token");
}
response.access_token
} else {
warn!(context, 0, "Internal OAuth2 error: 2");
warn!(context, "Internal OAuth2 error: 2");
None
}
@@ -268,17 +264,12 @@ impl Oauth2 {
// }
let response = reqwest::Client::new().get(&userinfo_url).send();
if response.is_err() {
warn!(context, 0, "Error getting userinfo: {:?}", response);
warn!(context, "Error getting userinfo: {:?}", response);
return None;
}
let mut response = response.unwrap();
if !response.status().is_success() {
warn!(
context,
0,
"Error getting userinfo: {:?}",
response.status()
);
warn!(context, "Error getting userinfo: {:?}", response.status());
return None;
}
@@ -286,19 +277,19 @@ impl Oauth2 {
if parsed.is_err() {
warn!(
context,
0, "Failed to parse userinfo JSON response: {:?}", parsed
"Failed to parse userinfo JSON response: {:?}", parsed
);
return None;
}
if let Ok(response) = parsed {
let addr = response.get("email");
if addr.is_none() {
warn!(context, 0, "E-mail missing in userinfo.");
warn!(context, "E-mail missing in userinfo.");
}
addr.map(|addr| addr.to_string())
} else {
warn!(context, 0, "Failed to parse userinfo.");
warn!(context, "Failed to parse userinfo.");
None
}
}

View File

@@ -1,6 +1,5 @@
use std::collections::HashSet;
use std::convert::TryInto;
use std::ffi::CStr;
use std::io::Cursor;
use std::ptr;
@@ -274,32 +273,25 @@ pub fn dc_pgp_pk_decrypt(
}
/// Symmetric encryption.
pub fn dc_pgp_symm_encrypt(passphrase: *const libc::c_char, plain: &[u8]) -> Option<String> {
assert!(!passphrase.is_null(), "invalid passphrase");
let pw = unsafe { CStr::from_ptr(passphrase).to_str().unwrap() };
pub fn dc_pgp_symm_encrypt(passphrase: &str, plain: &[u8]) -> Option<String> {
let mut rng = thread_rng();
let lit_msg = Message::new_literal_bytes("", plain);
let s2k = StringToKey::new_default(&mut rng);
let msg = lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || pw.into());
let msg =
lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || passphrase.into());
msg.and_then(|msg| msg.to_armored_string(None)).ok()
}
/// Symmetric decryption.
pub fn dc_pgp_symm_decrypt(passphrase: *const libc::c_char, ctext: &[u8]) -> Option<Vec<u8>> {
assert!(!passphrase.is_null(), "invalid passphrase");
let pw = unsafe { CStr::from_ptr(passphrase).to_str().unwrap() };
pub fn dc_pgp_symm_decrypt(passphrase: &str, ctext: &[u8]) -> Option<Vec<u8>> {
let enc_msg = Message::from_bytes(Cursor::new(ctext));
enc_msg
.and_then(|msg| {
let mut decryptor = msg
.decrypt_with_password(|| pw.into())
.decrypt_with_password(|| passphrase.into())
.expect("failed decryption");
decryptor.next().expect("no message")
})

View File

@@ -37,7 +37,7 @@ impl Into<Lot> for Error {
pub fn check_qr(context: &Context, qr: impl AsRef<str>) -> Lot {
let qr = qr.as_ref();
info!(context, 0, "Scanned QR code: {}", qr);
info!(context, "Scanned QR code: {}", qr);
if qr.starts_with(OPENPGP4FPR_SCHEME) {
decode_openpgp(context, qr)

View File

@@ -85,7 +85,7 @@ pub fn dc_get_securejoin_qr(context: &Context, group_chat_id: uint32_t) -> Optio
let self_addr = match context.sql.get_config(context, "configured_addr") {
Some(addr) => addr,
None => {
error!(context, 0, "Not configured, cannot generate QR code.",);
error!(context, "Not configured, cannot generate QR code.",);
return None;
}
};
@@ -123,10 +123,7 @@ pub fn dc_get_securejoin_qr(context: &Context, group_chat_id: uint32_t) -> Optio
&auth,
))
} else {
error!(
context,
0, "Cannot get QR-code for chat-id {}", group_chat_id,
);
error!(context, "Cannot get QR-code for chat-id {}", group_chat_id,);
return None;
}
} else {
@@ -136,7 +133,7 @@ pub fn dc_get_securejoin_qr(context: &Context, group_chat_id: uint32_t) -> Optio
))
};
info!(context, 0, "Generated QR code: {}", qr.as_ref().unwrap());
info!(context, "Generated QR code: {}", qr.as_ref().unwrap());
qr
}
@@ -182,7 +179,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> uint32_t {
let mut contact_chat_id: uint32_t = 0;
let mut join_vg: bool = false;
info!(context, 0, "Requesting secure-join ...",);
info!(context, "Requesting secure-join ...",);
ensure_secret_key_exists(context).ok();
if !dc_alloc_ongoing(context) {
return cleanup(&context, contact_chat_id, false, join_vg);
@@ -190,12 +187,12 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> uint32_t {
let qr_scan = check_qr(context, &qr);
if qr_scan.state != LotState::QrAskVerifyContact && qr_scan.state != LotState::QrAskVerifyGroup
{
error!(context, 0, "Unknown QR code.",);
error!(context, "Unknown QR code.",);
return cleanup(&context, contact_chat_id, true, join_vg);
}
contact_chat_id = chat::create_by_contact_id(context, qr_scan.id).unwrap_or_default();
if contact_chat_id == 0 {
error!(context, 0, "Unknown contact.",);
error!(context, "Unknown contact.",);
return cleanup(&context, contact_chat_id, true, join_vg);
}
if check_exit(context) {
@@ -221,7 +218,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> uint32_t {
.unwrap(),
contact_chat_id,
) {
info!(context, 0, "Taking protocol shortcut.");
info!(context, "Taking protocol shortcut.");
context.bob.write().unwrap().expects = DC_VC_CONTACT_CONFIRM;
joiner_progress!(context, chat_id_2_contact_id(context, contact_chat_id), 400);
let own_fingerprint = get_self_fingerprint(context).unwrap();
@@ -277,7 +274,7 @@ fn send_handshake_msg(
fingerprint: Option<String>,
grpid: impl AsRef<str>,
) {
let mut msg = unsafe { dc_msg_new_untyped(context) };
let mut msg = dc_msg_new_untyped();
msg.type_0 = Viewtype::Text;
msg.text = Some(format!("Secure-Join: {}", step));
msg.hidden = true;
@@ -359,7 +356,7 @@ pub fn handle_securejoin_handshake(
};
info!(
context,
0, ">>>>>>>>>>>>>>>>>>>>>>>>> secure-join message \'{}\' received", step,
">>>>>>>>>>>>>>>>>>>>>>>>> secure-join message \'{}\' received", step,
);
let (contact_chat_id, contact_chat_id_blocked) =
chat::create_or_lookup_by_contact_id(context, contact_id, Blocked::Not).unwrap_or_default();
@@ -383,15 +380,15 @@ pub fn handle_securejoin_handshake(
let invitenumber = match lookup_field(mimeparser, "Secure-Join-Invitenumber") {
Some(n) => n,
None => {
warn!(context, 0, "Secure-join denied (invitenumber missing).",);
warn!(context, "Secure-join denied (invitenumber missing).",);
return ret;
}
};
if !token::exists(context, token::Namespace::InviteNumber, &invitenumber) {
warn!(context, 0, "Secure-join denied (bad invitenumber).",);
warn!(context, "Secure-join denied (bad invitenumber).",);
return ret;
}
info!(context, 0, "Secure-join requested.",);
info!(context, "Secure-join requested.",);
inviter_progress!(context, contact_id, 300);
send_handshake_msg(
@@ -413,7 +410,7 @@ pub fn handle_securejoin_handshake(
};
if cond {
warn!(context, 0, "auth-required message out of sync.",);
warn!(context, "auth-required message out of sync.",);
// no error, just aborted somehow or a mail from another handshake
return ret;
}
@@ -442,7 +439,7 @@ pub fn handle_securejoin_handshake(
end_bobs_joining(context, DC_BOB_ERROR);
return ret;
}
info!(context, 0, "Fingerprint verified.",);
info!(context, "Fingerprint verified.",);
own_fingerprint = get_self_fingerprint(context).unwrap();
joiner_progress!(context, contact_id, 400);
context.bob.write().unwrap().expects = DC_VC_CONTACT_CONFIRM;
@@ -494,7 +491,7 @@ pub fn handle_securejoin_handshake(
);
return ret;
}
info!(context, 0, "Fingerprint verified.",);
info!(context, "Fingerprint verified.",);
// verify that the `Secure-Join-Auth:`-header matches the secret written to the QR code
let auth_0 = match lookup_field(mimeparser, "Secure-Join-Auth") {
Some(auth) => auth,
@@ -520,7 +517,7 @@ pub fn handle_securejoin_handshake(
return ret;
}
Contact::scaleup_origin_by_id(context, contact_id, Origin::SecurejoinInvited);
info!(context, 0, "Auth verified.",);
info!(context, "Auth verified.",);
secure_connection_established(context, contact_chat_id);
emit_event!(context, Event::CONTACTS_CHANGED, contact_id, 0);
inviter_progress!(context, contact_id, 600);
@@ -528,7 +525,7 @@ pub fn handle_securejoin_handshake(
let field_grpid = lookup_field(mimeparser, "Secure-Join-Group").unwrap_or_default();
let (group_chat_id, _, _) = chat::get_chat_id_by_grpid(context, &field_grpid);
if group_chat_id == 0 {
error!(context, 0, "Chat {} not found.", &field_grpid);
error!(context, "Chat {} not found.", &field_grpid);
return ret;
} else {
chat::add_contact_to_chat_ex(context, group_chat_id, contact_id, 0x1i32);
@@ -543,7 +540,7 @@ pub fn handle_securejoin_handshake(
ret = DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING;
}
if context.bob.read().unwrap().expects != DC_VC_CONTACT_CONFIRM {
info!(context, 0, "Message belongs to a different handshake.",);
info!(context, "Message belongs to a different handshake.",);
return ret;
}
let cond = {
@@ -554,7 +551,7 @@ pub fn handle_securejoin_handshake(
if cond {
warn!(
context,
0, "Message out of sync or belongs to a different handshake.",
"Message out of sync or belongs to a different handshake.",
);
return ret;
}
@@ -597,7 +594,7 @@ pub fn handle_securejoin_handshake(
let cg_member_added =
lookup_field(mimeparser, "Chat-Group-Member-Added").unwrap_or_default();
if join_vg && !addr_equals_self(context, cg_member_added) {
info!(context, 0, "Message belongs to a different handshake (scaled up contact anyway to allow creation of group).");
info!(context, "Message belongs to a different handshake (scaled up contact anyway to allow creation of group).");
return ret;
}
secure_connection_established(context, contact_chat_id);
@@ -620,19 +617,19 @@ pub fn handle_securejoin_handshake(
==== Step 8 in "Out-of-band verified groups" protocol ====
============================================================ */
if let Ok(contact) = Contact::get_by_id(context, contact_id) {
if contact.is_verified() == VerifiedStatus::Unverified {
warn!(context, 0, "vg-member-added-received invalid.",);
if contact.is_verified(context) == VerifiedStatus::Unverified {
warn!(context, "vg-member-added-received invalid.",);
return ret;
}
inviter_progress!(context, contact_id, 800);
inviter_progress!(context, contact_id, 1000);
} else {
warn!(context, 0, "vg-member-added-received invalid.",);
warn!(context, "vg-member-added-received invalid.",);
return ret;
}
}
_ => {
warn!(context, 0, "invalid step: {}", step);
warn!(context, "invalid step: {}", step);
}
}
if ret == DC_HANDSHAKE_STOP_NORMAL_PROCESSING {
@@ -694,7 +691,7 @@ fn could_not_establish_secure_connection(
);
chat::add_device_msg(context, contact_chat_id, &msg);
error!(context, 0, "{} ({})", &msg, details);
error!(context, "{} ({})", &msg, details);
}
fn mark_peer_as_verified(context: &Context, fingerprint: impl AsRef<str>) -> Result<(), Error> {
@@ -723,13 +720,13 @@ fn encrypted_and_signed(
expected_fingerprint: impl AsRef<str>,
) -> bool {
if !mimeparser.e2ee_helper.encrypted {
warn!(mimeparser.context, 0, "Message not encrypted.",);
warn!(mimeparser.context, "Message not encrypted.",);
false
} else if mimeparser.e2ee_helper.signatures.len() <= 0 {
warn!(mimeparser.context, 0, "Message not signed.",);
warn!(mimeparser.context, "Message not signed.",);
false
} else if expected_fingerprint.as_ref().is_empty() {
warn!(mimeparser.context, 0, "Fingerprint for comparison missing.",);
warn!(mimeparser.context, "Fingerprint for comparison missing.",);
false
} else if !mimeparser
.e2ee_helper
@@ -738,7 +735,6 @@ fn encrypted_and_signed(
{
warn!(
mimeparser.context,
0,
"Message does not match expected fingerprint {}.",
expected_fingerprint.as_ref(),
);

View File

@@ -45,7 +45,7 @@ impl Smtp {
/// Connect using the provided login params
pub fn connect(&mut self, context: &Context, lp: &LoginParam) -> bool {
if self.is_connected() {
warn!(context, 0, "SMTP already connected.");
warn!(context, "SMTP already connected.");
return true;
}
@@ -119,7 +119,7 @@ impl Smtp {
true
}
Err(err) => {
warn!(context, 0, "SMTP: failed to establish connection {:?}", err);
warn!(context, "SMTP: failed to establish connection {:?}", err);
false
}
}
@@ -151,7 +151,7 @@ impl Smtp {
1
}
Err(err) => {
warn!(context, 0, "SMTP failed to send message: {}", err);
warn!(context, "SMTP failed to send message: {}", err);
self.error = Some(format!("{}", err));
0
}

View File

@@ -35,7 +35,7 @@ impl Sql {
self.in_use.remove();
// drop closes the connection
info!(context, 0, "Database closed.");
info!(context, "Database closed.");
}
// return true on success, false on failure
@@ -176,7 +176,7 @@ impl Sql {
rusqlite::types::Type::Null,
))) => None,
Err(err) => {
error!(context, 0, "sql: Failed query_row: {}", err);
error!(context, "sql: Failed query_row: {}", err);
None
}
}
@@ -193,7 +193,7 @@ impl Sql {
value: Option<&str>,
) -> Result<()> {
if !self.is_open() {
error!(context, 0, "set_config(): Database not ready.");
error!(context, "set_config(): Database not ready.");
return Err(Error::SqlNoConnection);
}
@@ -227,7 +227,7 @@ impl Sql {
match res {
Ok(_) => Ok(()),
Err(err) => {
error!(context, 0, "set_config(): Cannot change value. {:?}", &err);
error!(context, "set_config(): Cannot change value. {:?}", &err);
Err(err.into())
}
}
@@ -259,6 +259,20 @@ impl Sql {
self.get_config(context, key).and_then(|s| s.parse().ok())
}
pub fn get_config_bool(&self, context: &Context, key: impl AsRef<str>) -> bool {
// Not the most obvious way to encode bool as string, but it is matter
// of backward compatibility.
self.get_config_int(context, key).unwrap_or_default() > 0
}
pub fn set_config_bool<T>(&self, context: &Context, key: T, value: bool) -> Result<()>
where
T: AsRef<str>,
{
let value = if value { Some("1") } else { None };
self.set_config(context, key, value)
}
pub fn set_config_int64(
&self,
context: &Context,
@@ -303,7 +317,6 @@ fn open(
if sql.is_open() {
error!(
context,
0,
"Cannot open, database \"{:?}\" already opened.",
dbfile.as_ref(),
);
@@ -337,7 +350,6 @@ fn open(
if !sql.table_exists("config") {
info!(
context,
0,
"First time init: creating tables in {:?}.",
dbfile.as_ref(),
);
@@ -453,7 +465,6 @@ fn open(
{
error!(
context,
0,
"Cannot create tables in new database \"{:?}\".",
dbfile.as_ref(),
);
@@ -674,7 +685,7 @@ fn open(
sql.set_config_int(context, "dbversion", 46)?;
}
if dbversion < 47 {
info!(context, 0, "[migration] v47");
info!(context, "[migration] v47");
sql.execute(
"ALTER TABLE jobs ADD COLUMN tries INTEGER DEFAULT 0;",
params![],
@@ -683,7 +694,7 @@ fn open(
sql.set_config_int(context, "dbversion", 47)?;
}
if dbversion < 48 {
info!(context, 0, "[migration] v48");
info!(context, "[migration] v48");
sql.execute(
"ALTER TABLE msgs ADD COLUMN move_state INTEGER DEFAULT 1;",
params![],
@@ -693,7 +704,7 @@ fn open(
sql.set_config_int(context, "dbversion", 48)?;
}
if dbversion < 49 {
info!(context, 0, "[migration] v49");
info!(context, "[migration] v49");
sql.execute(
"ALTER TABLE chats ADD COLUMN gossiped_timestamp INTEGER DEFAULT 0;",
params![],
@@ -702,7 +713,7 @@ fn open(
sql.set_config_int(context, "dbversion", 49)?;
}
if dbversion < 50 {
info!(context, 0, "[migration] v50");
info!(context, "[migration] v50");
if 0 != exists_before_update {
sql.set_config_int(context, "show_emails", 2)?;
}
@@ -710,7 +721,7 @@ fn open(
sql.set_config_int(context, "dbversion", 50)?;
}
if dbversion < 53 {
info!(context, 0, "[migration] v53");
info!(context, "[migration] v53");
sql.execute(
"CREATE TABLE locations ( id INTEGER PRIMARY KEY AUTOINCREMENT, latitude REAL DEFAULT 0.0, longitude REAL DEFAULT 0.0, accuracy REAL DEFAULT 0.0, timestamp INTEGER DEFAULT 0, chat_id INTEGER DEFAULT 0, from_id INTEGER DEFAULT 0);",
params![]
@@ -743,7 +754,7 @@ fn open(
sql.set_config_int(context, "dbversion", 53)?;
}
if dbversion < 54 {
info!(context, 0, "[migration] v54");
info!(context, "[migration] v54");
sql.execute(
"ALTER TABLE msgs ADD COLUMN location_id INTEGER DEFAULT 0;",
params![],
@@ -783,7 +794,7 @@ fn open(
// for newer versions, we copy files always to the blob directory and store relative paths.
// this snippet converts older databases and can be removed after some time.
info!(context, 0, "[open] update file paths");
info!(context, "[open] update file paths");
let repl_from = sql
.get_config(context, "backup_for")
@@ -810,7 +821,7 @@ fn open(
}
}
info!(context, 0, "Opened {:?}.", dbfile.as_ref(),);
info!(context, "Opened {:?}.", dbfile.as_ref(),);
Ok(())
}
@@ -825,7 +836,6 @@ where
Err(err) => {
error!(
context,
0,
"execute failed: {:?} for {}",
&err,
querystr.as_ref()
@@ -842,7 +852,6 @@ pub fn try_execute(context: &Context, sql: &Sql, querystr: impl AsRef<str>) -> R
Err(err) => {
warn!(
context,
0,
"Try-execute for \"{}\" failed: {}",
querystr.as_ref(),
&err,
@@ -886,7 +895,7 @@ pub fn get_rowid_with_conn(
Err(err) => {
error!(
context,
0, "sql: Failed to retrieve rowid: {} in {}", err, query
"sql: Failed to retrieve rowid: {} in {}", err, query
);
0
}
@@ -933,7 +942,7 @@ pub fn get_rowid2_with_conn(
) {
Ok(id) => id,
Err(err) => {
error!(context, 0, "sql: Failed to retrieve rowid2: {}", err);
error!(context, "sql: Failed to retrieve rowid2: {}", err);
0
}
}
@@ -943,7 +952,7 @@ pub fn housekeeping(context: &Context) {
let mut files_in_use = HashSet::new();
let mut unreferenced_count = 0;
info!(context, 0, "Start housekeeping...");
info!(context, "Start housekeeping...");
maybe_add_from_param(
context,
&mut files_in_use,
@@ -983,10 +992,10 @@ pub fn housekeeping(context: &Context) {
},
)
.unwrap_or_else(|err| {
warn!(context, 0, "sql: failed query: {}", err);
warn!(context, "sql: failed query: {}", err);
});
info!(context, 0, "{} files in use.", files_in_use.len(),);
info!(context, "{} files in use.", files_in_use.len(),);
/* go through directory and delete unused files */
let p = std::path::Path::new(as_str(context.get_blobdir()));
match std::fs::read_dir(p) {
@@ -1025,7 +1034,6 @@ pub fn housekeeping(context: &Context) {
if recently_created || recently_modified || recently_accessed {
info!(
context,
0,
"Housekeeping: Keeping new unreferenced file #{}: {:?}",
unreferenced_count,
entry.file_name(),
@@ -1037,7 +1045,6 @@ pub fn housekeeping(context: &Context) {
}
info!(
context,
0,
"Housekeeping: Deleting unreferenced file #{}: {:?}",
unreferenced_count,
entry.file_name()
@@ -1049,7 +1056,6 @@ pub fn housekeeping(context: &Context) {
Err(err) => {
warn!(
context,
0,
"Housekeeping: Cannot open {}. ({})",
as_str(context.get_blobdir()),
err
@@ -1057,7 +1063,7 @@ pub fn housekeeping(context: &Context) {
}
}
info!(context, 0, "Housekeeping done.",);
info!(context, "Housekeeping done.",);
}
fn is_file_in_use(files_in_use: &HashSet<String>, namespc_opt: Option<&str>, name: &str) -> bool {
@@ -1105,7 +1111,7 @@ fn maybe_add_from_param(
},
)
.unwrap_or_else(|err| {
warn!(context, 0, "sql: failed to add_from_param: {}", err);
warn!(context, "sql: failed to add_from_param: {}", err);
});
}

View File

@@ -6,13 +6,15 @@ import os
import re
if __name__ == "__main__":
if Path('src/top_evil_rs.py').exists():
os.chdir('src')
filestats = []
for fn in Path(".").glob("**/*.rs"):
s = fn.read_text()
s = re.sub(r"(?m)///.*$", "", s) # remove comments
unsafe = s.count("unsafe")
free = s.count("free(")
gotoblocks = s.count("ok_to_continue")
gotoblocks = s.count("ok_to_continue") + s.count('OK_TO_CONTINUE')
filestats.append((fn, unsafe, free, gotoblocks))
sum_unsafe, sum_free, sum_gotoblocks = 0, 0, 0

View File

@@ -12,7 +12,6 @@ use deltachat::contact::*;
use deltachat::context::*;
use deltachat::dc_imex::*;
use deltachat::dc_tools::*;
use deltachat::key::*;
use deltachat::keyring::*;
use deltachat::oauth2::*;
use deltachat::pgp::*;
@@ -91,7 +90,7 @@ unsafe fn stress_functions(context: &Context) {
assert!(dc_delete_file(context, "$BLOBDIR/dada"));
assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder"));
assert!(dc_file_exist(context, "$BLOBDIR/foobar-folder",));
assert!(dc_delete_file(context, "$BLOBDIR/foobar-folder"));
assert!(!dc_delete_file(context, "$BLOBDIR/foobar-folder"));
let fn0: *mut libc::c_char = dc_get_fine_pathNfilename(
context,
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
@@ -129,7 +128,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 = context.get_config(&config::Config::SysConfigKeys).unwrap();
assert!(!res.contains(" probably_never_a_key "));
assert!(res.contains(" addr "));
@@ -461,136 +460,111 @@ unsafe fn stress_functions(context: &Context) {
#[test]
#[ignore] // is too expensive
fn test_encryption_decryption() {
unsafe {
let mut bad_data: [libc::c_uchar; 4096] = [0; 4096];
let mut i_0: libc::c_int = 0i32;
while i_0 < 4096i32 {
bad_data[i_0 as usize] = (i_0 & 0xffi32) as libc::c_uchar;
i_0 += 1
}
let mut j: libc::c_int = 0i32;
let (public_key, private_key) = dc_pgp_create_keypair("foo@bar.de").unwrap();
while j < 4096 / 40 {
let bad_key = Key::from_binary(
&mut *bad_data.as_mut_ptr().offset(j as isize) as *const u8,
4096 / 2 + j,
if 0 != j & 1 {
KeyType::Public
} else {
KeyType::Private
},
);
private_key.split_key().unwrap();
assert!(bad_key.is_none());
j += 1
}
let (public_key2, private_key2) = dc_pgp_create_keypair("two@zwo.de").unwrap();
let (public_key, private_key) = dc_pgp_create_keypair("foo@bar.de").unwrap();
assert_ne!(public_key, public_key2);
private_key.split_key().unwrap();
let original_text = b"This is a test";
let mut keyring = Keyring::default();
keyring.add_owned(public_key.clone());
keyring.add_ref(&public_key2);
let (public_key2, private_key2) = dc_pgp_create_keypair("two@zwo.de").unwrap();
let ctext_signed = dc_pgp_pk_encrypt(original_text, &keyring, Some(&private_key)).unwrap();
assert!(!ctext_signed.is_empty());
assert!(ctext_signed.starts_with("-----BEGIN PGP MESSAGE-----"));
assert_ne!(public_key, public_key2);
let ctext_unsigned = dc_pgp_pk_encrypt(original_text, &keyring, None).unwrap();
assert!(!ctext_unsigned.is_empty());
assert!(ctext_unsigned.starts_with("-----BEGIN PGP MESSAGE-----"));
let original_text = b"This is a test";
let mut keyring = Keyring::default();
keyring.add_owned(public_key.clone());
keyring.add_ref(&public_key2);
let mut keyring = Keyring::default();
keyring.add_owned(private_key);
let ctext_signed = dc_pgp_pk_encrypt(original_text, &keyring, Some(&private_key)).unwrap();
assert!(!ctext_signed.is_empty());
assert!(ctext_signed.starts_with("-----BEGIN PGP MESSAGE-----"));
let mut public_keyring = Keyring::default();
public_keyring.add_ref(&public_key);
let ctext_unsigned = dc_pgp_pk_encrypt(original_text, &keyring, None).unwrap();
assert!(!ctext_unsigned.is_empty());
assert!(ctext_unsigned.starts_with("-----BEGIN PGP MESSAGE-----"));
let mut public_keyring2 = Keyring::default();
public_keyring2.add_owned(public_key2.clone());
let mut keyring = Keyring::default();
keyring.add_owned(private_key);
let mut valid_signatures: HashSet<String> = Default::default();
let mut public_keyring = Keyring::default();
public_keyring.add_ref(&public_key);
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
&keyring,
&public_keyring,
Some(&mut valid_signatures),
)
.unwrap();
let mut public_keyring2 = Keyring::default();
public_keyring2.add_owned(public_key2.clone());
assert_eq!(plain, original_text,);
assert_eq!(valid_signatures.len(), 1);
let mut valid_signatures: HashSet<String> = Default::default();
valid_signatures.clear();
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
&keyring,
&public_keyring,
Some(&mut valid_signatures),
)
.unwrap();
let empty_keyring = Keyring::default();
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
&keyring,
&empty_keyring,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(valid_signatures.len(), 0);
assert_eq!(plain, original_text,);
assert_eq!(valid_signatures.len(), 1);
valid_signatures.clear();
valid_signatures.clear();
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
&keyring,
&public_keyring2,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(valid_signatures.len(), 0);
let empty_keyring = Keyring::default();
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
&keyring,
&empty_keyring,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(valid_signatures.len(), 0);
valid_signatures.clear();
valid_signatures.clear();
public_keyring2.add_ref(&public_key);
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
&keyring,
&public_keyring2,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(valid_signatures.len(), 0);
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
&keyring,
&public_keyring2,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(valid_signatures.len(), 1);
valid_signatures.clear();
valid_signatures.clear();
public_keyring2.add_ref(&public_key);
let plain = dc_pgp_pk_decrypt(
ctext_unsigned.as_bytes(),
&keyring,
&public_keyring,
Some(&mut valid_signatures),
)
.unwrap();
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
&keyring,
&public_keyring2,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(valid_signatures.len(), 1);
assert_eq!(plain, original_text);
valid_signatures.clear();
valid_signatures.clear();
let plain = dc_pgp_pk_decrypt(
ctext_unsigned.as_bytes(),
&keyring,
&public_keyring,
Some(&mut valid_signatures),
)
.unwrap();
let mut keyring = Keyring::default();
keyring.add_ref(&private_key2);
let mut public_keyring = Keyring::default();
public_keyring.add_ref(&public_key);
assert_eq!(plain, original_text);
let plain =
dc_pgp_pk_decrypt(ctext_signed.as_bytes(), &keyring, &public_keyring, None).unwrap();
valid_signatures.clear();
let mut keyring = Keyring::default();
keyring.add_ref(&private_key2);
let mut public_keyring = Keyring::default();
public_keyring.add_ref(&public_key);
let plain =
dc_pgp_pk_decrypt(ctext_signed.as_bytes(), &keyring, &public_keyring, None).unwrap();
assert_eq!(plain, original_text);
}
assert_eq!(plain, original_text);
}
unsafe extern "C" fn cb(