From 3f445a3a6c919a2196d71132656b6ba7250f7838 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 28 Jul 2019 23:42:38 +0300 Subject: [PATCH 01/95] Make dc_get_config_t safe --- src/context.rs | 12 ++---------- src/imap.rs | 30 ++++++++++-------------------- src/types.rs | 3 +-- 3 files changed, 13 insertions(+), 32 deletions(-) diff --git a/src/context.rs b/src/context.rs index 2d68b5f00..99af1b6e8 100644 --- a/src/context.rs +++ b/src/context.rs @@ -254,16 +254,8 @@ unsafe fn cb_set_config(context: &Context, key: *const libc::c_char, value: *con * * @private @memberof Context */ -unsafe fn cb_get_config( - context: &Context, - key: *const libc::c_char, - def: *const libc::c_char, -) -> *mut libc::c_char { - let res = context - .sql - .get_config(context, as_str(key)) - .unwrap_or_else(|| to_string(def)); - to_cstring(res) +fn cb_get_config(context: &Context, key: &str) -> Option { + context.sql.get_config(context, key) } pub unsafe fn dc_context_unref(context: &mut Context) { diff --git a/src/imap.rs b/src/imap.rs index b07767372..17b544c49 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -5,7 +5,7 @@ use std::time::{Duration, SystemTime}; use crate::constants::*; use crate::context::Context; use crate::dc_loginparam::*; -use crate::dc_tools::{as_str, to_cstring}; +use crate::dc_tools::to_cstring; use crate::oauth2::dc_get_oauth2_access_token; use crate::types::*; use crate::x::free; @@ -705,26 +705,16 @@ impl Imap { fn get_config_last_seen_uid>(&self, context: &Context, folder: S) -> (u32, u32) { let key = format!("imap.mailbox.{}", folder.as_ref()); - let val1 = unsafe { - let key_c = to_cstring(key); - let val = (self.get_config)(context, key_c, 0 as *const libc::c_char); - free(key_c as *mut _); - val - }; - if val1.is_null() { - return (0, 0); + if let Some(entry) = (self.get_config)(context, &key) { + // the entry has the format `imap.mailbox.=:` + let mut parts = entry.split(':'); + ( + parts.next().unwrap().parse().unwrap_or_else(|_| 0), + parts.next().unwrap().parse().unwrap_or_else(|_| 0), + ) + } else { + (0, 0) } - let entry = as_str(val1); - - if entry.is_empty() { - return (0, 0); - } - // the entry has the format `imap.mailbox.=:` - let mut parts = entry.split(':'); - ( - parts.next().unwrap().parse().unwrap_or_else(|_| 0), - parts.next().unwrap().parse().unwrap_or_else(|_| 0), - ) } fn fetch_from_single_folder>(&self, context: &Context, folder: S) -> usize { diff --git a/src/types.rs b/src/types.rs index 3cf1043df..47bcbd23c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -36,8 +36,7 @@ pub type dc_precheck_imf_t = unsafe fn(_: &Context, _: *const libc::c_char, _: &str, _: u32) -> libc::c_int; pub type dc_set_config_t = unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char) -> (); -pub type dc_get_config_t = - unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char) -> *mut libc::c_char; +pub type dc_get_config_t = fn(_: &Context, _: &str) -> Option; pub type sqlite_int64 = i64; pub type sqlite3_int64 = sqlite_int64; From dfce34f275b33c6335fa74e097786725f9b19588 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 29 Jul 2019 00:27:43 +0300 Subject: [PATCH 02/95] Return bool from is_file_size_okay --- src/dc_mimefactory.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 8dc83f8d6..e32b31315 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -844,7 +844,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: /* add attachment part */ if msgtype_has_file((*msg).type_0) { - if 0 == is_file_size_okay(msg) { + if !is_file_size_okay(msg) { let error: *mut libc::c_char = dc_mprintf( b"Message exceeds the recommended %i MB.\x00" as *const u8 as *const libc::c_char, @@ -1328,13 +1328,13 @@ unsafe fn build_body_file( * Render ******************************************************************************/ #[allow(non_snake_case)] -unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> libc::c_int { - let mut file_size_okay = 1; +unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> bool { + let mut file_size_okay = true; let pathNfilename = to_cstring((*msg).param.get(Param::File).unwrap_or_default()); let bytes = dc_get_filebytes((*msg).context, pathNfilename); if bytes > (49 * 1024 * 1024 / 4 * 3) { - file_size_okay = 0; + file_size_okay = false; } free(pathNfilename as *mut _); From 2d5b04148fb9890a176d4e6308fa22484f244532 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 29 Jul 2019 03:04:59 +0300 Subject: [PATCH 03/95] Make dc_open arguments rusty --- deltachat-ffi/src/lib.rs | 9 ++++++++- examples/repl/cmdline.rs | 5 +---- examples/repl/main.rs | 7 +------ examples/simple.rs | 4 ++-- src/context.rs | 40 +++++++++++++++++----------------------- src/peerstate.rs | 14 ++++---------- src/test_utils.rs | 8 ++------ tests/stress.rs | 16 ++++++---------- 8 files changed, 41 insertions(+), 62 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 7a5e77ba5..87fb7282f 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -56,9 +56,16 @@ pub unsafe extern "C" fn dc_open( blobdir: *mut libc::c_char, ) -> libc::c_int { assert!(!context.is_null()); + assert!(!dbfile.is_null()); let context = &mut *context; - context::dc_open(context, dbfile, blobdir) + let dbfile_str = dc_tools::as_str(dbfile); + let blobdir_str = if blobdir.is_null() { + None + } else { + Some(dc_tools::as_str(blobdir)) + }; + context::dc_open(context, dbfile_str, blobdir_str) as libc::c_int } #[no_mangle] diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 09c0225a6..8f6e2d2e6 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -503,10 +503,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E "open" => { ensure!(!arg1.is_empty(), "Argument missing"); dc_close(context); - ensure!( - 0 != dc_open(context, arg1_c, 0 as *const libc::c_char), - "Open failed" - ); + ensure!(dc_open(context, arg1, None), "Open failed"); } "close" => { dc_close(context); diff --git a/examples/repl/main.rs b/examples/repl/main.rs index 7cc700af8..214527467 100644 --- a/examples/repl/main.rs +++ b/examples/repl/main.rs @@ -399,12 +399,7 @@ fn main_0(args: Vec) -> Result<(), failure::Error> { unsafe { dc_cmdline_skip_auth() }; if args.len() == 2 { - if 0 == unsafe { - let a = to_cstring(&args[1]); - let res = dc_open(&mut context, a, 0 as *const _); - free(a as *mut _); - res - } { + if unsafe { !dc_open(&mut context, &args[1], None) } { println!("Error: Cannot open {}.", args[0],); } } else if args.len() != 1 { diff --git a/examples/simple.rs b/examples/simple.rs index 4a9b0c1fc..2aa824acb 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -76,11 +76,11 @@ fn main() { }); let dir = tempdir().unwrap(); - let dbfile = CString::new(dir.path().join("db.sqlite").to_str().unwrap()).unwrap(); + let dbfile = dir.path().join("db.sqlite"); println!("opening database {:?}", dbfile); - assert_eq!(dc_open(&ctx, dbfile.as_ptr(), std::ptr::null()), 1); + assert!(dc_open(&ctx, dbfile.to_str().unwrap(), None)); println!("configuring"); let args = std::env::args().collect::>(); diff --git a/src/context.rs b/src/context.rs index 1bbc8a986..6f9a1b2f1 100644 --- a/src/context.rs +++ b/src/context.rs @@ -315,32 +315,26 @@ pub unsafe fn dc_get_userdata(context: &mut Context) -> *mut libc::c_void { context.userdata as *mut _ } -pub unsafe fn dc_open( - context: &Context, - dbfile: *const libc::c_char, - blobdir: *const libc::c_char, -) -> libc::c_int { - let mut success = 0; +pub unsafe fn dc_open(context: &Context, dbfile: &str, blobdir: Option<&str>) -> bool { + let mut success = false; if 0 != dc_is_open(context) { - return 0; + return false; } - if !dbfile.is_null() { - *context.dbfile.write().unwrap() = dc_strdup(dbfile); - if !blobdir.is_null() && 0 != *blobdir.offset(0isize) as libc::c_int { - let dir = dc_strdup(blobdir); - dc_ensure_no_slash(dir); - *context.blobdir.write().unwrap() = dir; - } else { - let dir = dc_mprintf(b"%s-blobs\x00" as *const u8 as *const libc::c_char, dbfile); - dc_create_folder(context, dir); - *context.blobdir.write().unwrap() = dir; - } - // Create/open sqlite database, this may already use the blobdir - if context.sql.open(context, as_path(dbfile), 0) { - success = 1i32 - } + *context.dbfile.write().unwrap() = to_cstring(dbfile); + if blobdir.is_some() && blobdir.unwrap().len() > 0 { + let dir = to_cstring(dc_ensure_no_slash_safe(blobdir.unwrap())); + *context.blobdir.write().unwrap() = dir; + } else { + let dir = to_cstring(dbfile.to_string() + "-blobs"); + dc_create_folder(context, dir); + *context.blobdir.write().unwrap() = dir; } - if 0 == success { + // Create/open sqlite database, this may already use the blobdir + let dbfile_path = std::path::Path::new(dbfile); + if context.sql.open(context, dbfile_path, 0) { + success = true + } + if !success { dc_close(context); } success diff --git a/src/peerstate.rs b/src/peerstate.rs index 876a300b1..7d0f2f648 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -462,12 +462,9 @@ mod tests { use super::*; use pretty_assertions::assert_eq; - use std::ffi::CStr; use tempfile::{tempdir, TempDir}; use crate::context::*; - use crate::dc_tools::to_cstring; - use crate::x::free; #[test] fn test_peerstate_save_to_db() { @@ -522,16 +519,13 @@ mod tests { unsafe fn create_test_context() -> TestContext { let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut()); let dir = tempdir().unwrap(); - let dbfile = to_cstring(dir.path().join("db.sqlite").to_str().unwrap()); - assert_eq!( - dc_open(&mut ctx, dbfile, std::ptr::null()), - 1, + let dbfile = dir.path().join("db.sqlite"); + assert!( + dc_open(&mut ctx, dbfile.to_str().unwrap(), None), "Failed to open {}", - CStr::from_ptr(dbfile as *const _).to_str().unwrap() + dbfile.to_str().unwrap() ); - free(dbfile as *mut _); - TestContext { ctx: ctx, dir: dir } } } diff --git a/src/test_utils.rs b/src/test_utils.rs index 1109bd4ec..f78aa14e6 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -7,8 +7,6 @@ use tempfile::{tempdir, TempDir}; use crate::context::{dc_context_new, dc_open, Context}; use crate::types::dc_callback_t; -use crate::dc_tools::OsStrExt; - /// A Context and temporary directory. /// /// The temporary directory can be used to store the SQLite database, @@ -29,10 +27,8 @@ pub fn test_context(cb: Option) -> TestContext { let mut ctx = dc_context_new(cb, std::ptr::null_mut(), std::ptr::null_mut()); let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); - let dbfile_c = dbfile.to_c_string().unwrap(); - assert_eq!( - dc_open(&mut ctx, dbfile_c.as_ptr(), std::ptr::null()), - 1, + assert!( + dc_open(&mut ctx, dbfile.to_str().unwrap(), None), "Failed to open {}", dbfile.display(), ); diff --git a/tests/stress.rs b/tests/stress.rs index d5518b9e2..912879374 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -817,14 +817,12 @@ struct TestContext { unsafe fn create_test_context() -> TestContext { let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut()); let dir = tempdir().unwrap(); - let dbfile = to_cstring(dir.path().join("db.sqlite").to_str().unwrap()); - assert_eq!( - dc_open(&mut ctx, dbfile, std::ptr::null()), - 1, + let dbfile = dir.path().join("db.sqlite"); + assert!( + dc_open(&mut ctx, dbfile.to_str().unwrap(), None), "Failed to open {}", - as_str(dbfile as *const libc::c_char) + dbfile.to_str().unwrap() ); - free(dbfile as *mut _); TestContext { ctx: ctx, dir: dir } } @@ -1006,9 +1004,7 @@ fn test_wrong_db() { let dbfile = dir.path().join("db.sqlite"); std::fs::write(&dbfile, b"123").unwrap(); - let dbfile_c = to_cstring(dbfile.to_str().unwrap()); - let res = dc_open(&mut ctx, dbfile_c, std::ptr::null()); - free(dbfile_c as *mut _); - assert_eq!(res, 0); + let res = dc_open(&mut ctx, dbfile.to_str().unwrap(), None); + assert!(!res); } } From 27342f50b5099119408184adace1bd873374d9e8 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 29 Jul 2019 18:45:12 +0300 Subject: [PATCH 04/95] Remove unsafe version of dc_timestamp_to_str --- examples/repl/cmdline.rs | 11 ++++------- src/dc_msg.rs | 9 ++++----- src/dc_tools.rs | 8 +------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 09c0225a6..0e608e415 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -229,7 +229,7 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef, msg: *mut dc_msg_t DC_STATE_OUT_FAILED => " !!", _ => "", }; - let temp2: *mut libc::c_char = dc_timestamp_to_str(dc_msg_get_timestamp(msg)); + let temp2 = dc_timestamp_to_str(dc_msg_get_timestamp(msg)); let msgtext: *mut libc::c_char = dc_msg_get_text(msg); info!( context, @@ -266,10 +266,9 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef, msg: *mut dc_msg_t "" }, statestr, - as_str(temp2), + &temp2, ); free(msgtext as *mut libc::c_void); - free(temp2 as *mut libc::c_void); free(contact_name as *mut libc::c_void); dc_contact_unref(contact); } @@ -682,7 +681,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E if !text1.is_null() { ": " } else { "" }, to_string(text2), statestr, - as_str(timestr), + ×tr, if 0 != dc_chat_is_sending_locations(chat) { "📍" } else { @@ -691,7 +690,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E ); free(text1 as *mut libc::c_void); free(text2 as *mut libc::c_void); - free(timestr as *mut libc::c_void); dc_lot_unref(lot); dc_chat_unref(chat); info!( @@ -886,7 +884,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E 0, "Loc#{}: {}: lat={} lng={} acc={} Chat#{} Contact#{} Msg#{} {}", dc_array_get_id(loc, j as size_t), - as_str(timestr_0), + ×tr_0, dc_array_get_latitude(loc, j as size_t), dc_array_get_longitude(loc, j as size_t), dc_array_get_accuracy(loc, j as size_t), @@ -899,7 +897,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E "-" }, ); - free(timestr_0 as *mut libc::c_void); free(marker as *mut libc::c_void); j += 1 } diff --git a/src/dc_msg.rs b/src/dc_msg.rs index 1361af3f8..b6548f770 100644 --- a/src/dc_msg.rs +++ b/src/dc_msg.rs @@ -70,7 +70,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch let rawtxt = rawtxt.unwrap(); let rawtxt = dc_truncate_str(rawtxt.trim(), 100000); - let fts = dc_timestamp_to_str_safe(dc_msg_get_timestamp(msg)); + let fts = dc_timestamp_to_str(dc_msg_get_timestamp(msg)); ret += &format!("Sent: {}", fts); p = dc_contact_get_name_n_addr(contact_from); @@ -79,13 +79,12 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch ret += "\n"; if (*msg).from_id != 1 as libc::c_uint { - p = dc_timestamp_to_str(if 0 != (*msg).timestamp_rcvd { + let s = dc_timestamp_to_str(if 0 != (*msg).timestamp_rcvd { (*msg).timestamp_rcvd } else { (*msg).timestamp_sort }); - ret += &format!("Received: {}", as_str(p)); - free(p as *mut libc::c_void); + ret += &format!("Received: {}", &s); ret += "\n"; } @@ -109,7 +108,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch |rows| { for row in rows { let (contact_id, ts) = row?; - let fts = dc_timestamp_to_str_safe(ts); + let fts = dc_timestamp_to_str(ts); ret += &format!("Read: {}", fts); let contact = dc_contact_new(context); diff --git a/src/dc_tools.rs b/src/dc_tools.rs index b9e425b2e..d2db0afa2 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -669,13 +669,7 @@ pub unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 { * date/time tools ******************************************************************************/ -/* the return value must be free()'d */ -pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char { - let res = dc_timestamp_to_str_safe(wanted); - to_cstring(res) -} - -pub fn dc_timestamp_to_str_safe(wanted: i64) -> String { +pub fn dc_timestamp_to_str(wanted: i64) -> String { let ts = chrono::Utc.timestamp(wanted, 0); ts.format("%Y.%m.%d %H:%M:%S").to_string() } From 03603a48a037e8da1c0f67cd556f85a683c33063 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 29 Jul 2019 20:20:52 +0300 Subject: [PATCH 05/95] dc_job.rs: add DC_{IMAP,SMTP}_THREAD constants --- src/dc_job.rs | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/dc_job.rs b/src/dc_job.rs index e5501bc77..2119c738f 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -23,6 +23,9 @@ use crate::sql; use crate::types::*; use crate::x::*; +const DC_IMAP_THREAD: libc::c_int = 100; +const DC_SMTP_THREAD: libc::c_int = 5000; + // thread IDs // jobs in the INBOX-thread, range from DC_IMAP_THREAD..DC_IMAP_THREAD+999 // low priority ... @@ -54,7 +57,7 @@ pub unsafe fn dc_perform_imap_jobs(context: &Context) { *context.probe_imap_network.write().unwrap() = 0; *context.perform_inbox_jobs_needed.write().unwrap() = 0; - dc_job_perform(context, 100, probe_imap_network); + dc_job_perform(context, DC_IMAP_THREAD, probe_imap_network); info!(context, 0, "dc_perform_imap_jobs ended.",); } @@ -116,7 +119,11 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: context, 0, "{}-job #{}, action {} started...", - if thread == 100 { "INBOX" } else { "SMTP" }, + if thread == DC_IMAP_THREAD { + "INBOX" + } else { + "SMTP" + }, job.job_id, job.action, ); @@ -175,7 +182,11 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: context, 0, "{}-job #{} not yet ready and will be delayed.", - if thread == 100 { "INBOX" } else { "SMTP" }, + if thread == DC_IMAP_THREAD { + "INBOX" + } else { + "SMTP" + }, job.job_id ); } else if job.try_again == -1 || job.try_again == 3 { @@ -189,13 +200,17 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: context, 0, "{}-job #{} not succeeded on try #{}, retry in ADD_TIME+{} (in {} seconds).", - if thread == 100 { "INBOX" } else { "SMTP" }, + if thread == DC_IMAP_THREAD { + "INBOX" + } else { + "SMTP" + }, job.job_id as libc::c_int, tries, time_offset, job.added_timestamp + time_offset - time() ); - if thread == 5000 && tries < 17 - 1 { + if thread == DC_SMTP_THREAD && tries < 17 - 1 { context .smtp_state .clone() @@ -801,10 +816,10 @@ pub unsafe fn dc_job_add( delay_seconds: libc::c_int, ) { let timestamp = time(); - let thread = if action >= 100 && action < 100 + 1000 { - 100 - } else if action >= 5000 && action < 5000 + 1000 { - 5000 + let thread = if action >= DC_IMAP_THREAD && action < DC_IMAP_THREAD + 1000 { + DC_IMAP_THREAD + } else if action >= DC_SMTP_THREAD && action < DC_SMTP_THREAD + 1000 { + DC_SMTP_THREAD } else { return; }; @@ -823,7 +838,7 @@ pub unsafe fn dc_job_add( ] ).ok(); - if thread == 100 { + if thread == DC_IMAP_THREAD { dc_interrupt_imap_idle(context); } else { dc_interrupt_smtp_idle(context); @@ -1039,7 +1054,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) { }; info!(context, 0, "SMTP-jobs started...",); - dc_job_perform(context, 5000, probe_smtp_network); + dc_job_perform(context, DC_SMTP_THREAD, probe_smtp_network); info!(context, 0, "SMTP-jobs ended."); { @@ -1062,7 +1077,7 @@ pub unsafe fn dc_perform_smtp_idle(context: &Context) { 0, "SMTP-idle will not be started because of waiting jobs.", ); } else { - let dur = get_next_wakeup_time(context, 5000); + let dur = get_next_wakeup_time(context, DC_SMTP_THREAD); loop { let res = cvar.wait_timeout(state, dur).unwrap(); From 0c082fac7b6a295dc408df28550a178a98607453 Mon Sep 17 00:00:00 2001 From: KAction Date: Mon, 29 Jul 2019 22:10:22 +0000 Subject: [PATCH 06/95] refactor: remove unused import of qsort() from C library ( --- src/x.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/x.rs b/src/x.rs index aa43b3f11..27b309b34 100644 --- a/src/x.rs +++ b/src/x.rs @@ -37,14 +37,6 @@ pub fn strndup(s: *const libc::c_char, n: libc::c_ulong) -> *mut libc::c_char { extern "C" { pub fn clock() -> libc::clock_t; - pub fn qsort( - __base: *mut libc::c_void, - __nel: size_t, - __width: size_t, - __compar: Option< - unsafe extern "C" fn(_: *const libc::c_void, _: *const libc::c_void) -> libc::c_int, - >, - ); // -- DC Methods pub fn dc_mprintf(format: *const libc::c_char, _: ...) -> *mut libc::c_char; From 21b4147d1599906f2f7404270980827adafce5cc Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 30 Jul 2019 01:01:36 +0300 Subject: [PATCH 07/95] sql.rs: make is_file_in_use() safe --- src/sql.rs | 86 ++++++++++++++---------------------------------------- 1 file changed, 22 insertions(+), 64 deletions(-) diff --git a/src/sql.rs b/src/sql.rs index ab3f00ac0..08382dc9e 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -1007,35 +1007,15 @@ pub fn housekeeping(context: &Context) { } let entry = entry.unwrap(); let name_f = entry.file_name(); - let name_c = unsafe { to_cstring(name_f.to_string_lossy()) }; + let name_s = name_f.to_string_lossy(); - if unsafe { is_file_in_use(&mut files_in_use, 0 as *const libc::c_char, name_c) } - || unsafe { - is_file_in_use( - &mut files_in_use, - b".increation\x00" as *const u8 as *const libc::c_char, - name_c, - ) - } - || unsafe { - is_file_in_use( - &mut files_in_use, - b".waveform\x00" as *const u8 as *const libc::c_char, - name_c, - ) - } - || unsafe { - is_file_in_use( - &mut files_in_use, - b"-preview.jpg\x00" as *const u8 as *const libc::c_char, - name_c, - ) - } + if is_file_in_use(&mut files_in_use, None, &name_s) + || is_file_in_use(&mut files_in_use, Some(".increation"), &name_s) + || is_file_in_use(&mut files_in_use, Some(".waveform"), &name_s) + || is_file_in_use(&mut files_in_use, Some("-preview.jpg"), &name_s) { - unsafe { free(name_c as *mut _) }; continue; } - unsafe { free(name_c as *mut _) }; unreferenced_count += 1; @@ -1089,26 +1069,18 @@ pub fn housekeeping(context: &Context) { info!(context, 0, "Housekeeping done.",); } -unsafe fn is_file_in_use( - files_in_use: &HashSet, - namespc: *const libc::c_char, - name: *const libc::c_char, -) -> bool { - let name_to_check = dc_strdup(name); - if !namespc.is_null() { - let name_len: libc::c_int = strlen(name) as libc::c_int; - let namespc_len: libc::c_int = strlen(namespc) as libc::c_int; - if name_len <= namespc_len - || strcmp(&*name.offset((name_len - namespc_len) as isize), namespc) != 0 - { +fn is_file_in_use(files_in_use: &HashSet, namespc_opt: Option<&str>, name: &str) -> bool { + let name_to_check = if let Some(namespc) = namespc_opt { + let name_len = name.len(); + let namespc_len = namespc.len(); + if name_len <= namespc_len || !name.ends_with(namespc) { return false; } - *name_to_check.offset((name_len - namespc_len) as isize) = 0 as libc::c_char - } - - let contains = files_in_use.contains(as_str(name_to_check)); - free(name_to_check as *mut libc::c_void); - contains + &name[..name_len - namespc_len] + } else { + name + }; + files_in_use.contains(name_to_check) } fn maybe_add_file(files_in_use: &mut HashSet, file: impl AsRef) { @@ -1162,26 +1134,12 @@ mod test { maybe_add_file(&mut files, "$BLOBDIR/world.txt"); maybe_add_file(&mut files, "world2.txt"); - assert!(unsafe { - is_file_in_use( - &mut files, - std::ptr::null(), - b"hello\x00" as *const u8 as *const _, - ) - }); - assert!(!unsafe { - is_file_in_use( - &mut files, - b".txt\x00" as *const u8 as *const _, - b"hello\x00" as *const u8 as *const _, - ) - }); - assert!(unsafe { - is_file_in_use( - &mut files, - b"-suffix\x00" as *const u8 as *const _, - b"world.txt-suffix\x00" as *const u8 as *const _, - ) - }); + assert!(is_file_in_use(&mut files, None, "hello")); + assert!(!is_file_in_use(&mut files, Some(".txt"), "hello")); + assert!(is_file_in_use( + &mut files, + Some("-suffix"), + "world.txt-suffix" + )); } } From 3ace4fcc2f419b58f408f8dda3927ae2c92191c0 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 30 Jul 2019 02:20:11 +0300 Subject: [PATCH 08/95] Make key::to_asc return String --- src/dc_imex.rs | 8 ++++---- src/key.rs | 23 ++++++++--------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/dc_imex.rs b/src/dc_imex.rs index c414fdbf1..1978c0da9 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -242,16 +242,16 @@ pub unsafe extern "C" fn dc_render_setup_file( None }; - if let Some(payload_key_asc) = curr_private_key.map(|k| k.to_asc_c(headers)) { + if let Some(payload_key_asc) = curr_private_key.map(|k| k.to_asc(headers)) { + let payload_key_asc_c = CString::new(payload_key_asc).unwrap(); if let Some(encr) = dc_pgp_symm_encrypt( passphrase, - payload_key_asc as *const libc::c_void, - strlen(payload_key_asc), + payload_key_asc_c.as_ptr() as *const libc::c_void, + payload_key_asc_c.as_bytes().len(), ) { let encr_string_c = CString::new(encr).unwrap(); let mut encr_string = strdup(encr_string_c.as_ptr()); - free(payload_key_asc as *mut libc::c_void); let replacement: *mut libc::c_char = dc_mprintf(b"-----BEGIN PGP MESSAGE-----\r\nPassphrase-Format: numeric9x4\r\nPassphrase-Begin: %s\x00" as *const u8 as *const libc::c_char, diff --git a/src/key.rs b/src/key.rs index 5d4dd2b12..6ed4b9eab 100644 --- a/src/key.rs +++ b/src/key.rs @@ -216,22 +216,16 @@ impl Key { } } - /// Each header line must be terminated by `\r\n`, the result must be freed. - pub fn to_asc_c(&self, header: Option<(&str, &str)>) -> *mut libc::c_char { + /// Each header line must be terminated by `\r\n` + pub fn to_asc(&self, header: Option<(&str, &str)>) -> String { let headers = header.map(|(key, value)| { let mut m = BTreeMap::new(); m.insert(key.to_string(), value.to_string()); m }); - let buf = self - .to_armored_string(headers.as_ref()) - .expect("failed to serialize key"); - let buf_c = CString::new(buf).unwrap(); - - // need to use strdup to allocate the result with malloc - // so it can be `free`d later. - unsafe { strdup(buf_c.as_ptr()) } + self.to_armored_string(headers.as_ref()) + .expect("failed to serialize key") } pub fn write_asc_to_file(&self, file: *const libc::c_char, context: &Context) -> bool { @@ -239,15 +233,16 @@ impl Key { return false; } - let file_content = self.to_asc_c(None); + let file_content = self.to_asc(None); + let file_content_c = CString::new(file_content).unwrap(); let success = if 0 == unsafe { dc_write_file( context, file, - file_content as *const libc::c_void, - strlen(file_content), + file_content_c.as_ptr() as *const libc::c_void, + file_content_c.as_bytes().len(), ) } { error!(context, 0, "Cannot write key to {}", to_string(file)); @@ -256,8 +251,6 @@ impl Key { true }; - unsafe { free(file_content as *mut libc::c_void) }; - success } From 2688a397aa7b27c1b03ff96ef4cf795f94f0a1e5 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 28 Jul 2019 15:27:50 +0300 Subject: [PATCH 09/95] Implement From> for dc_array_t --- src/dc_array.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/dc_array.rs b/src/dc_array.rs index b2834233a..b454fa716 100644 --- a/src/dc_array.rs +++ b/src/dc_array.rs @@ -138,6 +138,12 @@ impl dc_array_t { } } +impl From> for dc_array_t { + fn from(array: Vec) -> Self { + dc_array_t::Locations(array) + } +} + pub unsafe fn dc_array_unref(array: *mut dc_array_t) { if array.is_null() { return; From 14e42b48bdcd61588252ec1563a50d56b6aea70b Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 28 Jul 2019 15:29:47 +0300 Subject: [PATCH 10/95] dc_get_locations: use from(Vec) instead of add_location --- src/dc_location.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dc_location.rs b/src/dc_location.rs index bdef8671e..132d0f505 100644 --- a/src/dc_location.rs +++ b/src/dc_location.rs @@ -250,12 +250,12 @@ pub fn dc_get_locations( Ok(loc) }, |locations| { - let mut ret = dc_array_t::new_locations(500); + let mut ret = Vec::new(); for location in locations { - ret.add_location(location?); + ret.push(location?); } - Ok(ret.into_raw()) + Ok(dc_array_t::from(ret).into_raw()) }, ) .unwrap_or_else(|_| std::ptr::null_mut()) From 81a84620ebc784bb94580a83bf3d84a8a66e4c28 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 28 Jul 2019 15:50:41 +0300 Subject: [PATCH 11/95] Store dc_kml_t::locations as Option instead of pointer --- src/dc_location.rs | 39 ++++++++++++++++++--------------------- src/dc_mimeparser.rs | 4 ++-- src/dc_receive_imf.rs | 4 ++-- tests/stress.rs | 32 ++++++++++++++++---------------- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/dc_location.rs b/src/dc_location.rs index 132d0f505..5e78f20f7 100644 --- a/src/dc_location.rs +++ b/src/dc_location.rs @@ -51,7 +51,7 @@ impl dc_location { #[allow(non_camel_case_types)] pub struct dc_kml_t { pub addr: *mut libc::c_char, - pub locations: *mut dc_array_t, + pub locations: Option, pub tag: libc::c_int, pub curr: dc_location, } @@ -60,7 +60,7 @@ impl dc_kml_t { pub fn new() -> Self { dc_kml_t { addr: std::ptr::null_mut(), - locations: std::ptr::null_mut(), + locations: None, tag: 0, curr: dc_location::new(), } @@ -422,13 +422,14 @@ pub unsafe fn dc_save_locations( context: &Context, chat_id: u32, contact_id: u32, - locations: *const dc_array_t, + locations_opt: &Option, independent: libc::c_int, ) -> u32 { - if chat_id <= 9 || locations.is_null() { + if chat_id <= 9 || locations_opt.is_none() { return 0; } + let locations = locations_opt.as_ref().unwrap(); context .sql .prepare2( @@ -440,31 +441,31 @@ pub unsafe fn dc_save_locations( let mut newest_timestamp = 0; let mut newest_location_id = 0; - for i in 0..dc_array_get_cnt(locations) { - let location = dc_array_get_ptr(locations, i as size_t) as *mut dc_location; + for i in 0..locations.len() { + let location = locations.get_location(i as size_t); let exists = - stmt_test.exists(params![(*location).timestamp, contact_id as i32])?; + stmt_test.exists(params![location.timestamp, contact_id as i32])?; if 0 != independent || !exists { stmt_insert.execute(params![ - (*location).timestamp, + location.timestamp, contact_id as i32, chat_id as i32, - (*location).latitude, - (*location).longitude, - (*location).accuracy, + location.latitude, + location.longitude, + location.accuracy, independent, ])?; - if (*location).timestamp > newest_timestamp { - newest_timestamp = (*location).timestamp; + if location.timestamp > newest_timestamp { + newest_timestamp = location.timestamp; newest_location_id = sql::get_rowid2_with_conn( context, conn, "locations", "timestamp", - (*location).timestamp, + location.timestamp, "from_id", contact_id as i32, ); @@ -499,7 +500,7 @@ pub unsafe fn dc_kml_parse( } else { content_nullterminated = dc_null_terminate(content, content_bytes as libc::c_int); if !content_nullterminated.is_null() { - kml.locations = dc_array_new_locations(100); + kml.locations = Some(dc_array_t::new_locations(100)); dc_saxparser_init( &mut saxparser, &mut kml as *mut dc_kml_t as *mut libc::c_void, @@ -585,7 +586,7 @@ unsafe fn kml_endtag_cb(userdata: *mut libc::c_void, tag: *const libc::c_char) { && 0. != (*kml).curr.longitude { let location = (*kml).curr.clone(); - (*(*kml).locations).add_location(location); + ((*kml).locations.as_mut().unwrap()).add_location(location); } (*kml).tag = 0 }; @@ -636,11 +637,7 @@ unsafe fn kml_starttag_cb( }; } -pub unsafe fn dc_kml_unref(kml: *mut dc_kml_t) { - if kml.is_null() { - return; - } - dc_array_unref((*kml).locations); +pub unsafe fn dc_kml_unref(kml: &mut dc_kml_t) { free((*kml).addr as *mut libc::c_void); } diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index f5bc4cc64..c190d480a 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -135,12 +135,12 @@ pub unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) { dc_e2ee_thanks(&mut (*mimeparser).e2ee_helper); if let Some(location_kml) = (*mimeparser).location_kml.as_mut() { - dc_kml_unref(location_kml as *mut dc_kml_t); + dc_kml_unref(location_kml); } (*mimeparser).location_kml = None; if let Some(message_kml) = (*mimeparser).message_kml.as_mut() { - dc_kml_unref(message_kml as *mut dc_kml_t); + dc_kml_unref(message_kml); } (*mimeparser).message_kml = None; } diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 35964de91..4dd2d424c 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -771,7 +771,7 @@ pub unsafe fn dc_receive_imf( context, chat_id, from_id, - mime_parser.message_kml.unwrap().locations, + &mime_parser.message_kml.unwrap().locations, 1, ); if 0 != newest_location_id && 0 == hidden { @@ -797,7 +797,7 @@ pub unsafe fn dc_receive_imf( context, chat_id, from_id, - mime_parser.location_kml.as_ref().unwrap().locations, + &mime_parser.location_kml.as_ref().unwrap().locations, 0, ); if newest_location_id != 0 && hidden == 0 && !location_id_written { diff --git a/tests/stress.rs b/tests/stress.rs index 1a1e19d87..141d8c9fc 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -840,24 +840,24 @@ fn test_dc_kml_parse() { assert!(!kml.addr.is_null()); assert_eq!(as_str(kml.addr as *const libc::c_char), "user@example.org",); - assert_eq!(dc_array_get_cnt(kml.locations), 2); + let locations_ref = kml.locations.as_ref().unwrap(); + assert_eq!(locations_ref.len(), 2); - assert!(dc_array_get_latitude(kml.locations, 0) > 53.6f64); - assert!(dc_array_get_latitude(kml.locations, 0) < 53.8f64); - assert!(dc_array_get_longitude(kml.locations, 0) > 9.3f64); - assert!(dc_array_get_longitude(kml.locations, 0) < 9.5f64); - assert!(dc_array_get_accuracy(kml.locations, 0) > 31.9f64); - assert!(dc_array_get_accuracy(kml.locations, 0) < 32.1f64); - assert_eq!(dc_array_get_timestamp(kml.locations, 0), 1551906597); + assert!(locations_ref.get_latitude(0) > 53.6f64); + assert!(locations_ref.get_latitude(0) < 53.8f64); + assert!(locations_ref.get_longitude(0) > 9.3f64); + assert!(locations_ref.get_longitude(0) < 9.5f64); + assert!(locations_ref.get_accuracy(0) > 31.9f64); + assert!(locations_ref.get_accuracy(0) < 32.1f64); + assert_eq!(locations_ref.get_timestamp(0), 1551906597); - assert!(dc_array_get_latitude(kml.locations, 1) > 63.6f64); - assert!(dc_array_get_latitude(kml.locations, 1) < 63.8f64); - assert!(dc_array_get_longitude(kml.locations, 1) > 19.3f64); - assert!(dc_array_get_longitude(kml.locations, 1) < 19.5f64); - assert!(dc_array_get_accuracy(kml.locations, 1) > 2.4f64); - assert!(dc_array_get_accuracy(kml.locations, 1) < 2.6f64); - - assert_eq!(dc_array_get_timestamp(kml.locations, 1), 1544739072); + assert!(locations_ref.get_latitude(1) > 63.6f64); + assert!(locations_ref.get_latitude(1) < 63.8f64); + assert!(locations_ref.get_longitude(1) > 19.3f64); + assert!(locations_ref.get_longitude(1) < 19.5f64); + assert!(locations_ref.get_accuracy(1) > 2.4f64); + assert!(locations_ref.get_accuracy(1) < 2.6f64); + assert_eq!(locations_ref.get_timestamp(1), 1544739072); dc_kml_unref(&mut kml); } From ae6c41a01987e2af7ff396f49a4553489c166c17 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 28 Jul 2019 16:07:04 +0300 Subject: [PATCH 12/95] dc_kml_t: replace Option with Option> --- src/dc_location.rs | 10 +++++----- tests/stress.rs | 30 +++++++++++++++--------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/dc_location.rs b/src/dc_location.rs index 5e78f20f7..5977a939b 100644 --- a/src/dc_location.rs +++ b/src/dc_location.rs @@ -51,7 +51,7 @@ impl dc_location { #[allow(non_camel_case_types)] pub struct dc_kml_t { pub addr: *mut libc::c_char, - pub locations: Option, + pub locations: Option>, pub tag: libc::c_int, pub curr: dc_location, } @@ -422,7 +422,7 @@ pub unsafe fn dc_save_locations( context: &Context, chat_id: u32, contact_id: u32, - locations_opt: &Option, + locations_opt: &Option>, independent: libc::c_int, ) -> u32 { if chat_id <= 9 || locations_opt.is_none() { @@ -442,7 +442,7 @@ pub unsafe fn dc_save_locations( let mut newest_location_id = 0; for i in 0..locations.len() { - let location = locations.get_location(i as size_t); + let location = &locations[i]; let exists = stmt_test.exists(params![location.timestamp, contact_id as i32])?; @@ -500,7 +500,7 @@ pub unsafe fn dc_kml_parse( } else { content_nullterminated = dc_null_terminate(content, content_bytes as libc::c_int); if !content_nullterminated.is_null() { - kml.locations = Some(dc_array_t::new_locations(100)); + kml.locations = Some(Vec::with_capacity(100)); dc_saxparser_init( &mut saxparser, &mut kml as *mut dc_kml_t as *mut libc::c_void, @@ -586,7 +586,7 @@ unsafe fn kml_endtag_cb(userdata: *mut libc::c_void, tag: *const libc::c_char) { && 0. != (*kml).curr.longitude { let location = (*kml).curr.clone(); - ((*kml).locations.as_mut().unwrap()).add_location(location); + ((*kml).locations.as_mut().unwrap()).push(location); } (*kml).tag = 0 }; diff --git a/tests/stress.rs b/tests/stress.rs index 141d8c9fc..164a937bb 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -840,24 +840,24 @@ fn test_dc_kml_parse() { assert!(!kml.addr.is_null()); assert_eq!(as_str(kml.addr as *const libc::c_char), "user@example.org",); - let locations_ref = kml.locations.as_ref().unwrap(); + let locations_ref = &kml.locations.as_ref().unwrap(); assert_eq!(locations_ref.len(), 2); - assert!(locations_ref.get_latitude(0) > 53.6f64); - assert!(locations_ref.get_latitude(0) < 53.8f64); - assert!(locations_ref.get_longitude(0) > 9.3f64); - assert!(locations_ref.get_longitude(0) < 9.5f64); - assert!(locations_ref.get_accuracy(0) > 31.9f64); - assert!(locations_ref.get_accuracy(0) < 32.1f64); - assert_eq!(locations_ref.get_timestamp(0), 1551906597); + assert!(locations_ref[0].latitude > 53.6f64); + assert!(locations_ref[0].latitude < 53.8f64); + assert!(locations_ref[0].longitude > 9.3f64); + assert!(locations_ref[0].longitude < 9.5f64); + assert!(locations_ref[0].accuracy > 31.9f64); + assert!(locations_ref[0].accuracy < 32.1f64); + assert_eq!(locations_ref[0].timestamp, 1551906597); - assert!(locations_ref.get_latitude(1) > 63.6f64); - assert!(locations_ref.get_latitude(1) < 63.8f64); - assert!(locations_ref.get_longitude(1) > 19.3f64); - assert!(locations_ref.get_longitude(1) < 19.5f64); - assert!(locations_ref.get_accuracy(1) > 2.4f64); - assert!(locations_ref.get_accuracy(1) < 2.6f64); - assert_eq!(locations_ref.get_timestamp(1), 1544739072); + assert!(locations_ref[1].latitude > 63.6f64); + assert!(locations_ref[1].latitude < 63.8f64); + assert!(locations_ref[1].longitude > 19.3f64); + assert!(locations_ref[1].longitude < 19.5f64); + assert!(locations_ref[1].accuracy > 2.4f64); + assert!(locations_ref[1].accuracy < 2.6f64); + assert_eq!(locations_ref[1].timestamp, 1544739072); dc_kml_unref(&mut kml); } From 76e76470e0f1d313374d6a1f3144636a8331d891 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 28 Jul 2019 21:36:17 +0300 Subject: [PATCH 13/95] Replace range loop with foreach loop --- src/dc_location.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/dc_location.rs b/src/dc_location.rs index 5977a939b..b16e3cb74 100644 --- a/src/dc_location.rs +++ b/src/dc_location.rs @@ -441,9 +441,7 @@ pub unsafe fn dc_save_locations( let mut newest_timestamp = 0; let mut newest_location_id = 0; - for i in 0..locations.len() { - let location = &locations[i]; - + for location in locations { let exists = stmt_test.exists(params![location.timestamp, contact_id as i32])?; From f87c98d6eaf951506d4d9a02bf3c5cbc15856c96 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 30 Jul 2019 02:43:39 +0300 Subject: [PATCH 14/95] Make cb_set_config() safe --- src/context.rs | 9 ++------- src/imap.rs | 8 +------- src/types.rs | 3 +-- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/context.rs b/src/context.rs index 99d6749d7..29d8525a4 100644 --- a/src/context.rs +++ b/src/context.rs @@ -233,13 +233,8 @@ unsafe fn cb_precheck_imf( return rfc724_mid_exists; } -unsafe fn cb_set_config(context: &Context, key: *const libc::c_char, value: *const libc::c_char) { - let v = if value.is_null() { - None - } else { - Some(as_str(value)) - }; - context.sql.set_config(context, as_str(key), v).ok(); +fn cb_set_config(context: &Context, key: &str, value: Option<&str>) { + context.sql.set_config(context, key, value).ok(); } /* * diff --git a/src/imap.rs b/src/imap.rs index 17b544c49..3d6336299 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -914,13 +914,7 @@ impl Imap { let key = format!("imap.mailbox.{}", folder.as_ref()); let val = format!("{}:{}", uidvalidity, lastseenuid); - unsafe { - let key_c = to_cstring(key); - let val_c = to_cstring(val); - (self.set_config)(context, key_c, val_c); - free(key_c as *mut _); - free(val_c as *mut _); - }; + (self.set_config)(context, &key, Some(&val)); } fn fetch_single_msg>( diff --git a/src/types.rs b/src/types.rs index 47bcbd23c..f3d360333 100644 --- a/src/types.rs +++ b/src/types.rs @@ -34,8 +34,7 @@ the online state. */ pub type dc_precheck_imf_t = unsafe fn(_: &Context, _: *const libc::c_char, _: &str, _: u32) -> libc::c_int; -pub type dc_set_config_t = - unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char) -> (); +pub type dc_set_config_t = fn(_: &Context, _: &str, _: Option<&str>) -> (); pub type dc_get_config_t = fn(_: &Context, _: &str) -> Option; pub type sqlite_int64 = i64; From 707c8c2830d655108b56d7ebde764e135443a8b5 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 30 Jul 2019 09:46:36 +0300 Subject: [PATCH 15/95] Make dc_split_armored_data return bool (#251) * Make dc_split_armored_data return bool * Remove double negations --- src/dc_imex.rs | 24 ++++++------- src/dc_msg.rs | 24 ++++++------- src/pgp.rs | 7 ++-- tests/stress.rs | 93 +++++++++++++++++++++---------------------------- 4 files changed, 65 insertions(+), 83 deletions(-) diff --git a/src/dc_imex.rs b/src/dc_imex.rs index c414fdbf1..8366d6570 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -462,20 +462,18 @@ pub unsafe fn dc_decrypt_setup_file( let mut payload: *mut libc::c_char = 0 as *mut libc::c_char; fc_buf = dc_strdup(filecontent); - if !(0 - == dc_split_armored_data( - fc_buf, - &mut fc_headerline, - 0 as *mut *const libc::c_char, - 0 as *mut *const libc::c_char, - &mut fc_base64, - ) - || fc_headerline.is_null() - || strcmp( + if dc_split_armored_data( + fc_buf, + &mut fc_headerline, + 0 as *mut *const libc::c_char, + 0 as *mut *const libc::c_char, + &mut fc_base64, + ) && !fc_headerline.is_null() + && strcmp( fc_headerline, b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, - ) != 0i32 - || fc_base64.is_null()) + ) == 0 + && !fc_base64.is_null() { /* convert base64 to binary */ /*must be freed using mmap_string_unref()*/ @@ -1154,7 +1152,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) -> private_key = buf; free(buf2 as *mut libc::c_void); buf2 = dc_strdup(buf); - if 0 != dc_split_armored_data( + if dc_split_armored_data( buf2, &mut buf2_headerline, 0 as *mut *const libc::c_char, diff --git a/src/dc_msg.rs b/src/dc_msg.rs index b6548f770..6df04d5cb 100644 --- a/src/dc_msg.rs +++ b/src/dc_msg.rs @@ -1031,19 +1031,17 @@ pub unsafe fn dc_msg_get_setupcodebegin(msg: *const dc_msg_t) -> *mut libc::c_ch || buf.is_null() || buf_bytes <= 0) { - if !(0 - == dc_split_armored_data( - buf, - &mut buf_headerline, - &mut buf_setupcodebegin, - 0 as *mut *const libc::c_char, - 0 as *mut *const libc::c_char, - ) - || strcmp( - buf_headerline, - b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, - ) != 0i32 - || buf_setupcodebegin.is_null()) + if dc_split_armored_data( + buf, + &mut buf_headerline, + &mut buf_setupcodebegin, + 0 as *mut *const libc::c_char, + 0 as *mut *const libc::c_char, + ) && strcmp( + buf_headerline, + b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, + ) == 0 + && !buf_setupcodebegin.is_null() { ret = dc_strdup(buf_setupcodebegin) } diff --git a/src/pgp.rs b/src/pgp.rs index 600a61fd2..bfc68f281 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -17,15 +17,14 @@ use crate::keyring::*; use crate::types::*; use crate::x::*; -// TODO should return bool /rtn pub unsafe fn dc_split_armored_data( buf: *mut libc::c_char, ret_headerline: *mut *const libc::c_char, ret_setupcodebegin: *mut *const libc::c_char, ret_preferencrypt: *mut *const libc::c_char, ret_base64: *mut *const libc::c_char, -) -> libc::c_int { - let mut success: libc::c_int = 0i32; +) -> bool { + let mut success = false; let mut line_chars: size_t = 0i32 as size_t; let mut line: *mut libc::c_char = buf; let mut p1: *mut libc::c_char = buf; @@ -128,7 +127,7 @@ pub unsafe fn dc_split_armored_data( if !ret_base64.is_null() { *ret_base64 = base64 } - success = 1i32 + success = true; } } } diff --git a/tests/stress.rs b/tests/stress.rs index 1a1e19d87..5b3408686 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -273,7 +273,6 @@ unsafe fn stress_functions(context: &Context) { assert!(res.contains(" configured_send_port ")); assert!(res.contains(" configured_server_flags ")); - let mut ok: libc::c_int; let mut buf_0: *mut libc::c_char; let mut headerline: *const libc::c_char = 0 as *const libc::c_char; let mut setupcodebegin: *const libc::c_char = 0 as *const libc::c_char; @@ -283,14 +282,14 @@ unsafe fn stress_functions(context: &Context) { b"-----BEGIN PGP MESSAGE-----\nNoVal:\n\ndata\n-----END PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, ); - ok = dc_split_armored_data( + let ok = dc_split_armored_data( buf_0, &mut headerline, &mut setupcodebegin, 0 as *mut *const libc::c_char, &mut base64, ); - assert_eq!(ok, 1); + assert!(ok); assert!(!headerline.is_null()); assert_eq!( strcmp( @@ -308,7 +307,7 @@ unsafe fn stress_functions(context: &Context) { buf_0 = strdup(b"-----BEGIN PGP MESSAGE-----\n\ndat1\n-----END PGP MESSAGE-----\n-----BEGIN PGP MESSAGE-----\n\ndat2\n-----END PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char); - ok = dc_split_armored_data( + let ok = dc_split_armored_data( buf_0, &mut headerline, &mut setupcodebegin, @@ -316,7 +315,7 @@ unsafe fn stress_functions(context: &Context) { &mut base64, ); - assert_eq!(ok, 1); + assert!(ok); assert!(!headerline.is_null()); assert_eq!( strcmp( @@ -335,7 +334,7 @@ unsafe fn stress_functions(context: &Context) { b"foo \n -----BEGIN PGP MESSAGE----- \n base64-123 \n -----END PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, ); - ok = dc_split_armored_data( + let ok = dc_split_armored_data( buf_0, &mut headerline, &mut setupcodebegin, @@ -343,7 +342,7 @@ unsafe fn stress_functions(context: &Context) { &mut base64, ); - assert_eq!(ok, 1); + assert!(ok); assert!(!headerline.is_null()); assert_eq!( strcmp( @@ -360,7 +359,7 @@ unsafe fn stress_functions(context: &Context) { free(buf_0 as *mut libc::c_void); buf_0 = strdup(b"foo-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char); - ok = dc_split_armored_data( + let ok = dc_split_armored_data( buf_0, &mut headerline, &mut setupcodebegin, @@ -368,19 +367,19 @@ unsafe fn stress_functions(context: &Context) { &mut base64, ); - assert_eq!(ok, 0); + assert!(!ok); free(buf_0 as *mut libc::c_void); buf_0 = strdup(b"foo \n -----BEGIN PGP MESSAGE-----\n Passphrase-BeGIN : 23 \n \n base64-567 \r\n abc \n -----END PGP MESSAGE-----\n\n\n\x00" as *const u8 as *const libc::c_char); - ok = dc_split_armored_data( + let ok = dc_split_armored_data( buf_0, &mut headerline, &mut setupcodebegin, 0 as *mut *const libc::c_char, &mut base64, ); - assert_eq!(ok, 1); + assert!(ok); assert!(!headerline.is_null()); assert_eq!( strcmp( @@ -407,14 +406,14 @@ unsafe fn stress_functions(context: &Context) { buf_0 = strdup(b"-----BEGIN PGP PRIVATE KEY BLOCK-----\n Autocrypt-Prefer-Encrypt : mutual \n\nbase64\n-----END PGP PRIVATE KEY BLOCK-----\x00" as *const u8 as *const libc::c_char); - ok = dc_split_armored_data( + let ok = dc_split_armored_data( buf_0, &mut headerline, 0 as *mut *const libc::c_char, &mut preferencrypt, &mut base64, ); - assert_eq!(ok, 1); + assert!(ok); assert!(!headerline.is_null()); assert_eq!( strcmp( @@ -470,16 +469,13 @@ unsafe fn stress_functions(context: &Context) { let mut setupcodebegin_0: *const libc::c_char = 0 as *const libc::c_char; let mut preferencrypt_0: *const libc::c_char = 0 as *const libc::c_char; buf_1 = strdup(S_EM_SETUPFILE); - assert_ne!( - 0, - dc_split_armored_data( - buf_1, - &mut headerline_0, - &mut setupcodebegin_0, - &mut preferencrypt_0, - 0 as *mut *const libc::c_char, - ) - ); + assert!(dc_split_armored_data( + buf_1, + &mut headerline_0, + &mut setupcodebegin_0, + &mut preferencrypt_0, + 0 as *mut *const libc::c_char, + )); assert!(!headerline_0.is_null()); assert_eq!( 0, @@ -499,16 +495,13 @@ unsafe fn stress_functions(context: &Context) { free(buf_1 as *mut libc::c_void); buf_1 = dc_decrypt_setup_file(context, S_EM_SETUPCODE, S_EM_SETUPFILE); assert!(!buf_1.is_null()); - assert_ne!( - 0, - dc_split_armored_data( - buf_1, - &mut headerline_0, - &mut setupcodebegin_0, - &mut preferencrypt_0, - 0 as *mut *const libc::c_char, - ) - ); + assert!(dc_split_armored_data( + buf_1, + &mut headerline_0, + &mut setupcodebegin_0, + &mut preferencrypt_0, + 0 as *mut *const libc::c_char, + )); assert!(!headerline_0.is_null()); assert_eq!( strcmp( @@ -549,16 +542,13 @@ unsafe fn stress_functions(context: &Context) { let buf_2: *mut libc::c_char = dc_strdup(setupfile); let mut headerline_1: *const libc::c_char = 0 as *const libc::c_char; let mut setupcodebegin_1: *const libc::c_char = 0 as *const libc::c_char; - assert_eq!( - 0, - dc_split_armored_data( - buf_2, - &mut headerline_1, - &mut setupcodebegin_1, - 0 as *mut *const libc::c_char, - 0 as *mut *const libc::c_char, - ) - ); + assert!(!dc_split_armored_data( + buf_2, + &mut headerline_1, + &mut setupcodebegin_1, + 0 as *mut *const libc::c_char, + 0 as *mut *const libc::c_char, + )); assert!(!headerline_1.is_null()); assert_eq!( strcmp( @@ -577,16 +567,13 @@ unsafe fn stress_functions(context: &Context) { let mut headerline_2: *const libc::c_char = 0 as *const libc::c_char; payload = dc_decrypt_setup_file(context, setupcode, setupfile); assert!(payload.is_null()); - assert_eq!( - 0, - dc_split_armored_data( - payload, - &mut headerline_2, - 0 as *mut *const libc::c_char, - 0 as *mut *const libc::c_char, - 0 as *mut *const libc::c_char, - ) - ); + assert!(!dc_split_armored_data( + payload, + &mut headerline_2, + 0 as *mut *const libc::c_char, + 0 as *mut *const libc::c_char, + 0 as *mut *const libc::c_char, + )); assert!(!headerline_2.is_null()); assert_eq!( strcmp( From 73298c0273924c29e35521b6b2d4aadd32bf59b8 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Tue, 30 Jul 2019 07:58:28 +0000 Subject: [PATCH 16/95] chore: fix and enforce compiler warnings on CI --- ci/run.sh | 1 + src/chatlist.rs | 4 ++-- src/dc_array.rs | 1 + src/x.rs | 2 -- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/run.sh b/ci/run.sh index 1a770dbfe..e61a4abbc 100755 --- a/ci/run.sh +++ b/ci/run.sh @@ -4,6 +4,7 @@ set -ex export RUST_TEST_THREADS=1 export RUST_BACKTRACE=1 +export RUSTFLAGS='--deny warnings' export OPT="--target=$TARGET" export OPT_RELEASE="--release ${OPT}" export OPT_FFI_RELEASE="--manifest-path=deltachat-ffi/Cargo.toml --release" diff --git a/src/chatlist.rs b/src/chatlist.rs index 112363098..5f93d35e4 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -155,7 +155,7 @@ impl<'a> Chatlist<'a> { let query = query.trim().to_string(); ensure!(!query.is_empty(), "missing query"); - let strLikeCmd = format!("%{}%", query); + let str_like_cmd = format!("%{}%", query); context.sql.query_map( "SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \ ON c.id=m.chat_id \ @@ -164,7 +164,7 @@ impl<'a> Chatlist<'a> { AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \ AND c.blocked=0 AND c.name LIKE ? \ GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;", - params![strLikeCmd], + params![str_like_cmd], process_row, process_rows, )? diff --git a/src/dc_array.rs b/src/dc_array.rs index b2834233a..b582e474a 100644 --- a/src/dc_array.rs +++ b/src/dc_array.rs @@ -4,6 +4,7 @@ use crate::types::*; /* * the structure behind dc_array_t */ #[derive(Clone)] +#[allow(non_camel_case_types)] pub enum dc_array_t { Locations(Vec), Uint(Vec), diff --git a/src/x.rs b/src/x.rs index 27b309b34..f1bb01e37 100644 --- a/src/x.rs +++ b/src/x.rs @@ -1,5 +1,3 @@ -use crate::types::*; - pub use libc::{ calloc, exit, free, malloc, memcmp, memcpy, memmove, memset, realloc, strcat, strchr, strcmp, strcpy, strcspn, strlen, strncmp, strncpy, strrchr, strspn, strstr, strtol, system, From a41c0614cca0ac9d3f0b2fd73f79da5fa50e44ad Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Tue, 30 Jul 2019 14:08:15 +0000 Subject: [PATCH 17/95] Make dc_msg_is_starred() return bool --- deltachat-ffi/src/lib.rs | 2 +- examples/repl/cmdline.rs | 6 +----- src/dc_msg.rs | 7 +++---- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 507fd7de5..ab8b7ffce 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -1361,7 +1361,7 @@ pub unsafe extern "C" fn dc_msg_is_sent(msg: *mut dc_msg::dc_msg_t) -> libc::c_i #[no_mangle] pub unsafe extern "C" fn dc_msg_is_starred(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { - dc_msg::dc_msg_is_starred(msg) + dc_msg::dc_msg_is_starred(msg).into() } #[no_mangle] diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index d05432ace..960446fa5 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -246,11 +246,7 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef, msg: *mut dc_msg_t as_str(contact_name), contact_id, as_str(msgtext), - if 0 != dc_msg_is_starred(msg) { - "★" - } else { - "" - }, + if dc_msg_is_starred(msg) { "★" } else { "" }, if dc_msg_get_from_id(msg) == 1 as libc::c_uint { "" } else if dc_msg_get_state(msg) == DC_STATE_IN_SEEN { diff --git a/src/dc_msg.rs b/src/dc_msg.rs index 6df04d5cb..df4ed8bfe 100644 --- a/src/dc_msg.rs +++ b/src/dc_msg.rs @@ -949,12 +949,11 @@ pub unsafe fn dc_msg_is_sent(msg: *const dc_msg_t) -> libc::c_int { } } -// TODO should return bool /rtn -pub unsafe fn dc_msg_is_starred(msg: *const dc_msg_t) -> libc::c_int { +pub unsafe fn dc_msg_is_starred(msg: *const dc_msg_t) -> bool { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { - return 0i32; + return false; } - return if 0 != (*msg).starred { 1i32 } else { 0i32 }; + 0 != (*msg).starred } // TODO should return bool /rtn From d6dae0a9e892d1fead9831fc14bf18e229d8ca1f Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 31 Jul 2019 03:08:20 +0300 Subject: [PATCH 18/95] Make dc_array_sort_ids() safe and move it into impl --- src/dc_array.rs | 21 +++++++++------------ src/dc_receive_imf.rs | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/dc_array.rs b/src/dc_array.rs index b582e474a..2ca9164c2 100644 --- a/src/dc_array.rs +++ b/src/dc_array.rs @@ -137,6 +137,14 @@ impl dc_array_t { panic!("Attempt to search for id in array of other type"); } } + + pub fn sort_ids(&mut self) { + if let dc_array_t::Uint(v) = self { + v.sort(); + } else { + panic!("Attempt to sort array of something other than uints"); + } + } } pub unsafe fn dc_array_unref(array: *mut dc_array_t) { @@ -340,17 +348,6 @@ pub unsafe fn dc_array_duplicate(array: *const dc_array_t) -> *mut dc_array_t { } } -pub unsafe fn dc_array_sort_ids(array: *mut dc_array_t) { - if array.is_null() || (*array).len() <= 1 { - return; - } - if let dc_array_t::Uint(v) = &mut *array { - v.sort(); - } else { - panic!("Attempt to sort array of something other than uints"); - } -} - pub unsafe fn dc_array_get_string( array: *const dc_array_t, sep: *const libc::c_char, @@ -417,7 +414,7 @@ mod tests { dc_array_add_id(arr, 0 as uint32_t); dc_array_add_id(arr, 5000 as uint32_t); - dc_array_sort_ids(arr); + (*arr).sort_ids(); assert_eq!(dc_array_get_id(arr, 0 as size_t), 0); assert_eq!(dc_array_get_id(arr, 1 as size_t), 7); diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 35964de91..c7d27b558 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -1554,7 +1554,7 @@ unsafe fn search_chat_ids_by_contact_ids( i += 1 } if !(dc_array_get_cnt(contact_ids) == 0) { - dc_array_sort_ids(contact_ids); + (*contact_ids).sort_ids(); contact_ids_str = dc_array_get_string(contact_ids, b",\x00" as *const u8 as *const libc::c_char); From 7bc338fc72958d58c2981cd841af646d8a0e3d5e Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 31 Jul 2019 15:51:50 +0300 Subject: [PATCH 19/95] Mark get_backoff_time_offset as safe --- src/dc_job.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dc_job.rs b/src/dc_job.rs index 2119c738f..fe30c4873 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -251,7 +251,7 @@ fn dc_job_delete(context: &Context, job: &dc_job_t) -> bool { * Tools ******************************************************************************/ #[allow(non_snake_case)] -unsafe fn get_backoff_time_offset(c_tries: libc::c_int) -> i64 { +fn get_backoff_time_offset(c_tries: libc::c_int) -> i64 { // results in ~3 weeks for the last backoff timespan let mut N = 2_i32.pow((c_tries - 1) as u32); N = N * 60; From 8267ffb8d203994253f8ef6bce694059f424ae19 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 31 Jul 2019 15:57:05 +0300 Subject: [PATCH 20/95] Replace dc_mimeparser_t::reports carray with Vec --- src/dc_mimeparser.rs | 21 +++++---------------- src/dc_receive_imf.rs | 13 +++---------- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index f5bc4cc64..f740d3232 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -55,7 +55,7 @@ pub struct dc_mimeparser_t<'a> { pub e2ee_helper: dc_e2ee_helper_t, pub is_forwarded: libc::c_int, pub context: &'a Context, - pub reports: *mut carray, + pub reports: Vec<*mut mailmime>, pub is_system_message: libc::c_int, pub location_kml: Option, pub message_kml: Option, @@ -82,7 +82,7 @@ pub unsafe fn dc_mimeparser_new(context: &Context) -> dc_mimeparser_t { e2ee_helper: Default::default(), is_forwarded: 0, context, - reports: carray_new(16i32 as libc::c_uint), + reports: Vec::new(), is_system_message: 0, location_kml: None, message_kml: None, @@ -94,9 +94,6 @@ pub unsafe fn dc_mimeparser_unref(mimeparser: &mut dc_mimeparser_t) { if !(*mimeparser).parts.is_null() { carray_free((*mimeparser).parts); } - if !(*mimeparser).reports.is_null() { - carray_free((*mimeparser).reports); - } } pub unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) { @@ -128,9 +125,7 @@ pub unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) { (*mimeparser).mimeroot = 0 as *mut mailmime } (*mimeparser).is_forwarded = 0i32; - if !(*mimeparser).reports.is_null() { - carray_set_size((*mimeparser).reports, 0i32 as libc::c_uint); - } + (*mimeparser).reports.clear(); (*mimeparser).decrypting_failed = 0i32; dc_e2ee_thanks(&mut (*mimeparser).e2ee_helper); @@ -396,9 +391,7 @@ pub unsafe fn dc_mimeparser_parse( } } /* Cleanup - and try to create at least an empty part if there are no parts yet */ - if dc_mimeparser_get_last_nonmeta(mimeparser).is_null() - && carray_count((*mimeparser).reports) == 0i32 as libc::c_uint - { + if dc_mimeparser_get_last_nonmeta(mimeparser).is_null() && (*mimeparser).reports.is_empty() { let mut part_5 = dc_mimepart_new(); part_5.type_0 = 10i32; if !(*mimeparser).subject.is_null() && 0 == (*mimeparser).is_send_by_messenger { @@ -705,11 +698,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive( b"disposition-notification\x00" as *const u8 as *const libc::c_char, ) == 0i32 { - carray_add( - (*mimeparser).reports, - mime as *mut libc::c_void, - 0 as *mut libc::c_uint, - ); + (*mimeparser).reports.push(mime); } else { any_part_added = dc_mimeparser_parse_mime_recursive( mimeparser, diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 35964de91..01f88538c 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -51,8 +51,6 @@ pub unsafe fn dc_receive_imf( let mut add_delete_job: libc::c_int = 0; let mut insert_msg_id: uint32_t = 0 as uint32_t; - let mut i: size_t; - let mut icnt: size_t; /* Message-ID from the header */ let mut rfc724_mid = 0 as *mut libc::c_char; let mut sort_timestamp = 0; @@ -437,7 +435,7 @@ pub unsafe fn dc_receive_imf( ) } } - icnt = carray_count(mime_parser.parts) as size_t; + let icnt = carray_count(mime_parser.parts) as size_t; context.sql.prepare( "INSERT INTO msgs \ @@ -588,17 +586,13 @@ pub unsafe fn dc_receive_imf( match current_block { 16282941964262048061 => {} _ => { - if carray_count(mime_parser.reports) > 0 as libc::c_uint { + if !mime_parser.reports.is_empty() { let mdns_enabled = context .sql .get_config_int(context, "mdns_enabled") .unwrap_or_else(|| 1); - icnt = carray_count(mime_parser.reports) as size_t; - i = 0 as size_t; - while i < icnt { + for report_root in mime_parser.reports { let mut mdn_consumed: libc::c_int = 0; - let report_root: *mut mailmime = - carray_get(mime_parser.reports, i as libc::c_uint) as *mut mailmime; let report_type: *mut mailmime_parameter = mailmime_find_ct_parameter( report_root, b"report-type\x00" as *const u8 as *const libc::c_char, @@ -757,7 +751,6 @@ pub unsafe fn dc_receive_imf( } } } - i = i.wrapping_add(1) } } if !mime_parser.message_kml.is_none() && chat_id > 9 as libc::c_uint { From 0b679f8b95adba1b87e50076ffabbdde97ab6fd8 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 29 Jul 2019 14:19:43 +0300 Subject: [PATCH 21/95] dc_tools: Make dc_create_id() safe --- src/dc_chat.rs | 2 +- src/dc_securejoin.rs | 4 +-- src/dc_tools.rs | 84 +++++++++++++++++++++++++------------------- 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/dc_chat.rs b/src/dc_chat.rs index 18d0d6922..4166d7db6 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -1494,7 +1494,7 @@ pub unsafe fn dc_create_group_chat( let draft_txt = CString::new(context.stock_string_repl_str(StockMessage::NewGroupDraft, as_str(chat_name))) .unwrap(); - let grpid = as_str(dc_create_id()); + let grpid = dc_create_id(); if sql::execute( context, &context.sql, diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index 22ed7bcb5..3bf1f305b 100644 --- a/src/dc_securejoin.rs +++ b/src/dc_securejoin.rs @@ -45,12 +45,12 @@ pub unsafe fn dc_get_securejoin_qr( dc_ensure_secret_key_exists(context); invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id); if invitenumber.is_null() { - invitenumber = dc_create_id(); + invitenumber = to_cstring(dc_create_id()); dc_token_save(context, DC_TOKEN_INVITENUMBER, group_chat_id, invitenumber); } auth = dc_token_lookup(context, DC_TOKEN_AUTH, group_chat_id); if auth.is_null() { - auth = dc_create_id(); + auth = to_cstring(dc_create_id()); dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth); } let self_addr = context.sql.get_config(context, "configured_addr"); diff --git a/src/dc_tools.rs b/src/dc_tools.rs index d2db0afa2..f34cdad26 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -720,7 +720,7 @@ pub unsafe fn dc_create_smeared_timestamps(context: &Context, count: libc::c_int } /* Message-ID tools */ -pub unsafe fn dc_create_id() -> *mut libc::c_char { +pub fn dc_create_id() -> String { /* generate an id. the generated ID should be as short and as unique as possible: - short, because it may also used as part of Message-ID headers or in QR codes - unique as two IDs generated on two devices should not be the same. However, collisions are not world-wide but only by the few contacts. @@ -738,39 +738,34 @@ pub unsafe fn dc_create_id() -> *mut libc::c_char { encode_66bits_as_base64(buf[0usize], buf[1usize], buf[2usize]) } -/* ****************************************************************************** - * generate Message-IDs - ******************************************************************************/ -unsafe fn encode_66bits_as_base64(v1: uint32_t, v2: uint32_t, fill: uint32_t) -> *mut libc::c_char { - /* encode 66 bits as a base64 string. This is useful for ID generating with short strings as - we save 5 character in each id compared to 64 bit hex encoding, for a typical group ID, these are 10 characters (grpid+msgid): - hex: 64 bit, 4 bits/character, length = 64/4 = 16 characters - base64: 64 bit, 6 bits/character, length = 64/6 = 11 characters (plus 2 additional bits) */ - let ret: *mut libc::c_char = malloc(12) as *mut libc::c_char; - assert!(!ret.is_null()); - - static mut CHARS: [libc::c_char; 65] = [ +/// Encode 66 bits as a base64 string. +/// This is useful for ID generating with short strings as we save 5 character +/// in each id compared to 64 bit hex encoding. For a typical group ID, these +/// are 10 characters (grpid+msgid): +/// hex: 64 bit, 4 bits/character, length = 64/4 = 16 characters +/// base64: 64 bit, 6 bits/character, length = 64/6 = 11 characters (plus 2 additional bits) +/// Only the lower 2 bits of `fill` are used. +fn encode_66bits_as_base64(v1: u32, v2: u32, fill: u32) -> String { + static CHARS: [u8; 65] = [ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95, 0, ]; - *ret.offset(0isize) = CHARS[(v1 >> 26i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(1isize) = CHARS[(v1 >> 20i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(2isize) = CHARS[(v1 >> 14i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(3isize) = CHARS[(v1 >> 8i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(4isize) = CHARS[(v1 >> 2i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(5isize) = CHARS - [(v1 << 4i32 & 0x30i32 as libc::c_uint | v2 >> 28i32 & 0xfi32 as libc::c_uint) as usize]; - *ret.offset(6isize) = CHARS[(v2 >> 22i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(7isize) = CHARS[(v2 >> 16i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(8isize) = CHARS[(v2 >> 10i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(9isize) = CHARS[(v2 >> 4i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(10isize) = - CHARS[(v2 << 2i32 & 0x3ci32 as libc::c_uint | fill & 0x3i32 as libc::c_uint) as usize]; - *ret.offset(11isize) = 0i32 as libc::c_char; - - ret + let ret = vec![ + CHARS[((v1 >> 26) & 0x3f) as usize], + CHARS[((v1 >> 20) & 0x3f) as usize], + CHARS[((v1 >> 14) & 0x3f) as usize], + CHARS[((v1 >> 8) & 0x3f) as usize], + CHARS[((v1 >> 2) & 0x3f) as usize], + CHARS[(((v1 << 4) & 0x30) | ((v2 >> 28) & 0x0f)) as usize], + CHARS[((v2 >> 22) & 0x3f) as usize], + CHARS[((v2 >> 16) & 0x3f) as usize], + CHARS[((v2 >> 10) & 0x3f) as usize], + CHARS[((v2 >> 4) & 0x3f) as usize], + CHARS[(((v2 << 2) & 0x3c) | (fill & 0x03)) as usize], + ]; + String::from_utf8(ret).unwrap() } pub unsafe fn dc_create_incoming_rfc724_mid( @@ -810,7 +805,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( - the message ID should be globally unique - do not add a counter or any private data as as this may give unneeded information to the receiver */ let mut rand1: *mut libc::c_char = 0 as *mut libc::c_char; - let rand2: *mut libc::c_char = dc_create_id(); + let rand2: *mut libc::c_char = to_cstring(dc_create_id()); let ret: *mut libc::c_char; let mut at_hostname: *const libc::c_char = strchr(from_addr, '@' as i32); if at_hostname.is_null() { @@ -824,7 +819,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( at_hostname, ) } else { - rand1 = dc_create_id(); + rand1 = to_cstring(dc_create_id()); ret = dc_mprintf( b"Mr.%s.%s%s\x00" as *const u8 as *const libc::c_char, rand1, @@ -1981,11 +1976,28 @@ mod tests { #[test] fn test_dc_create_id() { - unsafe { - let buf = dc_create_id(); - assert_eq!(strlen(buf), 11); - free(buf as *mut libc::c_void); - } + let buf = dc_create_id(); + assert_eq!(buf.len(), 11); + } + + #[test] + fn test_encode_66bits_as_base64() { + assert_eq!( + encode_66bits_as_base64(0x01234567, 0x89abcdef, 0), + "ASNFZ4mrze8" + ); + assert_eq!( + encode_66bits_as_base64(0x01234567, 0x89abcdef, 1), + "ASNFZ4mrze9" + ); + assert_eq!( + encode_66bits_as_base64(0x01234567, 0x89abcdef, 2), + "ASNFZ4mrze-" + ); + assert_eq!( + encode_66bits_as_base64(0x01234567, 0x89abcdef, 3), + "ASNFZ4mrze_" + ); } #[test] From 164a8fe39ace6117116266cdccb974d8e98d6cf6 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 30 Jul 2019 01:59:36 +0300 Subject: [PATCH 22/95] encode_66bits_as_base64: use base64 crate --- Cargo.lock | 1 + Cargo.toml | 1 + src/dc_tools.rs | 32 ++++++++++++-------------------- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93f5cbdb6..1a1738981 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -463,6 +463,7 @@ dependencies = [ "addr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 2d42e6798..883ddbd42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ strum = "0.15.0" strum_macros = "0.15.0" thread-local-object = "0.1.0" backtrace = "0.3.33" +byteorder = "1.3.1" [dev-dependencies] tempfile = "3.0" diff --git a/src/dc_tools.rs b/src/dc_tools.rs index f34cdad26..e50ad15da 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -746,26 +746,18 @@ pub fn dc_create_id() -> String { /// base64: 64 bit, 6 bits/character, length = 64/6 = 11 characters (plus 2 additional bits) /// Only the lower 2 bits of `fill` are used. fn encode_66bits_as_base64(v1: u32, v2: u32, fill: u32) -> String { - static CHARS: [u8; 65] = [ - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 45, 95, 0, - ]; - let ret = vec![ - CHARS[((v1 >> 26) & 0x3f) as usize], - CHARS[((v1 >> 20) & 0x3f) as usize], - CHARS[((v1 >> 14) & 0x3f) as usize], - CHARS[((v1 >> 8) & 0x3f) as usize], - CHARS[((v1 >> 2) & 0x3f) as usize], - CHARS[(((v1 << 4) & 0x30) | ((v2 >> 28) & 0x0f)) as usize], - CHARS[((v2 >> 22) & 0x3f) as usize], - CHARS[((v2 >> 16) & 0x3f) as usize], - CHARS[((v2 >> 10) & 0x3f) as usize], - CHARS[((v2 >> 4) & 0x3f) as usize], - CHARS[(((v2 << 2) & 0x3c) | (fill & 0x03)) as usize], - ]; - String::from_utf8(ret).unwrap() + use byteorder::{BigEndian, WriteBytesExt}; + + let mut wrapped_writer = Vec::new(); + { + let mut enc = base64::write::EncoderWriter::new(&mut wrapped_writer, base64::URL_SAFE); + enc.write_u32::(v1).unwrap(); + enc.write_u32::(v2).unwrap(); + enc.write_u8(((fill & 0x3) as u8) << 6).unwrap(); + enc.finish().unwrap(); + } + assert_eq!(wrapped_writer.pop(), Some('A' as u8)); // Remove last "A" + String::from_utf8(wrapped_writer).unwrap() } pub unsafe fn dc_create_incoming_rfc724_mid( From 9fb9fb0fc1d1f3771d26bac7a646ac37463eddd0 Mon Sep 17 00:00:00 2001 From: jikstra Date: Mon, 29 Jul 2019 16:15:07 +0200 Subject: [PATCH 23/95] Remove goto/current_block logic with OK_TO_CONTINUE. Keeps identation --- src/dc_tools.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index e50ad15da..91ead6bbe 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -264,7 +264,7 @@ pub unsafe fn dc_unify_lineends(buf: *mut libc::c_char) { /* replace bad UTF-8 characters by sequences of `_` (to avoid problems in filenames, we do not use eg. `?`) the function is useful if strings are unexpectingly encoded eg. as ISO-8859-1 */ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) { - let current_block: u64; + let mut OK_TO_CONTINUE = true; if buf.is_null() { return; } @@ -280,7 +280,6 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) { ix = p1len; 's_36: loop { if !(i < ix) { - current_block = 13550086250199790493; break; } c = *p1.offset(i as isize) as libc::c_int; @@ -293,7 +292,7 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) { && *p1.offset((i + 1i32) as isize) as libc::c_int & 0xa0i32 == 0xa0i32 { /* U+d800 to U+dfff */ - current_block = 2775201239069267972; + OK_TO_CONTINUE = false; break; } else if c & 0xf0i32 == 0xe0i32 { n = 2i32 @@ -302,7 +301,7 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) { } else { //else if ((c & 0xFC) == 0xF8) { n=4; } /* 111110bb - not valid in https://tools.ietf.org/html/rfc3629 */ //else if ((c & 0xFE) == 0xFC) { n=5; } /* 1111110b - not valid in https://tools.ietf.org/html/rfc3629 */ - current_block = 2775201239069267972; + OK_TO_CONTINUE = false; break; } j = 0i32; @@ -310,16 +309,14 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) { /* n bytes matching 10bbbbbb follow ? */ i += 1; if i == ix || *p1.offset(i as isize) as libc::c_int & 0xc0i32 != 0x80i32 { - current_block = 2775201239069267972; + OK_TO_CONTINUE = false; break 's_36; } j += 1 } i += 1 } - match current_block { - 13550086250199790493 => return, - _ => { + if OK_TO_CONTINUE == false { while 0 != *p1 { if *p1 as libc::c_int > 0x7fi32 { *p1 = '_' as i32 as libc::c_uchar @@ -327,8 +324,7 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) { p1 = p1.offset(1isize) } return; - } - }; + } } pub unsafe fn dc_utf8_strlen(s: *const libc::c_char) -> size_t { From 566d255b33fa8ab928d43a7322e909788fc6bace Mon Sep 17 00:00:00 2001 From: jikstra Date: Mon, 29 Jul 2019 16:16:47 +0200 Subject: [PATCH 24/95] run cargo fmt --- src/dc_tools.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 91ead6bbe..5e524bdbe 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -317,13 +317,13 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) { i += 1 } if OK_TO_CONTINUE == false { - while 0 != *p1 { - if *p1 as libc::c_int > 0x7fi32 { - *p1 = '_' as i32 as libc::c_uchar - } - p1 = p1.offset(1isize) + while 0 != *p1 { + if *p1 as libc::c_int > 0x7fi32 { + *p1 = '_' as i32 as libc::c_uchar } - return; + p1 = p1.offset(1isize) + } + return; } } From 8274c6bf1728bacf5174802cb6e82ee7e852f518 Mon Sep 17 00:00:00 2001 From: jikstra Date: Mon, 29 Jul 2019 16:23:43 +0200 Subject: [PATCH 25/95] Allow non_snake_case in dc_replace_bad_utf8_chars function --- src/dc_tools.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 5e524bdbe..393b66860 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -263,6 +263,7 @@ pub unsafe fn dc_unify_lineends(buf: *mut libc::c_char) { } /* replace bad UTF-8 characters by sequences of `_` (to avoid problems in filenames, we do not use eg. `?`) the function is useful if strings are unexpectingly encoded eg. as ISO-8859-1 */ +#[allow(non_snake_case)] pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) { let mut OK_TO_CONTINUE = true; if buf.is_null() { From 39e530f7591d0d2a9a03db1b022ac3df4828a1b2 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Tue, 30 Jul 2019 21:25:45 +0000 Subject: [PATCH 26/95] Change Context.os_name field to String --- deltachat-ffi/src/lib.rs | 9 ++++++++- examples/repl/main.rs | 2 +- examples/simple.rs | 2 +- src/context.rs | 18 +++++++++++++----- src/dc_mimefactory.rs | 22 +++++++++++----------- src/lib.rs | 2 +- src/peerstate.rs | 2 +- src/stock.rs | 12 ++++++------ src/test_utils.rs | 2 +- tests/stress.rs | 4 ++-- 10 files changed, 45 insertions(+), 30 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 507fd7de5..0215b8da5 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -30,7 +30,13 @@ pub unsafe extern "C" fn dc_context_new( ) -> *mut dc_context_t { setup_panic!(); + let os_name = if os_name.is_null() { + None + } else { + Some(dc_tools::to_string_lossy(os_name)) + }; let ctx = context::dc_context_new(cb, userdata, os_name); + Box::into_raw(Box::new(ctx)) } @@ -38,7 +44,8 @@ pub unsafe extern "C" fn dc_context_new( pub unsafe extern "C" fn dc_context_unref(context: *mut dc_context_t) { assert!(!context.is_null()); let context = &mut *context; - context::dc_context_unref(context) + context::dc_context_unref(context); + Box::from_raw(context); } #[no_mangle] diff --git a/examples/repl/main.rs b/examples/repl/main.rs index 214527467..da7b28cab 100644 --- a/examples/repl/main.rs +++ b/examples/repl/main.rs @@ -393,7 +393,7 @@ fn main_0(args: Vec) -> Result<(), failure::Error> { let mut context = dc_context_new( Some(receive_event), 0 as *mut libc::c_void, - b"CLI\x00" as *const u8 as *const libc::c_char, + Some("CLI".into()), ); unsafe { dc_cmdline_skip_auth() }; diff --git a/examples/simple.rs b/examples/simple.rs index 2aa824acb..fc80fda68 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -41,7 +41,7 @@ extern "C" fn cb(_ctx: &Context, event: Event, data1: usize, data2: usize) -> us fn main() { unsafe { - let ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut()); + let ctx = dc_context_new(Some(cb), std::ptr::null_mut(), None); let running = Arc::new(RwLock::new(true)); let info = dc_get_info(&ctx); let info_s = CStr::from_ptr(info); diff --git a/src/context.rs b/src/context.rs index 29d8525a4..0a985447c 100644 --- a/src/context.rs +++ b/src/context.rs @@ -35,7 +35,7 @@ pub struct Context { pub smtp_state: Arc<(Mutex, Condvar)>, pub oauth2_critical: Arc>, pub cb: Option, - pub os_name: *mut libc::c_char, + pub os_name: Option, pub cmdline_sel_chat_id: Arc>, pub bob: Arc>, pub last_smeared_timestamp: Arc>, @@ -116,7 +116,7 @@ pub struct SmtpState { pub fn dc_context_new( cb: Option, userdata: *mut libc::c_void, - os_name: *const libc::c_char, + os_name: Option, ) -> Context { Context { blobdir: Arc::new(RwLock::new(std::ptr::null_mut())), @@ -131,7 +131,7 @@ pub fn dc_context_new( })), userdata, cb, - os_name: unsafe { dc_strdup_keep_null(os_name) }, + os_name: os_name, running_state: Arc::new(RwLock::new(Default::default())), sql: Sql::new(), smtp: Arc::new(Mutex::new(Smtp::new())), @@ -165,6 +165,16 @@ pub fn dc_context_new( } } +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn no_crashes_on_context_deref() { + let mut ctx = dc_context_new(None, std::ptr::null_mut(), Some("Test OS".into())); + unsafe { dc_context_unref(&mut ctx) }; + } +} + unsafe fn cb_receive_imf( context: &Context, imf_raw_not_terminated: *const libc::c_char, @@ -252,8 +262,6 @@ pub unsafe fn dc_context_unref(context: &mut Context) { if 0 != dc_is_open(context) { dc_close(context); } - - free(context.os_name as *mut libc::c_void); } pub unsafe fn dc_close(context: &Context) { diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index e32b31315..a3cccb129 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -477,26 +477,26 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: references_list, 0 as *mut libc::c_char, ); + + let os_name = &(*factory).context.os_name; + let os_part = os_name + .as_ref() + .map(|s| format!("/{}", s)) + .unwrap_or_default(); + let os_part = CString::new(os_part).expect("String -> CString conversion failed"); + mailimf_fields_add( imf_fields, mailimf_field_new_custom( strdup(b"X-Mailer\x00" as *const u8 as *const libc::c_char), dc_mprintf( - b"Delta Chat Core %s%s%s\x00" as *const u8 as *const libc::c_char, + b"Delta Chat Core %s%s\x00" as *const u8 as *const libc::c_char, DC_VERSION_STR as *const u8 as *const libc::c_char, - if !(*(*factory).context).os_name.is_null() { - b"/\x00" as *const u8 as *const libc::c_char - } else { - b"\x00" as *const u8 as *const libc::c_char - }, - if !(*(*factory).context).os_name.is_null() { - (*(*factory).context).os_name - } else { - b"\x00" as *const u8 as *const libc::c_char - }, + os_part.as_ptr(), ), ), ); + mailimf_fields_add( imf_fields, mailimf_field_new_custom( diff --git a/src/lib.rs b/src/lib.rs index 66181db63..bf361ae0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(c_variadic, ptr_wrapping_offset_from)] +#![feature(c_variadic, ptr_wrapping_offset_from, ptr_cast)] #[macro_use] extern crate failure_derive; diff --git a/src/peerstate.rs b/src/peerstate.rs index 7d0f2f648..b8f9b7724 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -517,7 +517,7 @@ mod tests { } unsafe fn create_test_context() -> TestContext { - let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut()); + let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), None); let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); assert!( diff --git a/src/stock.rs b/src/stock.rs index 3dcd66dfb..3416c31ea 100644 --- a/src/stock.rs +++ b/src/stock.rs @@ -264,7 +264,7 @@ mod tests { #[test] fn test_stock_str() { - let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); + let ctx = dc_context_new(None, std::ptr::null_mut(), None); assert_eq!(ctx.stock_str(StockMessage::NoMessages), "No messages."); } @@ -290,7 +290,7 @@ mod tests { #[test] fn test_stock_string_repl_str() { - let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); + let ctx = dc_context_new(None, std::ptr::null_mut(), None); // uses %1$s substitution assert_eq!( ctx.stock_string_repl_str(StockMessage::Member, "42"), @@ -301,7 +301,7 @@ mod tests { #[test] fn test_stock_string_repl_int() { - let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); + let ctx = dc_context_new(None, std::ptr::null_mut(), None); assert_eq!( ctx.stock_string_repl_int(StockMessage::Member, 42), "42 member(s)" @@ -310,7 +310,7 @@ mod tests { #[test] fn test_stock_string_repl_str2() { - let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); + let ctx = dc_context_new(None, std::ptr::null_mut(), None); assert_eq!( ctx.stock_string_repl_str2(StockMessage::ServerResponse, "foo", "bar"), "Response from foo: bar" @@ -319,7 +319,7 @@ mod tests { #[test] fn test_stock_system_msg_simple() { - let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); + let ctx = dc_context_new(None, std::ptr::null_mut(), None); assert_eq!( ctx.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0), "Location streaming enabled." @@ -328,7 +328,7 @@ mod tests { #[test] fn test_stock_system_msg_add_member_by_me() { - let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); + let ctx = dc_context_new(None, std::ptr::null_mut(), None); assert_eq!( ctx.stock_system_msg( StockMessage::MsgAddMember, diff --git a/src/test_utils.rs b/src/test_utils.rs index f78aa14e6..5ba5c0a37 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -24,7 +24,7 @@ pub struct TestContext { /// [Context]: crate::context::Context pub fn test_context(cb: Option) -> TestContext { unsafe { - let mut ctx = dc_context_new(cb, std::ptr::null_mut(), std::ptr::null_mut()); + let mut ctx = dc_context_new(cb, std::ptr::null_mut(), None); let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); assert!( diff --git a/tests/stress.rs b/tests/stress.rs index 5b3408686..4f363cb5e 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -802,7 +802,7 @@ struct TestContext { } unsafe fn create_test_context() -> TestContext { - let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut()); + let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), None); let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); assert!( @@ -986,7 +986,7 @@ fn test_chat() { #[test] fn test_wrong_db() { unsafe { - let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut()); + let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), None); let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); std::fs::write(&dbfile, b"123").unwrap(); From 9e50e77031f7814119ab6b9eadae45fdb4f6b794 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 31 Jul 2019 20:06:05 +0000 Subject: [PATCH 27/95] Simplify dc_initiate_key_transfer() --- src/dc_imex.rs | 165 ++++++++++++++++++++++--------------------------- 1 file changed, 73 insertions(+), 92 deletions(-) diff --git a/src/dc_imex.rs b/src/dc_imex.rs index 1ed594f8b..4e2618870 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -98,101 +98,86 @@ pub unsafe fn dc_imex_has_backup( } pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { - let current_block: u64; - let mut success: libc::c_int = 0i32; - let mut setup_code: *mut libc::c_char; let mut setup_file_content: *mut libc::c_char = 0 as *mut libc::c_char; let mut setup_file_name: *mut libc::c_char = 0 as *mut libc::c_char; - let chat_id: uint32_t; let mut msg: *mut dc_msg_t = 0 as *mut dc_msg_t; - let msg_id: uint32_t; - if 0 == dc_alloc_ongoing(context) { - return 0 as *mut libc::c_char; + if dc_alloc_ongoing(context) == 0 { + return std::ptr::null_mut(); } - setup_code = to_cstring(dc_create_setup_code(context)); - if !setup_code.is_null() { - /* this may require a keypair to be created. this may take a second ... */ - if !context - .running_state - .clone() - .read() - .unwrap() - .shall_stop_ongoing - { - setup_file_content = dc_render_setup_file(context, setup_code); - if !setup_file_content.is_null() { - /* encrypting may also take a while ... */ - if !context - .running_state - .clone() - .read() - .unwrap() - .shall_stop_ongoing - { - setup_file_name = dc_get_fine_pathNfilename( + let setup_code = CString::new(dc_create_setup_code(context)).unwrap(); + /* this may require a keypair to be created. this may take a second ... */ + if !context + .running_state + .clone() + .read() + .unwrap() + .shall_stop_ongoing + { + setup_file_content = dc_render_setup_file(context, setup_code.as_ptr()); + if !setup_file_content.is_null() { + /* encrypting may also take a while ... */ + if !context + .running_state + .clone() + .read() + .unwrap() + .shall_stop_ongoing + { + setup_file_name = dc_get_fine_pathNfilename( + context, + b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, + b"autocrypt-setup-message.html\x00" as *const u8 as *const libc::c_char, + ); + if !(setup_file_name.is_null() + || 0 == dc_write_file( context, - b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, - b"autocrypt-setup-message.html\x00" as *const u8 as *const libc::c_char, - ); - if !(setup_file_name.is_null() - || 0 == dc_write_file( - context, - setup_file_name, - setup_file_content as *const libc::c_void, - strlen(setup_file_content), - )) - { - chat_id = dc_create_chat_by_contact_id(context, 1i32 as uint32_t); - if !(chat_id == 0i32 as libc::c_uint) { - msg = dc_msg_new_untyped(context); - (*msg).type_0 = DC_MSG_FILE; - (*msg).param.set(Param::File, as_str(setup_file_name)); + setup_file_name, + setup_file_content as *const libc::c_void, + strlen(setup_file_content), + )) + { + let chat_id = dc_create_chat_by_contact_id(context, 1i32 as uint32_t); + if !(chat_id == 0i32 as libc::c_uint) { + msg = dc_msg_new_untyped(context); + (*msg).type_0 = DC_MSG_FILE; + (*msg).param.set(Param::File, as_str(setup_file_name)); - (*msg) - .param - .set(Param::MimeType, "application/autocrypt-setup"); - (*msg).param.set_int(Param::Cmd, 6); - (*msg).param.set_int(Param::ForcePlaintext, 2); + (*msg) + .param + .set(Param::MimeType, "application/autocrypt-setup"); + (*msg).param.set_int(Param::Cmd, 6); + (*msg).param.set_int(Param::ForcePlaintext, 2); - if !context - .running_state - .clone() - .read() - .unwrap() - .shall_stop_ongoing - { - msg_id = dc_send_msg(context, chat_id, msg); - if !(msg_id == 0i32 as libc::c_uint) { + if !context + .running_state + .clone() + .read() + .unwrap() + .shall_stop_ongoing + { + let msg_id = dc_send_msg(context, chat_id, msg); + if msg_id != 0 { + dc_msg_unref(msg); + msg = 0 as *mut dc_msg_t; + info!(context, 0, "Wait for setup message being sent ...",); + loop { + if context + .running_state + .clone() + .read() + .unwrap() + .shall_stop_ongoing + { + break; + } + std::thread::sleep(std::time::Duration::from_secs(1)); + msg = dc_get_msg(context, msg_id); + if 0 != dc_msg_is_sent(msg) { + info!(context, 0, "... setup message sent.",); + break; + } dc_msg_unref(msg); - msg = 0 as *mut dc_msg_t; - info!(context, 0, "Wait for setup message being sent ...",); - loop { - if context - .running_state - .clone() - .read() - .unwrap() - .shall_stop_ongoing - { - current_block = 6116957410927263949; - break; - } - std::thread::sleep(std::time::Duration::from_secs(1)); - msg = dc_get_msg(context, msg_id); - if 0 != dc_msg_is_sent(msg) { - current_block = 6450636197030046351; - break; - } - dc_msg_unref(msg); - msg = 0 as *mut dc_msg_t - } - match current_block { - 6116957410927263949 => {} - _ => { - info!(context, 0, "... setup message sent.",); - success = 1; - } - } + msg = 0 as *mut dc_msg_t } } } @@ -201,16 +186,12 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { } } } - if 0 == success { - free(setup_code as *mut libc::c_void); - setup_code = 0 as *mut libc::c_char - } free(setup_file_name as *mut libc::c_void); free(setup_file_content as *mut libc::c_void); dc_msg_unref(msg); dc_free_ongoing(context); - setup_code + dc_strdup(setup_code.as_ptr()) } pub unsafe extern "C" fn dc_render_setup_file( From c04c8ff1032a17a85e78c55a1d1778ab83f128f0 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Mon, 29 Jul 2019 01:58:42 +0000 Subject: [PATCH 28/95] Introduce new enum: Viewtype With this change, kind of message is represented by value of enum `Viewtype' instead of raw libc::c_int, providing more type safety. This enum replaces DC_MSG_* constants. The only way to create `Viewtype' from libc::c_int is smart constructor. With this change, functions `dc_get_chat_media' and `dc_get_next_media' became less forgiving about invalid message type arguments. Previously, invalid message types were implicitly interpreted as 0 (Viewtype::Unknown). Now, function calls with invalid message type arguments are rejected (error code returned) on FFI boundary. Additionally, when `Viewtype' is read from database, it is checked to have sensible value. No tests assumed forgiving behaviour. --- Cargo.lock | 1 + deltachat-ffi/Cargo.toml | 1 + deltachat-ffi/src/lib.rs | 40 +++++++++++-- examples/repl/cmdline.rs | 19 ++++++- src/constants.rs | 119 +++++++++++++++++++++++++-------------- src/dc_chat.rs | 58 +++++++++---------- src/dc_imex.rs | 2 +- src/dc_job.rs | 4 +- src/dc_location.rs | 5 +- src/dc_mimefactory.rs | 19 +++---- src/dc_msg.rs | 84 +++++++++++++-------------- src/dc_securejoin.rs | 2 +- 12 files changed, 219 insertions(+), 135 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a1738981..ca7f78e6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -507,6 +507,7 @@ dependencies = [ "deltachat 1.0.0-alpha.3", "human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/deltachat-ffi/Cargo.toml b/deltachat-ffi/Cargo.toml index c4e0d8580..ad4a79228 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -18,6 +18,7 @@ crate-type = ["cdylib", "staticlib"] deltachat = { path = "../", default-features = false } libc = "0.2" human-panic = "1.0.1" +num-traits = "0.2.6" [features] default = ["vendored", "nightly", "ringbuf"] diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 3cef3ef07..045053044 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -9,7 +9,10 @@ #[macro_use] extern crate human_panic; +extern crate num_traits; +use num_traits::{FromPrimitive, ToPrimitive}; +use std::ptr; use std::str::FromStr; use deltachat::*; @@ -458,6 +461,14 @@ pub unsafe extern "C" fn dc_marknoticed_all_chats(context: *mut dc_context_t) { dc_chat::dc_marknoticed_all_chats(context); } +fn from_prim(s: S) -> Option +where + T: FromPrimitive, + S: Into, +{ + FromPrimitive::from_i64(s.into()) +} + #[no_mangle] pub unsafe extern "C" fn dc_get_chat_media( context: *mut dc_context_t, @@ -469,7 +480,15 @@ pub unsafe extern "C" fn dc_get_chat_media( assert!(!context.is_null()); let context = &*context; - dc_chat::dc_get_chat_media(context, chat_id, msg_type, or_msg_type2, or_msg_type3) + if let (Some(msg_type), Some(or_msg_type2), Some(or_msg_type3)) = ( + from_prim(msg_type), + from_prim(or_msg_type2), + from_prim(or_msg_type3), + ) { + dc_chat::dc_get_chat_media(context, chat_id, msg_type, or_msg_type2, or_msg_type3) + } else { + ptr::null_mut() + } } #[no_mangle] @@ -484,7 +503,15 @@ pub unsafe extern "C" fn dc_get_next_media( assert!(!context.is_null()); let context = &*context; - dc_chat::dc_get_next_media(context, msg_id, dir, msg_type, or_msg_type2, or_msg_type3) + if let (Some(msg_type), Some(or_msg_type2), Some(or_msg_type3)) = ( + from_prim(msg_type), + from_prim(or_msg_type2), + from_prim(or_msg_type3), + ) { + dc_chat::dc_get_next_media(context, msg_id, dir, msg_type, or_msg_type2, or_msg_type3) + } else { + 0 + } } #[no_mangle] @@ -1236,8 +1263,11 @@ pub unsafe extern "C" fn dc_msg_new<'a>( ) -> *mut dc_msg::dc_msg_t<'a> { assert!(!context.is_null()); let context = &*context; - - dc_msg::dc_msg_new(context, viewtype) + if let Some(viewtype) = from_prim(viewtype) { + dc_msg::dc_msg_new(context, viewtype) + } else { + ptr::null_mut() + } } #[no_mangle] @@ -1268,6 +1298,8 @@ pub unsafe extern "C" fn dc_msg_get_chat_id(msg: *mut dc_msg::dc_msg_t) -> u32 { #[no_mangle] pub unsafe extern "C" fn dc_msg_get_viewtype(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { dc_msg::dc_msg_get_viewtype(msg) + .to_i64() + .expect("impossible: Viewtype -> i64 conversion failed") as libc::c_int } #[no_mangle] diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 960446fa5..f6bcb083d 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -963,7 +963,14 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E ensure!(!sel_chat.is_null(), "No chat selected."); ensure!(!arg1.is_empty() && !arg2.is_empty(), "No file given."); - let msg_0 = dc_msg_new(context, if arg0 == "sendimage" { 20 } else { 60 }); + let msg_0 = dc_msg_new( + context, + if arg0 == "sendimage" { + Viewtype::Image + } else { + Viewtype::File + }, + ); dc_msg_set_file(msg_0, arg1_c, 0 as *const libc::c_char); dc_msg_set_text(msg_0, arg2_c); dc_send_msg(context, dc_chat_get_id(sel_chat), msg_0); @@ -990,7 +997,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E ensure!(!sel_chat.is_null(), "No chat selected."); if !arg1.is_empty() { - let draft_0 = dc_msg_new(context, 10); + let draft_0 = dc_msg_new(context, Viewtype::Text); dc_msg_set_text(draft_0, arg1_c); dc_set_draft(context, dc_chat_get_id(sel_chat), draft_0); dc_msg_unref(draft_0); @@ -1003,7 +1010,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E "listmedia" => { ensure!(!sel_chat.is_null(), "No chat selected."); - let images = dc_get_chat_media(context, dc_chat_get_id(sel_chat), 20, 21, 50); + let images = dc_get_chat_media( + context, + dc_chat_get_id(sel_chat), + Viewtype::Image, + Viewtype::Gif, + Viewtype::Video, + ); let icnt: libc::c_int = dc_array_get_cnt(images) as libc::c_int; println!("{} images or videos: ", icnt); for i in 0..icnt { diff --git a/src/constants.rs b/src/constants.rs index e1eb5b835..e72019174 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,5 +1,9 @@ -#![allow(non_camel_case_types)] //! Constants +#![allow(non_camel_case_types)] +use num_traits::{FromPrimitive, ToPrimitive}; +use rusqlite as sql; +use rusqlite::types::*; +use std::fmt; pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00"; @@ -96,46 +100,6 @@ pub const DC_TEXT1_SELF: usize = 3; pub const DC_CREATE_MVBOX: usize = 1; -/// Text message. -/// The text of the message is set using dc_msg_set_text() -/// and retrieved with dc_msg_get_text(). -pub const DC_MSG_TEXT: i32 = 10; - -/// Image message. -/// If the image is an animated GIF, the type DC_MSG_GIF should be used. -/// File, width and height are set via dc_msg_set_file(), dc_msg_set_dimension -/// and retrieved via dc_msg_set_file(), dc_msg_set_dimension(). -pub const DC_MSG_IMAGE: i32 = 20; - -/// Animated GIF message. -/// File, width and height are set via dc_msg_set_file(), dc_msg_set_dimension() -/// and retrieved via dc_msg_get_file(), dc_msg_get_width(), dc_msg_get_height(). -pub const DC_MSG_GIF: i32 = 21; - -/// Message containing an Audio file. -/// File and duration are set via dc_msg_set_file(), dc_msg_set_duration() -/// and retrieved via dc_msg_get_file(), dc_msg_get_duration(). -pub const DC_MSG_AUDIO: i32 = 40; - -/// A voice message that was directly recorded by the user. -/// For all other audio messages, the type #DC_MSG_AUDIO should be used. -/// File and duration are set via dc_msg_set_file(), dc_msg_set_duration() -/// and retrieved via dc_msg_get_file(), dc_msg_get_duration() -pub const DC_MSG_VOICE: i32 = 41; - -/// Video messages. -/// File, width, height and durarion -/// are set via dc_msg_set_file(), dc_msg_set_dimension(), dc_msg_set_duration() -/// and retrieved via -/// dc_msg_get_file(), dc_msg_get_width(), -/// dc_msg_get_height(), dc_msg_get_duration(). -pub const DC_MSG_VIDEO: i32 = 50; - -/// Message containing any file, eg. a PDF. -/// The file is set via dc_msg_set_file() -/// and retrieved via dc_msg_get_file(). -pub const DC_MSG_FILE: i32 = 60; - // Flags for configuring IMAP and SMTP servers. // These flags are optional // and may be set together with the username, password etc. @@ -183,6 +147,79 @@ pub const DC_LP_IMAP_SOCKET_FLAGS: usize = pub const DC_LP_SMTP_SOCKET_FLAGS: usize = (DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN); +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] +#[repr(i32)] +pub enum Viewtype { + Unknown = 0, + /// Text message. + /// The text of the message is set using dc_msg_set_text() + /// and retrieved with dc_msg_get_text(). + Text = 10, + + /// Image message. + /// If the image is an animated GIF, the type DC_MSG_GIF should be used. + /// File, width and height are set via dc_msg_set_file(), dc_msg_set_dimension + /// and retrieved via dc_msg_set_file(), dc_msg_set_dimension(). + Image = 20, + + /// Animated GIF message. + /// File, width and height are set via dc_msg_set_file(), dc_msg_set_dimension() + /// and retrieved via dc_msg_get_file(), dc_msg_get_width(), dc_msg_get_height(). + Gif = 21, + + /// Message containing an Audio file. + /// File and duration are set via dc_msg_set_file(), dc_msg_set_duration() + /// and retrieved via dc_msg_get_file(), dc_msg_get_duration(). + Audio = 40, + + /// A voice message that was directly recorded by the user. + /// For all other audio messages, the type #DC_MSG_AUDIO should be used. + /// File and duration are set via dc_msg_set_file(), dc_msg_set_duration() + /// and retrieved via dc_msg_get_file(), dc_msg_get_duration() + Voice = 41, + + /// Video messages. + /// File, width, height and durarion + /// are set via dc_msg_set_file(), dc_msg_set_dimension(), dc_msg_set_duration() + /// and retrieved via + /// dc_msg_get_file(), dc_msg_get_width(), + /// dc_msg_get_height(), dc_msg_get_duration(). + Video = 50, + + /// Message containing any file, eg. a PDF. + /// The file is set via dc_msg_set_file() + /// and retrieved via dc_msg_get_file(). + File = 60, +} + +impl ToSql for Viewtype { + fn to_sql(&self) -> sql::Result { + let num: i64 = self + .to_i64() + .expect("impossible: Viewtype -> i64 conversion failed"); + + Ok(ToSqlOutput::Owned(Value::Integer(num))) + } +} + +impl FromSql for Viewtype { + fn column_result(col: ValueRef) -> FromSqlResult { + let inner = FromSql::column_result(col)?; + FromPrimitive::from_i64(inner).ok_or(FromSqlError::InvalidType) + } +} + +impl fmt::Display for Viewtype { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + self.to_i64() + .expect("impossible: Viewtype -> i64 conversion failed") + ) + } +} + // These constants are used as events // reported to the callback given to dc_context_new(). // If you do not want to handle an event, it is always safe to return 0, diff --git a/src/dc_chat.rs b/src/dc_chat.rs index 4166d7db6..03ebd1c03 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -371,14 +371,14 @@ pub unsafe fn dc_prepare_msg<'a>( return msg_id; } -pub fn msgtype_has_file(msgtype: i32) -> bool { +pub fn msgtype_has_file(msgtype: Viewtype) -> bool { match msgtype { - DC_MSG_IMAGE => true, - DC_MSG_GIF => true, - DC_MSG_AUDIO => true, - DC_MSG_VOICE => true, - DC_MSG_VIDEO => true, - DC_MSG_FILE => true, + Viewtype::Image => true, + Viewtype::Gif => true, + Viewtype::Audio => true, + Viewtype::Voice => true, + Viewtype::Video => true, + Viewtype::File => true, _ => false, } } @@ -392,7 +392,7 @@ unsafe fn prepare_msg_common<'a>( let mut OK_TO_CONTINUE = true; (*msg).id = 0i32 as uint32_t; (*msg).context = context; - if (*msg).type_0 == DC_MSG_TEXT { + if (*msg).type_0 == Viewtype::Text { /* the caller should check if the message text is empty */ } else if msgtype_has_file((*msg).type_0) { let mut pathNfilename = (*msg) @@ -417,16 +417,16 @@ unsafe fn prepare_msg_common<'a>( OK_TO_CONTINUE = false; } else { (*msg).param.set(Param::File, as_str(pathNfilename)); - if (*msg).type_0 == DC_MSG_FILE || (*msg).type_0 == DC_MSG_IMAGE { + if (*msg).type_0 == Viewtype::File || (*msg).type_0 == Viewtype::Image { /* Correct the type, take care not to correct already very special formats as GIF or VOICE. Typical conversions: - from FILE to AUDIO/VIDEO/IMAGE - from FILE/IMAGE to GIF */ - let mut better_type = 0; + let mut better_type = Viewtype::Unknown; let mut better_mime = std::ptr::null_mut(); dc_msg_guess_msgtype_from_suffix(pathNfilename, &mut better_type, &mut better_mime); - if 0 != better_type && !better_mime.is_null() { + if Viewtype::Unknown != better_type && !better_mime.is_null() { (*msg).type_0 = better_type; (*msg).param.set(Param::MimeType, as_str(better_mime)); } @@ -436,7 +436,7 @@ unsafe fn prepare_msg_common<'a>( dc_msg_guess_msgtype_from_suffix( pathNfilename, - 0 as *mut libc::c_int, + 0 as *mut Viewtype, &mut better_mime, ); @@ -974,7 +974,7 @@ pub unsafe fn dc_send_text_msg( return 0; } - let mut msg = dc_msg_new(context, 10); + let mut msg = dc_msg_new(context, Viewtype::Text); (*msg).text = dc_strdup(text_to_send); let ret = dc_send_msg(context, chat_id, msg); dc_msg_unref(msg); @@ -1004,7 +1004,7 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t } // save new draft if !msg.is_null() { - if (*msg).type_0 == DC_MSG_TEXT { + if (*msg).type_0 == Viewtype::Text { if (*msg).text.is_null() || *(*msg).text.offset(0isize) as libc::c_int == 0i32 { OK_TO_CONTINUE = false; } @@ -1258,20 +1258,20 @@ pub fn dc_marknoticed_all_chats(context: &Context) -> bool { pub fn dc_get_chat_media( context: &Context, chat_id: uint32_t, - msg_type: libc::c_int, - msg_type2: libc::c_int, - msg_type3: libc::c_int, + msg_type: Viewtype, + msg_type2: Viewtype, + msg_type3: Viewtype, ) -> *mut dc_array_t { context.sql.query_map( "SELECT id FROM msgs WHERE chat_id=? AND (type=? OR type=? OR type=?) ORDER BY timestamp, id;", params![ chat_id as i32, msg_type, - if msg_type2 > 0 { + if msg_type2 != Viewtype::Unknown { msg_type2 } else { msg_type - }, if msg_type3 > 0 { + }, if msg_type3 != Viewtype::Unknown { msg_type3 } else { msg_type @@ -1292,9 +1292,9 @@ pub unsafe fn dc_get_next_media( context: &Context, curr_msg_id: uint32_t, dir: libc::c_int, - msg_type: libc::c_int, - msg_type2: libc::c_int, - msg_type3: libc::c_int, + msg_type: Viewtype, + msg_type2: Viewtype, + msg_type3: Viewtype, ) -> uint32_t { let mut ret_msg_id: uint32_t = 0i32 as uint32_t; let msg: *mut dc_msg_t = dc_msg_new_untyped(context); @@ -1306,7 +1306,7 @@ pub unsafe fn dc_get_next_media( list = dc_get_chat_media( context, (*msg).chat_id, - if msg_type > 0i32 { + if msg_type != Viewtype::Unknown { msg_type } else { (*msg).type_0 @@ -1510,7 +1510,7 @@ pub unsafe fn dc_create_group_chat( chat_id = sql::get_rowid(context, &context.sql, "chats", "grpid", grpid); if chat_id != 0 { if 0 != dc_add_to_chat_contacts_table(context, chat_id, 1) { - let draft_msg = dc_msg_new(context, 10); + let draft_msg = dc_msg_new(context, Viewtype::Text); dc_msg_set_text(draft_msg, draft_txt.as_ptr()); set_draft_raw(context, chat_id, draft_msg); dc_msg_unref(draft_msg); @@ -1619,7 +1619,7 @@ pub unsafe fn dc_add_contact_to_chat_ex( } if OK_TO_CONTINUE { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { - (*msg).type_0 = DC_MSG_TEXT; + (*msg).type_0 = Viewtype::Text; (*msg).text = to_cstring(context.stock_system_msg( StockMessage::MsgAddMember, as_str((*contact).addr), @@ -1730,7 +1730,7 @@ pub unsafe fn dc_remove_contact_from_chat( /* we should respect this - whatever we send to the group, it gets discarded anyway! */ if !contact.is_null() { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { - (*msg).type_0 = DC_MSG_TEXT; + (*msg).type_0 = Viewtype::Text; if (*contact).id == 1 as libc::c_uint { dc_set_group_explicitly_left(context, (*chat).grpid); (*msg).text = to_cstring(context.stock_system_msg( @@ -1845,7 +1845,7 @@ pub unsafe fn dc_set_chat_name( .is_ok() { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { - (*msg).type_0 = DC_MSG_TEXT; + (*msg).type_0 = Viewtype::Text; (*msg).text = to_cstring(context.stock_system_msg( StockMessage::MsgGrpName, as_str((*chat).name), @@ -1917,7 +1917,7 @@ pub unsafe fn dc_set_chat_profile_image( if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { (*msg).param.set_int(Param::Cmd, 3); (*msg).param.set(Param::Arg, as_str(new_image_rel)); - (*msg).type_0 = DC_MSG_TEXT; + (*msg).type_0 = Viewtype::Text; (*msg).text = to_cstring(context.stock_system_msg( if !new_image_rel.is_null() { StockMessage::MsgGrpImgChanged @@ -2287,7 +2287,7 @@ pub fn dc_add_device_msg(context: &Context, chat_id: uint32_t, text: *const libc 2, 2, unsafe {dc_create_smeared_timestamp(context)}, - DC_MSG_TEXT, + Viewtype::Text, DC_STATE_IN_NOTICED, as_str(text), as_str(rfc724_mid), diff --git a/src/dc_imex.rs b/src/dc_imex.rs index 4e2618870..cc6ffaf33 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -139,7 +139,7 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { let chat_id = dc_create_chat_by_contact_id(context, 1i32 as uint32_t); if !(chat_id == 0i32 as libc::c_uint) { msg = dc_msg_new_untyped(context); - (*msg).type_0 = DC_MSG_FILE; + (*msg).type_0 = Viewtype::File; (*msg).param.set(Param::File, as_str(setup_file_name)); (*msg) diff --git a/src/dc_job.rs b/src/dc_job.rs index fe30c4873..78d18f28a 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -1184,8 +1184,8 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in .unwrap_or_default(), ); if strlen(pathNfilename) > 0 { - if ((*mimefactory.msg).type_0 == DC_MSG_IMAGE - || (*mimefactory.msg).type_0 == DC_MSG_GIF) + if ((*mimefactory.msg).type_0 == Viewtype::Image + || (*mimefactory.msg).type_0 == Viewtype::Gif) && !(*mimefactory.msg).param.exists(Param::Width) { let mut buf = 0 as *mut libc::c_uchar; diff --git a/src/dc_location.rs b/src/dc_location.rs index b16e3cb74..14edc3767 100644 --- a/src/dc_location.rs +++ b/src/dc_location.rs @@ -1,6 +1,7 @@ use std::ffi::CString; use crate::constants::Event; +use crate::constants::*; use crate::context::*; use crate::dc_array::*; use crate::dc_chat::*; @@ -98,7 +99,7 @@ pub unsafe fn dc_send_locations_to_chat( .is_ok() { if 0 != seconds && !is_sending_locations_before { - msg = dc_msg_new(context, 10i32); + msg = dc_msg_new(context, Viewtype::Text); (*msg).text = to_cstring(context.stock_system_msg( StockMessage::MsgLocationEnabled, "", @@ -702,7 +703,7 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: *mu // 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, 10); + let mut msg = dc_msg_new(context, Viewtype::Text); (*msg).hidden = 1; (*msg).param.set_int(Param::Cmd, 9); dc_send_msg(context, chat_id as u32, msg); diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index a3cccb129..22214b125 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -738,10 +738,9 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: } } } - if let Some(grpimage) = grpimage { let mut meta = dc_msg_new_untyped((*factory).context); - (*meta).type_0 = DC_MSG_IMAGE as libc::c_int; + (*meta).type_0 = Viewtype::Image; (*meta).param.set(Param::File, grpimage); let mut filename_as_sent = 0 as *mut libc::c_char; @@ -762,11 +761,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: dc_msg_unref(meta); } - if (*msg).type_0 == DC_MSG_VOICE - || (*msg).type_0 == DC_MSG_AUDIO - || (*msg).type_0 == DC_MSG_VIDEO + if (*msg).type_0 == Viewtype::Voice + || (*msg).type_0 == Viewtype::Audio + || (*msg).type_0 == Viewtype::Video { - if (*msg).type_0 == DC_MSG_VOICE { + if (*msg).type_0 == Viewtype::Voice { mailimf_fields_add( imf_fields, mailimf_field_new_custom( @@ -1179,7 +1178,7 @@ unsafe fn build_body_file( let mut filename_encoded = 0 as *mut libc::c_char; if !pathNfilename.is_null() { - if (*msg).type_0 == DC_MSG_VOICE { + if (*msg).type_0 == Viewtype::Voice { let ts = chrono::Utc.timestamp((*msg).timestamp_sort as i64, 0); let suffix = if !suffix.is_null() { @@ -1191,9 +1190,9 @@ unsafe fn build_body_file( .format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix)) .to_string(); filename_to_send = to_cstring(res); - } else if (*msg).type_0 == DC_MSG_AUDIO { + } else if (*msg).type_0 == Viewtype::Audio { filename_to_send = dc_get_filename(pathNfilename) - } else if (*msg).type_0 == DC_MSG_IMAGE || (*msg).type_0 == DC_MSG_GIF { + } else if (*msg).type_0 == Viewtype::Image || (*msg).type_0 == Viewtype::Gif { if base_name.is_null() { base_name = b"image\x00" as *const u8 as *const libc::c_char } @@ -1206,7 +1205,7 @@ unsafe fn build_body_file( b"dat\x00" as *const u8 as *const libc::c_char }, ) - } else if (*msg).type_0 == DC_MSG_VIDEO { + } else if (*msg).type_0 == Viewtype::Video { filename_to_send = dc_mprintf( b"video.%s\x00" as *const u8 as *const libc::c_char, if !suffix.is_null() { diff --git a/src/dc_msg.rs b/src/dc_msg.rs index df4ed8bfe..150d389ef 100644 --- a/src/dc_msg.rs +++ b/src/dc_msg.rs @@ -25,7 +25,7 @@ pub struct dc_msg_t<'a> { pub to_id: uint32_t, pub chat_id: uint32_t, pub move_state: dc_move_state_t, - pub type_0: libc::c_int, + pub type_0: Viewtype, pub state: libc::c_int, pub hidden: libc::c_int, pub timestamp_sort: i64, @@ -177,15 +177,15 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch } free(p as *mut libc::c_void); - if (*msg).type_0 != DC_MSG_TEXT { + if (*msg).type_0 != Viewtype::Text { ret += "Type: "; match (*msg).type_0 { - DC_MSG_AUDIO => ret += "Audio", - DC_MSG_FILE => ret += "File", - DC_MSG_GIF => ret += "GIF", - DC_MSG_IMAGE => ret += "Image", - DC_MSG_VIDEO => ret += "Video", - DC_MSG_VOICE => ret += "Voice", + Viewtype::Audio => ret += "Audio", + Viewtype::File => ret += "File", + Viewtype::Gif => ret += "GIF", + Viewtype::Image => ret += "Image", + Viewtype::Video => ret += "Video", + Viewtype::Voice => ret += "Voice", _ => ret += &format!("{}", (*msg).type_0), } ret += "\n"; @@ -222,7 +222,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch } pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a> { - dc_msg_new(context, 0i32) + dc_msg_new(context, Viewtype::Unknown) } /* * @@ -235,7 +235,7 @@ pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a> // to check if a mail was sent, use dc_msg_is_sent() // approx. max. length returned by dc_msg_get_text() // approx. max. length returned by dc_get_msg_info() -pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: libc::c_int) -> *mut dc_msg_t<'a> { +pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut dc_msg_t<'a> { let msg = dc_msg_t { magic: 0x11561156, id: 0, @@ -301,7 +301,7 @@ pub unsafe fn dc_msg_get_filemime(msg: *const dc_msg_t) -> *mut libc::c_char { None => { if let Some(file) = (*msg).param.get(Param::File) { let file_c = to_cstring(file); - dc_msg_guess_msgtype_from_suffix(file_c, 0 as *mut libc::c_int, &mut ret); + dc_msg_guess_msgtype_from_suffix(file_c, 0 as *mut Viewtype, &mut ret); if ret.is_null() { ret = dc_strdup( b"application/octet-stream\x00" as *const u8 as *const libc::c_char, @@ -323,11 +323,11 @@ pub unsafe fn dc_msg_get_filemime(msg: *const dc_msg_t) -> *mut libc::c_char { #[allow(non_snake_case)] pub unsafe fn dc_msg_guess_msgtype_from_suffix( pathNfilename: *const libc::c_char, - mut ret_msgtype: *mut libc::c_int, + mut ret_msgtype: *mut Viewtype, mut ret_mime: *mut *mut libc::c_char, ) { let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char; - let mut dummy_msgtype: libc::c_int = 0; + let mut dummy_msgtype = Viewtype::Unknown; let mut dummy_buf: *mut libc::c_char = 0 as *mut libc::c_char; if !pathNfilename.is_null() { if ret_msgtype.is_null() { @@ -336,37 +336,37 @@ pub unsafe fn dc_msg_guess_msgtype_from_suffix( if ret_mime.is_null() { ret_mime = &mut dummy_buf } - *ret_msgtype = 0; + *ret_msgtype = Viewtype::Unknown; *ret_mime = 0 as *mut libc::c_char; suffix = dc_get_filesuffix_lc(pathNfilename); if !suffix.is_null() { if strcmp(suffix, b"mp3\x00" as *const u8 as *const libc::c_char) == 0i32 { - *ret_msgtype = DC_MSG_AUDIO; + *ret_msgtype = Viewtype::Audio; *ret_mime = dc_strdup(b"audio/mpeg\x00" as *const u8 as *const libc::c_char) } else if strcmp(suffix, b"aac\x00" as *const u8 as *const libc::c_char) == 0i32 { - *ret_msgtype = DC_MSG_AUDIO; + *ret_msgtype = Viewtype::Audio; *ret_mime = dc_strdup(b"audio/aac\x00" as *const u8 as *const libc::c_char) } else if strcmp(suffix, b"mp4\x00" as *const u8 as *const libc::c_char) == 0i32 { - *ret_msgtype = DC_MSG_VIDEO; + *ret_msgtype = Viewtype::Video; *ret_mime = dc_strdup(b"video/mp4\x00" as *const u8 as *const libc::c_char) } else if strcmp(suffix, b"jpg\x00" as *const u8 as *const libc::c_char) == 0i32 || strcmp(suffix, b"jpeg\x00" as *const u8 as *const libc::c_char) == 0i32 { - *ret_msgtype = DC_MSG_IMAGE; + *ret_msgtype = Viewtype::Image; *ret_mime = dc_strdup(b"image/jpeg\x00" as *const u8 as *const libc::c_char) } else if strcmp(suffix, b"png\x00" as *const u8 as *const libc::c_char) == 0i32 { - *ret_msgtype = DC_MSG_IMAGE; + *ret_msgtype = Viewtype::Image; *ret_mime = dc_strdup(b"image/png\x00" as *const u8 as *const libc::c_char) } else if strcmp(suffix, b"webp\x00" as *const u8 as *const libc::c_char) == 0i32 { - *ret_msgtype = DC_MSG_IMAGE; + *ret_msgtype = Viewtype::Image; *ret_mime = dc_strdup(b"image/webp\x00" as *const u8 as *const libc::c_char) } else if strcmp(suffix, b"gif\x00" as *const u8 as *const libc::c_char) == 0i32 { - *ret_msgtype = DC_MSG_GIF; + *ret_msgtype = Viewtype::Gif; *ret_mime = dc_strdup(b"image/gif\x00" as *const u8 as *const libc::c_char) } else if strcmp(suffix, b"vcf\x00" as *const u8 as *const libc::c_char) == 0i32 || strcmp(suffix, b"vcard\x00" as *const u8 as *const libc::c_char) == 0i32 { - *ret_msgtype = DC_MSG_FILE; + *ret_msgtype = Viewtype::File; *ret_mime = dc_strdup(b"text/vcard\x00" as *const u8 as *const libc::c_char) } } @@ -681,9 +681,9 @@ pub unsafe fn dc_msg_get_chat_id(msg: *const dc_msg_t) -> uint32_t { }; } -pub unsafe fn dc_msg_get_viewtype(msg: *const dc_msg_t) -> libc::c_int { +pub unsafe fn dc_msg_get_viewtype(msg: *const dc_msg_t) -> Viewtype { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { - return 0i32; + return Viewtype::Unknown; } (*msg).type_0 @@ -853,7 +853,7 @@ pub unsafe fn dc_msg_get_summarytext( /* the returned value must be free()'d */ #[allow(non_snake_case)] pub unsafe fn dc_msg_get_summarytext_by_raw( - type_0: libc::c_int, + type_0: Viewtype, text: *const libc::c_char, param: &mut Params, approx_characters: libc::c_int, @@ -866,11 +866,11 @@ pub unsafe fn dc_msg_get_summarytext_by_raw( let mut value: *mut libc::c_char = 0 as *mut libc::c_char; let mut append_text: libc::c_int = 1i32; match type_0 { - 20 => prefix = to_cstring(context.stock_str(StockMessage::Image)), - 21 => prefix = to_cstring(context.stock_str(StockMessage::Gif)), - 50 => prefix = to_cstring(context.stock_str(StockMessage::Video)), - 41 => prefix = to_cstring(context.stock_str(StockMessage::VoiceMessage)), - 40 | 60 => { + Viewtype::Image => prefix = to_cstring(context.stock_str(StockMessage::Image)), + Viewtype::Gif => prefix = to_cstring(context.stock_str(StockMessage::Gif)), + Viewtype::Video => prefix = to_cstring(context.stock_str(StockMessage::Video)), + Viewtype::Voice => prefix = to_cstring(context.stock_str(StockMessage::VoiceMessage)), + Viewtype::Audio | Viewtype::File => { if param.get_int(Param::Cmd) == Some(6) { prefix = to_cstring(context.stock_str(StockMessage::AcSetupMsgSubject)); append_text = 0i32 @@ -879,7 +879,7 @@ pub unsafe fn dc_msg_get_summarytext_by_raw( value = dc_get_filename(pathNfilename); let label = CString::new( context - .stock_str(if type_0 == DC_MSG_AUDIO { + .stock_str(if type_0 == Viewtype::Audio { StockMessage::Audio } else { StockMessage::File @@ -1000,7 +1000,7 @@ pub unsafe fn dc_msg_is_increation(msg: *const dc_msg_t) -> libc::c_int { pub unsafe fn dc_msg_is_setupmessage(msg: *const dc_msg_t) -> bool { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint - || (*msg).type_0 != DC_MSG_FILE as libc::c_int + || (*msg).type_0 != Viewtype::File { return false; } @@ -1442,7 +1442,7 @@ mod tests { #[test] fn test_dc_msg_guess_msgtype_from_suffix() { unsafe { - let mut type_0: libc::c_int = 0; + let mut type_0 = Viewtype::Unknown; let mut mime_0: *mut libc::c_char = 0 as *mut libc::c_char; dc_msg_guess_msgtype_from_suffix( @@ -1450,7 +1450,7 @@ mod tests { &mut type_0, &mut mime_0, ); - assert_eq!(type_0, DC_MSG_AUDIO as libc::c_int); + assert_eq!(type_0, Viewtype::Audio); assert_eq!(as_str(mime_0 as *const libc::c_char), "audio/mpeg"); free(mime_0 as *mut libc::c_void); @@ -1459,7 +1459,7 @@ mod tests { &mut type_0, &mut mime_0, ); - assert_eq!(type_0, DC_MSG_AUDIO as libc::c_int); + assert_eq!(type_0, Viewtype::Audio); assert_eq!(as_str(mime_0 as *const libc::c_char), "audio/aac"); free(mime_0 as *mut libc::c_void); @@ -1468,7 +1468,7 @@ mod tests { &mut type_0, &mut mime_0, ); - assert_eq!(type_0, DC_MSG_VIDEO as libc::c_int); + assert_eq!(type_0, Viewtype::Video); assert_eq!(as_str(mime_0 as *const libc::c_char), "video/mp4"); free(mime_0 as *mut libc::c_void); @@ -1477,7 +1477,7 @@ mod tests { &mut type_0, &mut mime_0, ); - assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int); + assert_eq!(type_0, Viewtype::Image); assert_eq!( CStr::from_ptr(mime_0 as *const libc::c_char) .to_str() @@ -1491,7 +1491,7 @@ mod tests { &mut type_0, &mut mime_0, ); - assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int); + assert_eq!(type_0, Viewtype::Image); assert_eq!( CStr::from_ptr(mime_0 as *const libc::c_char) .to_str() @@ -1505,7 +1505,7 @@ mod tests { &mut type_0, &mut mime_0, ); - assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int); + assert_eq!(type_0, Viewtype::Image); assert_eq!( CStr::from_ptr(mime_0 as *const libc::c_char) .to_str() @@ -1519,7 +1519,7 @@ mod tests { &mut type_0, &mut mime_0, ); - assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int); + assert_eq!(type_0, Viewtype::Image); assert_eq!( CStr::from_ptr(mime_0 as *const libc::c_char) .to_str() @@ -1533,7 +1533,7 @@ mod tests { &mut type_0, &mut mime_0, ); - assert_eq!(type_0, DC_MSG_GIF as libc::c_int); + assert_eq!(type_0, Viewtype::Gif); assert_eq!( CStr::from_ptr(mime_0 as *const libc::c_char) .to_str() @@ -1547,7 +1547,7 @@ mod tests { &mut type_0, &mut mime_0, ); - assert_eq!(type_0, DC_MSG_FILE as libc::c_int); + assert_eq!(type_0, Viewtype::File); assert_eq!( CStr::from_ptr(mime_0 as *const libc::c_char) .to_str() diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index 3bf1f305b..d1910212d 100644 --- a/src/dc_securejoin.rs +++ b/src/dc_securejoin.rs @@ -263,7 +263,7 @@ unsafe fn send_handshake_msg( grpid: *const libc::c_char, ) { let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context); - (*msg).type_0 = DC_MSG_TEXT; + (*msg).type_0 = Viewtype::Text; (*msg).text = dc_mprintf( b"Secure-Join: %s\x00" as *const u8 as *const libc::c_char, step, From 3358d09148d2972dc3e9467757c150d3897c8de7 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Tue, 30 Jul 2019 08:52:43 +0000 Subject: [PATCH 29/95] Derive and use Display trait for Viewtype --- src/constants.rs | 24 +++++++++++------------- src/dc_msg.rs | 10 +--------- src/lib.rs | 3 +++ 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index e72019174..e055dc73d 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -3,7 +3,6 @@ use num_traits::{FromPrimitive, ToPrimitive}; use rusqlite as sql; use rusqlite::types::*; -use std::fmt; pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00"; @@ -147,7 +146,7 @@ pub const DC_LP_IMAP_SOCKET_FLAGS: usize = pub const DC_LP_SMTP_SOCKET_FLAGS: usize = (DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN); -#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] +#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] #[repr(i32)] pub enum Viewtype { Unknown = 0, @@ -192,6 +191,16 @@ pub enum Viewtype { File = 60, } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn derive_display_works_as_expected() { + assert_eq!(format!("{}", Viewtype::Audio), "Audio"); + } +} + impl ToSql for Viewtype { fn to_sql(&self) -> sql::Result { let num: i64 = self @@ -209,17 +218,6 @@ impl FromSql for Viewtype { } } -impl fmt::Display for Viewtype { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - self.to_i64() - .expect("impossible: Viewtype -> i64 conversion failed") - ) - } -} - // These constants are used as events // reported to the callback given to dc_context_new(). // If you do not want to handle an event, it is always safe to return 0, diff --git a/src/dc_msg.rs b/src/dc_msg.rs index 150d389ef..66e404680 100644 --- a/src/dc_msg.rs +++ b/src/dc_msg.rs @@ -179,15 +179,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch if (*msg).type_0 != Viewtype::Text { ret += "Type: "; - match (*msg).type_0 { - Viewtype::Audio => ret += "Audio", - Viewtype::File => ret += "File", - Viewtype::Gif => ret += "GIF", - Viewtype::Image => ret += "Image", - Viewtype::Video => ret += "Video", - Viewtype::Voice => ret += "Voice", - _ => ret += &format!("{}", (*msg).type_0), - } + ret += &format!("{}", (*msg).type_0); ret += "\n"; p = dc_msg_get_filemime(msg); ret += &format!("Mimetype: {}\n", as_str(p)); diff --git a/src/lib.rs b/src/lib.rs index bf361ae0d..f735de035 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,9 @@ extern crate num_derive; extern crate smallvec; #[macro_use] extern crate rusqlite; +extern crate strum; +#[macro_use] +extern crate strum_macros; #[macro_use] mod log; From 1f9807ccfe9e0f61f0ea9f800e16c0493fa7a48c Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Thu, 1 Aug 2019 06:23:37 +0000 Subject: [PATCH 30/95] Refine type of Context.probe_network to bool --- src/context.rs | 4 ++-- src/dc_job.rs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/context.rs b/src/context.rs index 0a985447c..cf39e5387 100644 --- a/src/context.rs +++ b/src/context.rs @@ -28,7 +28,7 @@ pub struct Context { pub sql: Sql, pub inbox: Arc>, pub perform_inbox_jobs_needed: Arc>, - pub probe_imap_network: Arc>, + pub probe_imap_network: Arc>, pub sentbox_thread: Arc>, pub mvbox_thread: Arc>, pub smtp: Arc>, @@ -160,7 +160,7 @@ pub fn dc_context_new( cb_receive_imf, ), ))), - probe_imap_network: Arc::new(RwLock::new(0)), + probe_imap_network: Arc::new(RwLock::new(false)), perform_inbox_jobs_needed: Arc::new(RwLock::new(0)), } } diff --git a/src/dc_job.rs b/src/dc_job.rs index fe30c4873..e483c2ed5 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -54,15 +54,15 @@ pub unsafe fn dc_perform_imap_jobs(context: &Context) { info!(context, 0, "dc_perform_imap_jobs starting.",); let probe_imap_network = *context.probe_imap_network.clone().read().unwrap(); - *context.probe_imap_network.write().unwrap() = 0; + *context.probe_imap_network.write().unwrap() = false; *context.perform_inbox_jobs_needed.write().unwrap() = 0; dc_job_perform(context, DC_IMAP_THREAD, probe_imap_network); info!(context, 0, "dc_perform_imap_jobs ended.",); } -unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: libc::c_int) { - let query = if probe_network == 0 { +unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: bool) { + let query = if !probe_network { // processing for first-try and after backoff-timeouts: // process jobs in the order they were added. "SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \ @@ -77,7 +77,7 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: let params_no_probe = params![thread as i64, time()]; let params_probe = params![thread as i64]; - let params: &[&dyn rusqlite::ToSql] = if probe_network == 0 { + let params: &[&dyn rusqlite::ToSql] = if !probe_network { params_no_probe } else { params_probe @@ -225,7 +225,7 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: } dc_job_delete(context, &mut job); } - if 0 == probe_network { + if !probe_network { continue; } // on dc_maybe_network() we stop trying here; @@ -1050,7 +1050,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) { return; } state.doing_jobs = 1; - probe_smtp_network + probe_smtp_network != 0 }; info!(context, 0, "SMTP-jobs started...",); @@ -1125,7 +1125,7 @@ pub unsafe fn dc_maybe_network(context: &Context) { let mut state = lock.lock().unwrap(); state.probe_network = 1; - *context.probe_imap_network.write().unwrap() = 1; + *context.probe_imap_network.write().unwrap() = true; } dc_interrupt_smtp_idle(context); From 07d7316a9f07872343828ffef397b1f85fea0da1 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Thu, 1 Aug 2019 06:31:58 +0000 Subject: [PATCH 31/95] Refine type of Context.perform_inbox_jobs_needed to bool --- src/context.rs | 4 ++-- src/dc_job.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/context.rs b/src/context.rs index cf39e5387..3124727f7 100644 --- a/src/context.rs +++ b/src/context.rs @@ -27,7 +27,7 @@ pub struct Context { pub blobdir: Arc>, pub sql: Sql, pub inbox: Arc>, - pub perform_inbox_jobs_needed: Arc>, + pub perform_inbox_jobs_needed: Arc>, pub probe_imap_network: Arc>, pub sentbox_thread: Arc>, pub mvbox_thread: Arc>, @@ -161,7 +161,7 @@ pub fn dc_context_new( ), ))), probe_imap_network: Arc::new(RwLock::new(false)), - perform_inbox_jobs_needed: Arc::new(RwLock::new(0)), + perform_inbox_jobs_needed: Arc::new(RwLock::new(false)), } } diff --git a/src/dc_job.rs b/src/dc_job.rs index e483c2ed5..66eac5d9d 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -55,7 +55,7 @@ pub unsafe fn dc_perform_imap_jobs(context: &Context) { 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() = 0; + *context.perform_inbox_jobs_needed.write().unwrap() = false; dc_job_perform(context, DC_IMAP_THREAD, probe_imap_network); info!(context, 0, "dc_perform_imap_jobs ended.",); @@ -859,7 +859,7 @@ pub unsafe fn dc_interrupt_smtp_idle(context: &Context) { pub unsafe fn dc_interrupt_imap_idle(context: &Context) { info!(context, 0, "Interrupting IMAP-IDLE...",); - *context.perform_inbox_jobs_needed.write().unwrap() = 1; + *context.perform_inbox_jobs_needed.write().unwrap() = true; context.inbox.read().unwrap().interrupt_idle(); } @@ -967,7 +967,7 @@ pub fn dc_perform_imap_idle(context: &Context) { connect_to_inbox(context, &inbox); - if 0 != *context.perform_inbox_jobs_needed.clone().read().unwrap() { + if *context.perform_inbox_jobs_needed.clone().read().unwrap() { info!( context, 0, "INBOX-IDLE will not be started because of waiting jobs." From b2807429cc698668cf16b0216fedf3e20394d0fa Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Thu, 1 Aug 2019 06:37:06 +0000 Subject: [PATCH 32/95] Refine type of SmtpState.probe_network to bool --- src/context.rs | 2 +- src/dc_job.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/context.rs b/src/context.rs index 3124727f7..11b344f72 100644 --- a/src/context.rs +++ b/src/context.rs @@ -109,7 +109,7 @@ pub struct SmtpState { pub suspended: i32, pub doing_jobs: i32, pub perform_jobs_needed: i32, - pub probe_network: i32, + pub probe_network: bool, } // create/open/config/information diff --git a/src/dc_job.rs b/src/dc_job.rs index 66eac5d9d..20f6edda0 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -1042,7 +1042,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) { let mut state = lock.lock().unwrap(); let probe_smtp_network = state.probe_network; - state.probe_network = 0; + state.probe_network = false; state.perform_jobs_needed = 0; if 0 != state.suspended { @@ -1050,7 +1050,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) { return; } state.doing_jobs = 1; - probe_smtp_network != 0 + probe_smtp_network }; info!(context, 0, "SMTP-jobs started...",); @@ -1123,7 +1123,7 @@ pub unsafe fn dc_maybe_network(context: &Context) { { let &(ref lock, _) = &*context.smtp_state.clone(); let mut state = lock.lock().unwrap(); - state.probe_network = 1; + state.probe_network = true; *context.probe_imap_network.write().unwrap() = true; } From 8eb5cec9ceafbb977399fca91526fa5c4d983597 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Thu, 1 Aug 2019 06:41:50 +0000 Subject: [PATCH 33/95] Refine type of SmtpState.suspended to bool --- src/context.rs | 2 +- src/dc_job.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/context.rs b/src/context.rs index 11b344f72..1a296627c 100644 --- a/src/context.rs +++ b/src/context.rs @@ -106,7 +106,7 @@ impl Default for BobStatus { #[derive(Default, Debug)] pub struct SmtpState { pub idle: bool, - pub suspended: i32, + pub suspended: bool, pub doing_jobs: i32, pub perform_jobs_needed: i32, pub probe_network: bool, diff --git a/src/dc_job.rs b/src/dc_job.rs index 20f6edda0..f1f9bfa8b 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -136,7 +136,7 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: dc_job_kill_action(context, job.action); dc_jobthread_suspend(context, &context.sentbox_thread.clone().read().unwrap(), 1); dc_jobthread_suspend(context, &context.mvbox_thread.clone().read().unwrap(), 1); - dc_suspend_smtp_thread(context, 1); + dc_suspend_smtp_thread(context, true); } let mut tries = 0; @@ -174,7 +174,7 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: &mut context.mvbox_thread.clone().read().unwrap(), 0, ); - dc_suspend_smtp_thread(context, 0); + dc_suspend_smtp_thread(context, false); break; } else if job.try_again == 2 { // just try over next loop unconditionally, the ui typically interrupts idle when the file (video) is ready @@ -279,9 +279,9 @@ fn dc_job_update(context: &Context, job: &dc_job_t) -> bool { .is_ok() } -unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: libc::c_int) { +unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: bool) { context.smtp_state.0.lock().unwrap().suspended = suspend; - if 0 != suspend { + if suspend { loop { if context.smtp_state.0.lock().unwrap().doing_jobs == 0 { return; @@ -1045,7 +1045,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) { state.probe_network = false; state.perform_jobs_needed = 0; - if 0 != state.suspended { + if state.suspended { info!(context, 0, "SMTP-jobs suspended.",); return; } From 7394666266b89036aefde0047136510993c0a79c Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Thu, 1 Aug 2019 06:51:52 +0000 Subject: [PATCH 34/95] Refine type of SmtpState.doing_jobs to bool --- src/context.rs | 2 +- src/dc_job.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/context.rs b/src/context.rs index 1a296627c..46613ffe9 100644 --- a/src/context.rs +++ b/src/context.rs @@ -107,7 +107,7 @@ impl Default for BobStatus { pub struct SmtpState { pub idle: bool, pub suspended: bool, - pub doing_jobs: i32, + pub doing_jobs: bool, pub perform_jobs_needed: i32, pub probe_network: bool, } diff --git a/src/dc_job.rs b/src/dc_job.rs index f1f9bfa8b..07080d2a4 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -283,7 +283,7 @@ unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: bool) { context.smtp_state.0.lock().unwrap().suspended = suspend; if suspend { loop { - if context.smtp_state.0.lock().unwrap().doing_jobs == 0 { + if !context.smtp_state.0.lock().unwrap().doing_jobs { return; } std::thread::sleep(std::time::Duration::from_micros(300 * 1000)); @@ -1049,7 +1049,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) { info!(context, 0, "SMTP-jobs suspended.",); return; } - state.doing_jobs = 1; + state.doing_jobs = true; probe_smtp_network }; @@ -1061,7 +1061,7 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) { let &(ref lock, _) = &*context.smtp_state.clone(); let mut state = lock.lock().unwrap(); - state.doing_jobs = 0; + state.doing_jobs = false; } } From b6b0849bce4cc3212085a326ef2c4f3aed122111 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Thu, 1 Aug 2019 00:08:23 +0200 Subject: [PATCH 35/95] Remove to_cstring() naming convention ambiguity Add a trait for str.strdup() to replace to_cstring() which avoid the signature ambiguity with .to_string(). Also instruduce CString::yolo() as a shortcut to CString::new().unwrap() and use it whenever the variable does can be deallocated by going out of scope. This is less error prone. Use some Path.to_c_string() functions where possible. --- deltachat-ffi/src/lib.rs | 8 +-- examples/repl/cmdline.rs | 17 ++--- examples/repl/main.rs | 2 +- src/chatlist.rs | 6 +- src/config.rs | 8 +-- src/context.rs | 2 +- src/dc_array.rs | 4 +- src/dc_chat.rs | 144 +++++++++++++++++++++------------------ src/dc_configure.rs | 10 +-- src/dc_contact.rs | 25 ++++--- src/dc_dehtml.rs | 2 +- src/dc_e2ee.rs | 18 ++--- src/dc_imex.rs | 67 +++++++++--------- src/dc_job.rs | 13 ++-- src/dc_location.rs | 13 ++-- src/dc_lot.rs | 4 +- src/dc_mimefactory.rs | 110 +++++++++++++++--------------- src/dc_mimeparser.rs | 5 +- src/dc_msg.rs | 63 ++++++++--------- src/dc_qr.rs | 14 ++-- src/dc_receive_imf.rs | 18 ++--- src/dc_securejoin.rs | 4 +- src/dc_simplify.rs | 2 +- src/dc_strencode.rs | 7 +- src/dc_token.rs | 2 +- src/dc_tools.rs | 95 ++++++++++++++++++++++---- src/imap.rs | 10 ++- src/log.rs | 20 +++--- src/peerstate.rs | 28 +------- src/sql.rs | 6 +- tests/stress.rs | 49 ++++++------- 31 files changed, 395 insertions(+), 381 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 045053044..920a97a38 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -15,6 +15,7 @@ use num_traits::{FromPrimitive, ToPrimitive}; use std::ptr; use std::str::FromStr; +use deltachat::dc_tools::StrExt; use deltachat::*; // TODO: constants @@ -126,10 +127,7 @@ pub unsafe extern "C" fn dc_get_config( let context = &*context; match config::Config::from_str(dc_tools::as_str(key)) { - Ok(key) => { - let value = context.get_config(key).unwrap_or_default(); - dc_tools::to_cstring(value) - } + Ok(key) => context.get_config(key).unwrap_or_default().strdup(), Err(_) => std::ptr::null_mut(), } } @@ -154,7 +152,7 @@ pub unsafe extern "C" fn dc_get_oauth2_url( let addr = dc_tools::to_string(addr); let redirect = dc_tools::to_string(redirect); match oauth2::dc_get_oauth2_url(context, addr, redirect) { - Some(res) => dc_tools::to_cstring(res), + Some(res) => res.strdup(), None => std::ptr::null_mut(), } } diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index f6bcb083d..2ed21522a 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -147,7 +147,7 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int } else { current_block = 7149356873433890176; } - real_spec = to_cstring(rs.unwrap_or_default()); + real_spec = rs.unwrap_or_default().strdup(); } match current_block { 8522321847195001863 => {} @@ -184,11 +184,10 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int if name.ends_with(".eml") { let path_plus_name = format!("{}/{}", as_str(real_spec), name); info!(context, 0, "Import: {}", path_plus_name); - let path_plus_name_c = to_cstring(path_plus_name); - if 0 != dc_poke_eml_file(context, path_plus_name_c) { + 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 } - free(path_plus_name_c as *mut _); } } current_block = 1622411330066726685; @@ -386,13 +385,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E let arg1_c = if arg1.is_empty() { std::ptr::null() } else { - to_cstring(arg1) as *const _ + arg1.strdup() as *const _ }; let arg2 = args.next().unwrap_or_default(); let arg2_c = if arg2.is_empty() { std::ptr::null() } else { - to_cstring(arg2) as *const _ + arg2.strdup() as *const _ }; match arg0 { @@ -928,13 +927,11 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E ensure!(!sel_chat.is_null(), "No chat selected."); ensure!(!arg1.is_empty(), "No message text given."); - let msg = to_cstring(format!("{} {}", arg1, arg2)); + let msg = CString::yolo(format!("{} {}", arg1, arg2)); - if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg) { + if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg.as_ptr()) { println!("Message sent."); - free(msg as *mut _); } else { - free(msg as *mut _); bail!("Sending failed."); } } diff --git a/examples/repl/main.rs b/examples/repl/main.rs index da7b28cab..b023c801e 100644 --- a/examples/repl/main.rs +++ b/examples/repl/main.rs @@ -481,7 +481,7 @@ unsafe fn handle_cmd(line: &str, ctx: Arc>) -> Result Chatlist<'a> { let mut ret = dc_lot_new(); if index >= self.ids.len() { - (*ret).text2 = to_cstring("ErrBadChatlistIndex"); + (*ret).text2 = "ErrBadChatlistIndex".strdup(); return ret; } @@ -267,7 +267,7 @@ impl<'a> Chatlist<'a> { chat = dc_chat_new(self.context); let chat_to_delete = chat; if !dc_chat_load_from_db(chat, self.ids[index].0) { - (*ret).text2 = to_cstring("ErrCannotReadChat"); + (*ret).text2 = "ErrCannotReadChat".strdup(); dc_chat_unref(chat_to_delete); return ret; @@ -293,7 +293,7 @@ impl<'a> Chatlist<'a> { if (*chat).id == DC_CHAT_ID_ARCHIVED_LINK as u32 { (*ret).text2 = dc_strdup(0 as *const libc::c_char) } else if lastmsg.is_null() || (*lastmsg).from_id == DC_CONTACT_ID_SELF as u32 { - (*ret).text2 = to_cstring(self.context.stock_str(StockMessage::NoMessages)); + (*ret).text2 = self.context.stock_str(StockMessage::NoMessages).strdup(); } else { dc_lot_fill(ret, lastmsg, chat, lastcontact, self.context); } diff --git a/src/config.rs b/src/config.rs index ff7aa0905..f4be262b3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,5 @@ +use std::ffi::CString; + use strum::{EnumProperty, IntoEnumIterator}; use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString}; @@ -72,10 +74,8 @@ impl Context { let rel_path = self.sql.get_config(self, key); rel_path.map(|p| { let v = unsafe { - let n = to_cstring(p); - let res = dc_get_abs_path(self, n); - free(n as *mut libc::c_void); - res + let n = CString::yolo(p); + dc_get_abs_path(self, n.as_ptr()) }; let r = to_string(v); unsafe { free(v as *mut _) }; diff --git a/src/context.rs b/src/context.rs index 46613ffe9..ba12edc21 100644 --- a/src/context.rs +++ b/src/context.rs @@ -483,7 +483,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char { fingerprint_str, ); - to_cstring(res) + res.strdup() } pub unsafe fn dc_get_version_str() -> *mut libc::c_char { diff --git a/src/dc_array.rs b/src/dc_array.rs index 5e0fb97fa..224ef9cc8 100644 --- a/src/dc_array.rs +++ b/src/dc_array.rs @@ -271,7 +271,7 @@ pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *m if let dc_array_t::Locations(v) = &*array { if let Some(s) = &v[index].marker { - to_cstring(s) + s.strdup() } else { std::ptr::null_mut() } @@ -375,7 +375,7 @@ pub unsafe fn dc_array_get_string( res + sep + &n.to_string() } }); - to_cstring(res) + res.strdup() } else { panic!("Attempt to get string from array of other type"); } diff --git a/src/dc_chat.rs b/src/dc_chat.rs index 03ebd1c03..23b5956dd 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -137,14 +137,8 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool { c.id = row.get(0)?; c.type_0 = row.get(1)?; - c.name = { - let raw: String = row.get(2)?; - unsafe { to_cstring(raw) } - }; - c.grpid = { - let raw: String = row.get(3)?; - unsafe { to_cstring(raw) } - }; + c.name = unsafe { row.get::<_, String>(2)?.strdup() }; + c.grpid = unsafe { row.get::<_, String>(3)?.strdup() }; c.param = row.get::<_, String>(4)?.parse().unwrap_or_default(); c.archived = row.get(5)?; @@ -172,24 +166,27 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool { match c.id { 1 => unsafe { free((*chat).name as *mut libc::c_void); - (*chat).name = to_cstring((*chat).context.stock_str(StockMessage::DeadDrop)); + (*chat).name = (*chat).context.stock_str(StockMessage::DeadDrop).strdup(); }, 6 => unsafe { free((*chat).name as *mut libc::c_void); let tempname = (*chat).context.stock_str(StockMessage::ArchivedChats); let cnt = dc_get_archived_cnt((*chat).context); - (*chat).name = to_cstring(format!("{} ({})", tempname, cnt)); + (*chat).name = format!("{} ({})", tempname, cnt).strdup(); }, 5 => unsafe { free((*chat).name as *mut libc::c_void); - (*chat).name = to_cstring((*chat).context.stock_str(StockMessage::StarredMsgs)); + (*chat).name = (*chat) + .context + .stock_str(StockMessage::StarredMsgs) + .strdup(); }, _ => { if unsafe { &(*chat).param }.exists(Param::Selftalk) { unsafe { free((*chat).name as *mut libc::c_void); (*chat).name = - to_cstring((*chat).context.stock_str(StockMessage::SelfMsg)); + (*chat).context.stock_str(StockMessage::SelfMsg).strdup(); } } } @@ -398,7 +395,7 @@ unsafe fn prepare_msg_common<'a>( let mut pathNfilename = (*msg) .param .get(Param::File) - .map(|s| to_cstring(s)) + .map(|s| s.strdup()) .unwrap_or_else(|| std::ptr::null_mut()); if pathNfilename.is_null() { error!( @@ -516,16 +513,15 @@ unsafe fn prepare_msg_raw( if from.is_none() { error!(context, 0, "Cannot send message, not configured.",); } else { - let from_c = to_cstring(from.unwrap()); + let from_c = CString::yolo(from.unwrap()); new_rfc724_mid = dc_create_outgoing_rfc724_mid( if (*chat).type_0 == 120 || (*chat).type_0 == 130 { (*chat).grpid } else { 0 as *mut libc::c_char }, - from_c, + from_c.as_ptr(), ); - free(from_c as *mut _); if (*chat).type_0 == DC_CHAT_TYPE_SINGLE { if let Some(id) = context.sql.query_row_col( @@ -789,9 +785,9 @@ unsafe fn get_parent_mime_headers( FROM msgs WHERE chat_id=? AND from_id!=?);", params![(*chat).id as i32, 1], |row| { - *parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?); - *parent_in_reply_to = to_cstring(row.get::<_, String>(1)?); - *parent_references = to_cstring(row.get::<_, String>(2)?); + *parent_rfc724_mid = row.get::<_, String>(0)?.strdup(); + *parent_in_reply_to = row.get::<_, String>(1)?.strdup(); + *parent_references = row.get::<_, String>(2)?.strdup(); Ok(()) }, ) @@ -807,9 +803,9 @@ unsafe fn get_parent_mime_headers( FROM msgs WHERE chat_id=? AND from_id==?);", params![(*chat).id as i32, 1], |row| { - *parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?); - *parent_in_reply_to = to_cstring(row.get::<_, String>(1)?); - *parent_references = to_cstring(row.get::<_, String>(2)?); + *parent_rfc724_mid = row.get::<_, String>(0)?.strdup(); + *parent_in_reply_to = row.get::<_, String>(1)?.strdup(); + *parent_references = row.get::<_, String>(2)?.strdup(); Ok(()) }, ) @@ -1012,7 +1008,7 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t let mut pathNfilename = (*msg) .param .get(Param::File) - .map(|s| to_cstring(s)) + .map(|s| s.strdup()) .unwrap_or_else(|| std::ptr::null_mut()); if pathNfilename.is_null() { OK_TO_CONTINUE = false; @@ -1620,12 +1616,14 @@ pub unsafe fn dc_add_contact_to_chat_ex( if OK_TO_CONTINUE { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { (*msg).type_0 = Viewtype::Text; - (*msg).text = to_cstring(context.stock_system_msg( - StockMessage::MsgAddMember, - as_str((*contact).addr), - "", - DC_CONTACT_ID_SELF as uint32_t, - )); + (*msg).text = context + .stock_system_msg( + StockMessage::MsgAddMember, + as_str((*contact).addr), + "", + DC_CONTACT_ID_SELF as uint32_t, + ) + .strdup(); (*msg).param.set_int(Param::Cmd, 4); if !(*contact).addr.is_null() { (*msg).param.set(Param::Arg, as_str((*contact).addr)); @@ -1733,19 +1731,23 @@ pub unsafe fn dc_remove_contact_from_chat( (*msg).type_0 = Viewtype::Text; if (*contact).id == 1 as libc::c_uint { dc_set_group_explicitly_left(context, (*chat).grpid); - (*msg).text = to_cstring(context.stock_system_msg( - StockMessage::MsgGroupLeft, - "", - "", - DC_CONTACT_ID_SELF as u32, - )); + (*msg).text = context + .stock_system_msg( + StockMessage::MsgGroupLeft, + "", + "", + DC_CONTACT_ID_SELF as u32, + ) + .strdup(); } else { - (*msg).text = to_cstring(context.stock_system_msg( - StockMessage::MsgDelMember, - as_str((*contact).addr), - "", - DC_CONTACT_ID_SELF as u32, - )); + (*msg).text = context + .stock_system_msg( + StockMessage::MsgDelMember, + as_str((*contact).addr), + "", + DC_CONTACT_ID_SELF as u32, + ) + .strdup(); } (*msg).param.set_int(Param::Cmd, 5); if !(*contact).addr.is_null() { @@ -1846,12 +1848,14 @@ pub unsafe fn dc_set_chat_name( { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { (*msg).type_0 = Viewtype::Text; - (*msg).text = to_cstring(context.stock_system_msg( - StockMessage::MsgGrpName, - as_str((*chat).name), - as_str(new_name), - DC_CONTACT_ID_SELF as u32, - )); + (*msg).text = context + .stock_system_msg( + StockMessage::MsgGrpName, + as_str((*chat).name), + as_str(new_name), + DC_CONTACT_ID_SELF as u32, + ) + .strdup(); (*msg).param.set_int(Param::Cmd, 2); if !(*chat).name.is_null() { (*msg).param.set(Param::Arg, as_str((*chat).name)); @@ -1918,16 +1922,18 @@ pub unsafe fn dc_set_chat_profile_image( (*msg).param.set_int(Param::Cmd, 3); (*msg).param.set(Param::Arg, as_str(new_image_rel)); (*msg).type_0 = Viewtype::Text; - (*msg).text = to_cstring(context.stock_system_msg( - if !new_image_rel.is_null() { - StockMessage::MsgGrpImgChanged - } else { - StockMessage::MsgGrpImgDeleted - }, - "", - "", - DC_CONTACT_ID_SELF as uint32_t, - )); + (*msg).text = context + .stock_system_msg( + if !new_image_rel.is_null() { + StockMessage::MsgGrpImgChanged + } else { + StockMessage::MsgGrpImgDeleted + }, + "", + "", + DC_CONTACT_ID_SELF as uint32_t, + ) + .strdup(); (*msg).id = dc_send_msg(context, chat_id, msg); context.call_cb( Event::MSGS_CHANGED, @@ -2094,7 +2100,10 @@ pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char { let mut ret: *mut libc::c_char = std::ptr::null_mut(); if (*chat).type_0 == 100 && (*chat).param.exists(Param::Selftalk) { - ret = to_cstring((*chat).context.stock_str(StockMessage::SelfTalkSubTitle)); + ret = (*chat) + .context + .stock_str(StockMessage::SelfTalkSubTitle) + .strdup(); } else if (*chat).type_0 == 100 { let ret_raw: String = (*chat) .context @@ -2108,17 +2117,16 @@ pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char { 0, ) .unwrap_or_else(|| "Err".into()); - ret = to_cstring(ret_raw); + ret = ret_raw.strdup(); } else if (*chat).type_0 == 120 || (*chat).type_0 == 130 { if (*chat).id == 1 { - ret = to_cstring((*chat).context.stock_str(StockMessage::DeadDrop)); + ret = (*chat).context.stock_str(StockMessage::DeadDrop).strdup(); } else { let cnt = dc_get_chat_contact_cnt((*chat).context, (*chat).id); - ret = to_cstring( - (*chat) - .context - .stock_string_repl_int(StockMessage::Member, cnt), - ); + ret = (*chat) + .context + .stock_string_repl_int(StockMessage::Member, cnt) + .strdup(); } } return if !ret.is_null() { @@ -2146,7 +2154,11 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t; let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t; if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) { - image_rel = to_cstring((*chat).param.get(Param::ProfileImage).unwrap_or_default()); + image_rel = (*chat) + .param + .get(Param::ProfileImage) + .unwrap_or_default() + .strdup(); if !image_rel.is_null() && 0 != *image_rel.offset(0isize) as libc::c_int { image_abs = dc_get_abs_path((*chat).context, image_rel) } else if (*chat).type_0 == 100i32 { diff --git a/src/dc_configure.rs b/src/dc_configure.rs index a1397742a..73f449e7b 100644 --- a/src/dc_configure.rs +++ b/src/dc_configure.rs @@ -1102,14 +1102,14 @@ unsafe fn moz_autoconfigure( tag_config: 0, }; - let url_c = to_cstring(url); + let url_c = url.strdup(); let xml_raw = read_autoconf_file(context, url_c); free(url_c as *mut libc::c_void); if xml_raw.is_null() { return None; } - moz_ac.in_emaillocalpart = to_cstring(¶m_in.addr); + moz_ac.in_emaillocalpart = param_in.addr.strdup(); let p = strchr(moz_ac.in_emaillocalpart, '@' as i32); if p.is_null() { @@ -1166,7 +1166,7 @@ unsafe fn moz_autoconfigure_text_cb( let mut moz_ac: *mut moz_autoconfigure_t = userdata as *mut moz_autoconfigure_t; let mut val: *mut libc::c_char = dc_strdup(text); dc_trim(val); - let addr = to_cstring(&(*moz_ac).in_0.addr); + let addr = (*moz_ac).in_0.addr.strdup(); dc_str_replace( &mut val, b"%EMAILADDRESS%\x00" as *const u8 as *const libc::c_char, @@ -1306,7 +1306,7 @@ fn read_autoconf_file(context: &Context, url: *const libc::c_char) -> *mut libc: .send() .and_then(|mut res| res.text()) { - Ok(res) => unsafe { to_cstring(res) }, + Ok(res) => unsafe { res.strdup() }, Err(_err) => { info!(context, 0, "Can\'t read file.",); @@ -1322,7 +1322,7 @@ unsafe fn outlk_autodiscover( ) -> Option { let current_block: u64; let mut xml_raw: *mut libc::c_char = 0 as *mut libc::c_char; - let mut url = to_cstring(url__); + let mut url = url__.strdup(); let mut outlk_ad = outlk_autodiscover_t { in_0: param_in, out: dc_loginparam_new(), diff --git a/src/dc_contact.rs b/src/dc_contact.rs index 1beeb3a81..3b5b5b0d4 100644 --- a/src/dc_contact.rs +++ b/src/dc_contact.rs @@ -278,14 +278,13 @@ pub unsafe fn dc_contact_load_from_db( if contact_id == 1 as libc::c_uint { (*contact).id = contact_id; - (*contact).name = to_cstring((*contact).context.stock_str(StockMessage::SelfMsg)); - (*contact).addr = to_cstring( - (*contact) - .context - .sql - .get_config((*contact).context, "configured_addr") - .unwrap_or_default(), - ); + (*contact).name = (*contact).context.stock_str(StockMessage::SelfMsg).strdup(); + (*contact).addr = (*contact) + .context + .sql + .get_config((*contact).context, "configured_addr") + .unwrap_or_default() + .strdup(); true } else { sql.query_row( @@ -293,11 +292,11 @@ pub unsafe fn dc_contact_load_from_db( params![contact_id as i32], |row| { (*contact).id = contact_id; - (*contact).name = to_cstring(row.get::<_, String>(0)?); - (*contact).addr = to_cstring(row.get::<_, String>(1)?); + (*contact).name = row.get::<_, String>(0)?.strdup(); + (*contact).addr = row.get::<_, String>(1)?.strdup(); (*contact).origin = row.get(2)?; (*contact).blocked = row.get::<_, Option>(3)?.unwrap_or_default(); - (*contact).authname = to_cstring(row.get::<_, String>(4)?); + (*contact).authname = row.get::<_, String>(4)?.strdup(); Ok(()) } ).is_ok() @@ -726,7 +725,7 @@ pub unsafe fn dc_get_contact_encrinfo( free(fingerprint_other_verified as *mut libc::c_void); free(fingerprint_other_unverified as *mut libc::c_void); - to_cstring(ret) + ret.strdup() } unsafe fn cat_fingerprint( @@ -901,7 +900,7 @@ pub fn dc_contact_get_profile_image(contact: *const dc_contact_t) -> *mut libc:: if unsafe { (*contact).id } == 1 { let context = unsafe { (*contact) }.context; if let Some(avatar) = context.get_config(config::Config::Selfavatar) { - image_abs = unsafe { to_cstring(avatar) }; + image_abs = unsafe { avatar.strdup() }; } } // TODO: else get image_abs from contact param diff --git a/src/dc_dehtml.rs b/src/dc_dehtml.rs index ae0cd7546..bc9747556 100644 --- a/src/dc_dehtml.rs +++ b/src/dc_dehtml.rs @@ -53,7 +53,7 @@ pub unsafe fn dc_dehtml(buf_terminated: *mut libc::c_char) -> *mut libc::c_char dc_saxparser_parse(&mut saxparser, buf_terminated); free(dehtml.last_href as *mut libc::c_void); - to_cstring(dehtml.strbuilder) + dehtml.strbuilder.strdup() } unsafe fn dehtml_text_cb( diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index 3232a9a91..70e77544a 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -177,16 +177,12 @@ pub unsafe fn dc_e2ee_encrypt( let p = peerstates[i as usize] .render_gossip_header(min_verified as usize); - if p.is_some() { - let header = to_cstring(p.unwrap()); + if let Some(header) = p { mailimf_fields_add( imffields_encrypted, mailimf_field_new_custom( - strdup( - b"Autocrypt-Gossip\x00" as *const u8 - as *const libc::c_char, - ), - header, + "Autocrypt-Gossip".strdup(), + header.strdup(), ), ); } @@ -296,7 +292,7 @@ pub unsafe fn dc_e2ee_encrypt( sign_key.as_ref(), ) { let ctext_bytes = ctext_v.len(); - let ctext = to_cstring(ctext_v); + let ctext = ctext_v.strdup(); (*helper).cdata_to_free = ctext as *mut _; /* create MIME-structure that will contain the encrypted text */ @@ -354,13 +350,11 @@ pub unsafe fn dc_e2ee_encrypt( 14181132614457621749 => {} _ => { let aheader = Aheader::new(addr, public_key, prefer_encrypt); - let rendered = to_cstring(aheader.to_string()); - mailimf_fields_add( imffields_unprotected, mailimf_field_new_custom( - strdup(b"Autocrypt\x00" as *const u8 as *const libc::c_char), - rendered, + "Autocrypt".strdup(), + aheader.to_string().strdup(), ), ); } diff --git a/src/dc_imex.rs b/src/dc_imex.rs index cc6ffaf33..0ca50eb4b 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -515,7 +515,7 @@ pub unsafe fn dc_normalize_setup_code( p1 = p1.offset(1); } - to_cstring(out) + out.strdup() } #[allow(non_snake_case)] @@ -524,16 +524,14 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) let mut success: libc::c_int = 0; let mut ongoing_allocated_here: libc::c_int = 0; let what: libc::c_int; - let mut param1 = 0 as *mut libc::c_char; - let mut param2 = 0 as *mut libc::c_char; if !(0 == dc_alloc_ongoing(context)) { ongoing_allocated_here = 1; what = (*job).param.get_int(Param::Cmd).unwrap_or_default(); - param1 = to_cstring((*job).param.get(Param::Arg).unwrap_or_default()); - param2 = to_cstring((*job).param.get(Param::Arg2).unwrap_or_default()); + let param1 = CString::yolo((*job).param.get(Param::Arg).unwrap_or_default()); + let _param2 = CString::yolo((*job).param.get(Param::Arg2).unwrap_or_default()); - if strlen(param1) == 0 { + if strlen(param1.as_ptr()) == 0 { error!(context, 0, "No Import/export dir/file given.",); } else { info!(context, 0, "Import/export process started.",); @@ -551,7 +549,7 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) ); current_block = 3568988166330621280; } else { - dc_create_folder(context, param1); + dc_create_folder(context, param1.as_ptr()); current_block = 4495394744059808450; } } else { @@ -564,28 +562,28 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) current_block = 10991094515395304355; match current_block { 2973387206439775448 => { - if 0 == import_backup(context, param1) { + if 0 == import_backup(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } 11250025114629486028 => { - if 0 == import_self_keys(context, param1) { + if 0 == import_self_keys(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } 12669919903773909120 => { - if 0 == export_backup(context, param1) { + if 0 == export_backup(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } _ => { - if 0 == export_self_keys(context, param1) { + if 0 == export_self_keys(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; @@ -604,28 +602,28 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) current_block = 11250025114629486028; match current_block { 2973387206439775448 => { - if 0 == import_backup(context, param1) { + if 0 == import_backup(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } 11250025114629486028 => { - if 0 == import_self_keys(context, param1) { + if 0 == import_self_keys(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } 12669919903773909120 => { - if 0 == export_backup(context, param1) { + if 0 == export_backup(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } _ => { - if 0 == export_self_keys(context, param1) { + if 0 == export_self_keys(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; @@ -644,28 +642,28 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) current_block = 12669919903773909120; match current_block { 2973387206439775448 => { - if 0 == import_backup(context, param1) { + if 0 == import_backup(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } 11250025114629486028 => { - if 0 == import_self_keys(context, param1) { + if 0 == import_self_keys(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } 12669919903773909120 => { - if 0 == export_backup(context, param1) { + if 0 == export_backup(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } _ => { - if 0 == export_self_keys(context, param1) { + if 0 == export_self_keys(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; @@ -684,28 +682,28 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) current_block = 2973387206439775448; match current_block { 2973387206439775448 => { - if 0 == import_backup(context, param1) { + if 0 == import_backup(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } 11250025114629486028 => { - if 0 == import_self_keys(context, param1) { + if 0 == import_self_keys(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } 12669919903773909120 => { - if 0 == export_backup(context, param1) { + if 0 == export_backup(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; } } _ => { - if 0 == export_self_keys(context, param1) { + if 0 == export_self_keys(context, param1.as_ptr()) { current_block = 3568988166330621280; } else { current_block = 1118134448028020070; @@ -727,8 +725,6 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) } } - free(param1 as *mut libc::c_void); - free(param2 as *mut libc::c_void); if 0 != ongoing_allocated_here { dc_free_ongoing(context); } @@ -875,9 +871,8 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_ let res = chrono::NaiveDateTime::from_timestamp(now as i64, 0) .format("delta-chat-%Y-%m-%d.bak") .to_string(); - let buffer = to_cstring(res); - let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer); - free(buffer as *mut _); + let 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.",); @@ -1076,7 +1071,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) -> let mut imported_cnt: libc::c_int = 0; let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char; let mut path_plus_name: *mut libc::c_char = 0 as *mut libc::c_char; - let mut name_c: *mut libc::c_char = 0 as *mut libc::c_char; let mut set_default: libc::c_int; let mut buf: *mut libc::c_char = 0 as *mut libc::c_char; let mut buf_bytes: size_t = 0 as size_t; @@ -1104,9 +1098,8 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) -> let entry = entry.unwrap(); free(suffix as *mut libc::c_void); let name_f = entry.file_name(); - free(name_c as *mut libc::c_void); - name_c = to_cstring(name_f.to_string_lossy()); - suffix = dc_get_filesuffix_lc(name_c); + let name_c = name_f.to_c_string().unwrap(); + suffix = dc_get_filesuffix_lc(name_c.as_ptr()); if suffix.is_null() || strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0 { @@ -1116,7 +1109,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) -> path_plus_name = dc_mprintf( b"%s/%s\x00" as *const u8 as *const libc::c_char, dir_name, - name_c, + name_c.as_ptr(), ); info!(context, 0, "Checking: {}", as_str(path_plus_name)); free(buf as *mut libc::c_void); @@ -1154,7 +1147,12 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) -> } } set_default = 1; - if !strstr(name_c, b"legacy\x00" as *const u8 as *const libc::c_char).is_null() { + if !strstr( + name_c.as_ptr(), + b"legacy\x00" as *const u8 as *const libc::c_char, + ) + .is_null() + { info!( context, 0, @@ -1179,7 +1177,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) -> } } - free(name_c as *mut libc::c_void); free(suffix as *mut libc::c_void); free(path_plus_name as *mut libc::c_void); free(buf as *mut libc::c_void); diff --git a/src/dc_job.rs b/src/dc_job.rs index 9bfa71dde..5efa05f53 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -314,7 +314,7 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) { } match current_block { 13109137661213826276 => { - filename = to_cstring(job.param.get(Param::File).unwrap_or_default()); + filename = job.param.get(Param::File).unwrap_or_default().strdup(); if strlen(filename) == 0 { warn!(context, 0, "Missing file name for job {}", job.job_id,); } else if !(0 == dc_read_file(context, filename, &mut buf, &mut buf_bytes)) { @@ -1177,12 +1177,11 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in } else { // no redo, no IMAP. moreover, as the data does not exist, there is no need in calling dc_set_msg_failed() if msgtype_has_file((*mimefactory.msg).type_0) { - let pathNfilename = to_cstring( - (*mimefactory.msg) - .param - .get(Param::File) - .unwrap_or_default(), - ); + let pathNfilename = (*mimefactory.msg) + .param + .get(Param::File) + .unwrap_or_default() + .strdup(); if strlen(pathNfilename) > 0 { if ((*mimefactory.msg).type_0 == Viewtype::Image || (*mimefactory.msg).type_0 == Viewtype::Gif) diff --git a/src/dc_location.rs b/src/dc_location.rs index 14edc3767..c9e3ee66e 100644 --- a/src/dc_location.rs +++ b/src/dc_location.rs @@ -100,12 +100,9 @@ pub unsafe fn dc_send_locations_to_chat( { if 0 != seconds && !is_sending_locations_before { msg = dc_msg_new(context, Viewtype::Text); - (*msg).text = to_cstring(context.stock_system_msg( - StockMessage::MsgLocationEnabled, - "", - "", - 0, - )); + (*msg).text = context + .stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0) + .strdup(); (*msg).param.set_int(Param::Cmd, 8); dc_send_msg(context, chat_id, msg); } else if 0 == seconds && is_sending_locations_before { @@ -351,7 +348,7 @@ pub fn dc_get_location_kml( } if 0 != success { - unsafe { to_cstring(ret) } + unsafe { ret.strdup() } } else { std::ptr::null_mut() } @@ -365,7 +362,7 @@ unsafe fn get_kml_timestamp(utc: i64) -> *mut libc::c_char { let res = chrono::NaiveDateTime::from_timestamp(utc, 0) .format("%Y-%m-%dT%H:%M:%SZ") .to_string(); - to_cstring(res) + res.strdup() } pub unsafe fn dc_get_message_kml( diff --git a/src/dc_lot.rs b/src/dc_lot.rs index 429859636..3d4c714de 100644 --- a/src/dc_lot.rs +++ b/src/dc_lot.rs @@ -134,14 +134,14 @@ pub unsafe fn dc_lot_fill( return; } if (*msg).state == 19i32 { - (*lot).text1 = to_cstring(context.stock_str(StockMessage::Draft)); + (*lot).text1 = context.stock_str(StockMessage::Draft).strdup(); (*lot).text1_meaning = 1i32 } else if (*msg).from_id == 1i32 as libc::c_uint { if 0 != dc_msg_is_info(msg) || 0 != dc_chat_is_self_talk(chat) { (*lot).text1 = 0 as *mut libc::c_char; (*lot).text1_meaning = 0i32 } else { - (*lot).text1 = to_cstring(context.stock_str(StockMessage::SelfMsg)); + (*lot).text1 = context.stock_str(StockMessage::SelfMsg).strdup(); (*lot).text1_meaning = 3i32 } } else if chat.is_null() { diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 22214b125..0cb95d780 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -158,13 +158,13 @@ pub unsafe fn dc_mimefactory_load_msg( |rows| { for row in rows { let (authname, addr) = row?; - let addr_c = to_cstring(addr); + let addr_c = addr.strdup(); if clist_search_string_nocase((*factory).recipients_addr, addr_c) == 0 { clist_insert_after( (*factory).recipients_names, (*(*factory).recipients_names).last, if !authname.is_empty() { - to_cstring(authname) + authname.strdup() } else { std::ptr::null_mut() } as *mut libc::c_void, @@ -188,7 +188,7 @@ pub unsafe fn dc_mimefactory_load_msg( if command == 5 { let email_to_remove = (*(*factory).msg).param.get(Param::Arg).unwrap_or_default(); - let email_to_remove_c = to_cstring(email_to_remove); + let email_to_remove_c = email_to_remove.strdup(); let self_addr = context .sql @@ -234,8 +234,8 @@ pub unsafe fn dc_mimefactory_load_msg( ); match row { Ok((in_reply_to, references)) => { - (*factory).in_reply_to = to_cstring(in_reply_to); - (*factory).references = to_cstring(references); + (*factory).in_reply_to = in_reply_to.strdup(); + (*factory).references = references.strdup(); } Err(err) => { error!( @@ -259,27 +259,28 @@ pub unsafe fn dc_mimefactory_load_msg( unsafe fn load_from(mut factory: *mut dc_mimefactory_t) { let context = (*factory).context; - (*factory).from_addr = to_cstring( - context - .sql - .get_config(context, "configured_addr") - .unwrap_or_default(), - ); + (*factory).from_addr = context + .sql + .get_config(context, "configured_addr") + .unwrap_or_default() + .strdup(); - (*factory).from_displayname = to_cstring( - context - .sql - .get_config(context, "displayname") - .unwrap_or_default(), - ); - (*factory).selfstatus = to_cstring( - context - .sql - .get_config(context, "selfstatus") - .unwrap_or_default(), - ); + (*factory).from_displayname = context + .sql + .get_config(context, "displayname") + .unwrap_or_default() + .strdup(); + + (*factory).selfstatus = context + .sql + .get_config(context, "selfstatus") + .unwrap_or_default() + .strdup(); if (*factory).selfstatus.is_null() { - (*factory).selfstatus = to_cstring((*factory).context.stock_str(StockMessage::StatusLine)); + (*factory).selfstatus = (*factory) + .context + .stock_str(StockMessage::StatusLine) + .strdup(); }; } @@ -573,8 +574,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: ), ); if command == 5 { - let email_to_remove = - to_cstring((*msg).param.get(Param::Arg).unwrap_or_default()); + let email_to_remove = (*msg).param.get(Param::Arg).unwrap_or_default().strdup(); if strlen(email_to_remove) > 0 { mailimf_fields_add( imf_fields, @@ -589,7 +589,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: } } else if command == 4 { do_gossip = 1; - let email_to_add = to_cstring((*msg).param.get(Param::Arg).unwrap_or_default()); + let email_to_add = (*msg).param.get(Param::Arg).unwrap_or_default().strdup(); if strlen(email_to_add) > 0 { mailimf_fields_add( imf_fields, @@ -619,7 +619,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: ); } } else if command == 2 { - let value_to_add = to_cstring((*msg).param.get(Param::Arg).unwrap_or_default()); + let value_to_add = (*msg).param.get(Param::Arg).unwrap_or_default().strdup(); mailimf_fields_add( imf_fields, mailimf_field_new_custom( @@ -661,11 +661,13 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: strdup(b"v1\x00" as *const u8 as *const libc::c_char), ), ); - placeholdertext = - to_cstring((*factory).context.stock_str(StockMessage::AcSetupMsgBody)); + placeholdertext = (*factory) + .context + .stock_str(StockMessage::AcSetupMsgBody) + .strdup(); } if command == 7 { - let step = to_cstring((*msg).param.get(Param::Arg).unwrap_or_default()); + let step = (*msg).param.get(Param::Arg).unwrap_or_default().strdup(); if strlen(step) > 0 { info!( (*msg).context, @@ -680,7 +682,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: step, ), ); - let param2 = to_cstring((*msg).param.get(Param::Arg2).unwrap_or_default()); + let param2 = (*msg).param.get(Param::Arg2).unwrap_or_default().strdup(); if strlen(param2) > 0 { mailimf_fields_add( imf_fields, @@ -708,7 +710,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: ), ); } - let fingerprint = to_cstring((*msg).param.get(Param::Arg3).unwrap_or_default()); + let fingerprint = (*msg).param.get(Param::Arg3).unwrap_or_default().strdup(); if strlen(fingerprint) > 0 { mailimf_fields_add( imf_fields, @@ -722,7 +724,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: ); } let grpid = match (*msg).param.get(Param::Arg4) { - Some(id) => to_cstring(id), + Some(id) => id.strdup(), None => std::ptr::null_mut(), }; if !grpid.is_null() { @@ -958,25 +960,23 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: ) as *mut libc::c_void, ); mailmime_add_part(message, multipart); - let p1: *mut libc::c_char; - let p2: *mut libc::c_char; - if 0 != (*(*factory).msg) - .param - .get_int(Param::GuranteeE2ee) - .unwrap_or_default() + let p1 = if 0 + != (*(*factory).msg) + .param + .get_int(Param::GuranteeE2ee) + .unwrap_or_default() { - p1 = to_cstring((*factory).context.stock_str(StockMessage::EncryptedMsg)); - } else { - p1 = dc_msg_get_summarytext((*factory).msg, 32) - } - p2 = to_cstring( (*factory) .context - .stock_string_repl_str(StockMessage::ReadRcptMailBody, as_str(p1)), - ); - message_text = dc_mprintf(b"%s\r\n\x00" as *const u8 as *const libc::c_char, p2); - free(p1 as *mut libc::c_void); - free(p2 as *mut libc::c_void); + .stock_str(StockMessage::EncryptedMsg) + .into_owned() + } else { + to_string(dc_msg_get_summarytext((*factory).msg, 32)) + }; + let p2 = (*factory) + .context + .stock_string_repl_str(StockMessage::ReadRcptMailBody, p1); + message_text = format!("{}\r\n", p2).strdup(); let human_mime_part: *mut mailmime = build_body_text(message_text); mailmime_add_part(multipart, human_mime_part); message_text2 = @@ -1102,7 +1102,7 @@ unsafe fn get_subject( b"\x00" as *const u8 as *const libc::c_char }; if (*msg).param.get_int(Param::Cmd).unwrap_or_default() == 6 { - ret = to_cstring(context.stock_str(StockMessage::AcSetupMsgSubject)) + ret = context.stock_str(StockMessage::AcSetupMsgSubject).strdup() } else if (*chat).type_0 == DC_CHAT_TYPE_GROUP as libc::c_int || (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP as libc::c_int { @@ -1165,12 +1165,12 @@ unsafe fn build_body_file( let pathNfilename = (*msg) .param .get(Param::File) - .map(|s| to_cstring(s)) + .map(|s| s.strdup()) .unwrap_or_else(|| std::ptr::null_mut()); let mut mimetype = (*msg) .param .get(Param::MimeType) - .map(|s| to_cstring(s)) + .map(|s| s.strdup()) .unwrap_or_else(|| std::ptr::null_mut()); let suffix = dc_get_filesuffix_lc(pathNfilename); @@ -1189,7 +1189,7 @@ unsafe fn build_body_file( let res = ts .format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix)) .to_string(); - filename_to_send = to_cstring(res); + filename_to_send = res.strdup(); } else if (*msg).type_0 == Viewtype::Audio { filename_to_send = dc_get_filename(pathNfilename) } else if (*msg).type_0 == Viewtype::Image || (*msg).type_0 == Viewtype::Gif { @@ -1329,7 +1329,7 @@ unsafe fn build_body_file( #[allow(non_snake_case)] unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> bool { let mut file_size_okay = true; - let pathNfilename = to_cstring((*msg).param.get(Param::File).unwrap_or_default()); + let pathNfilename = (*msg).param.get(Param::File).unwrap_or_default().strdup(); let bytes = dc_get_filebytes((*msg).context, pathNfilename); if bytes > (49 * 1024 * 1024 / 4 * 3) { diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index b0b06cc0b..05c1bec43 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -1312,9 +1312,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known( } if !filename_parts.is_empty() { free(desired_filename as *mut libc::c_void); - let parts_c = to_cstring(filename_parts); - desired_filename = dc_decode_ext_header(parts_c); - free(parts_c as *mut _); + let parts_c = CString::yolo(filename_parts); + desired_filename = dc_decode_ext_header(parts_c.as_ptr()); } if desired_filename.is_null() { let param = mailmime_find_ct_parameter( diff --git a/src/dc_msg.rs b/src/dc_msg.rs index 66e404680..596347610 100644 --- a/src/dc_msg.rs +++ b/src/dc_msg.rs @@ -65,7 +65,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch ret += &format!("Cannot load message #{}.", msg_id as usize); dc_msg_unref(msg); dc_contact_unref(contact_from); - return to_cstring(ret); + return ret.strdup(); } let rawtxt = rawtxt.unwrap(); let rawtxt = dc_truncate_str(rawtxt.trim(), 100000); @@ -92,7 +92,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch // device-internal message, no further details needed dc_msg_unref(msg); dc_contact_unref(contact_from); - return to_cstring(ret); + return ret.strdup(); } context @@ -210,7 +210,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch dc_msg_unref(msg); dc_contact_unref(contact_from); - to_cstring(ret) + ret.strdup() } pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a> { @@ -288,18 +288,17 @@ pub unsafe fn dc_msg_get_filemime(msg: *const dc_msg_t) -> *mut libc::c_char { if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) { match (*msg).param.get(Param::MimeType) { Some(m) => { - ret = to_cstring(m); + ret = m.strdup(); } None => { if let Some(file) = (*msg).param.get(Param::File) { - let file_c = to_cstring(file); - dc_msg_guess_msgtype_from_suffix(file_c, 0 as *mut Viewtype, &mut ret); + let file_c = CString::yolo(file); + dc_msg_guess_msgtype_from_suffix(file_c.as_ptr(), 0 as *mut Viewtype, &mut ret); if ret.is_null() { ret = dc_strdup( b"application/octet-stream\x00" as *const u8 as *const libc::c_char, ) } - free(file_c as *mut _); } } } @@ -372,9 +371,8 @@ pub unsafe fn dc_msg_get_file(msg: *const dc_msg_t) -> *mut libc::c_char { if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) { if let Some(file_rel) = (*msg).param.get(Param::File) { - let file_rel_c = to_cstring(file_rel); - file_abs = dc_get_abs_path((*msg).context, file_rel_c); - free(file_rel_c as *mut _); + let file_rel_c = CString::yolo(file_rel); + file_abs = dc_get_abs_path((*msg).context, file_rel_c.as_ptr()); } } if !file_abs.is_null() { @@ -464,12 +462,12 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id: dc_msg_empty(msg); (*msg).id = row.get::<_, i32>(0)? as u32; - (*msg).rfc724_mid = to_cstring(row.get::<_, String>(1)?); + (*msg).rfc724_mid = row.get::<_, String>(1)?.strdup(); (*msg).in_reply_to = match row.get::<_, Option>(2)? { - Some(s) => to_cstring(s), + Some(s) => s.strdup(), None => std::ptr::null_mut(), }; - (*msg).server_folder = to_cstring(row.get::<_, String>(3)?); + (*msg).server_folder = row.get::<_, String>(3)?.strdup(); (*msg).server_uid = row.get(4)?; (*msg).move_state = row.get(5)?; (*msg).chat_id = row.get(6)?; @@ -481,7 +479,7 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id: (*msg).type_0 = row.get(12)?; (*msg).state = row.get(13)?; (*msg).is_dc_message = row.get(14)?; - (*msg).text = to_cstring(row.get::<_, String>(15).unwrap_or_default()); + (*msg).text = row.get::<_, String>(15).unwrap_or_default().strdup(); (*msg).param = row.get::<_, String>(16)?.parse().unwrap_or_default(); (*msg).starred = row.get(17)?; (*msg).hidden = row.get(18)?; @@ -507,10 +505,8 @@ pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: uint32_t) -> *mut l ); if let Some(headers) = headers { - let h = to_cstring(headers); - let res = dc_strdup_keep_null(h); - free(h as *mut _); - res + let h = CString::yolo(headers); + dc_strdup_keep_null(h.as_ptr()) } else { std::ptr::null_mut() } @@ -711,7 +707,7 @@ pub unsafe fn dc_msg_get_text(msg: *const dc_msg_t) -> *mut libc::c_char { } let res = dc_truncate_str(as_str((*msg).text), 30000); - to_cstring(res) + res.strdup() } #[allow(non_snake_case)] @@ -720,9 +716,8 @@ pub unsafe fn dc_msg_get_filename(msg: *const dc_msg_t) -> *mut libc::c_char { if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) { if let Some(file) = (*msg).param.get(Param::File) { - let file_c = to_cstring(file); - ret = dc_get_filename(file_c); - free(file_c as *mut _); + let file_c = CString::yolo(file); + ret = dc_get_filename(file_c.as_ptr()); } } if !ret.is_null() { @@ -737,9 +732,8 @@ pub unsafe fn dc_msg_get_filebytes(msg: *const dc_msg_t) -> uint64_t { if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) { if let Some(file) = (*msg).param.get(Param::File) { - let file_c = to_cstring(file); - ret = dc_get_filebytes((*msg).context, file_c); - free(file_c as *mut _); + let file_c = CString::yolo(file); + ret = dc_get_filebytes((*msg).context, file_c.as_ptr()); } } @@ -858,16 +852,19 @@ pub unsafe fn dc_msg_get_summarytext_by_raw( let mut value: *mut libc::c_char = 0 as *mut libc::c_char; let mut append_text: libc::c_int = 1i32; match type_0 { - Viewtype::Image => prefix = to_cstring(context.stock_str(StockMessage::Image)), - Viewtype::Gif => prefix = to_cstring(context.stock_str(StockMessage::Gif)), - Viewtype::Video => prefix = to_cstring(context.stock_str(StockMessage::Video)), - Viewtype::Voice => prefix = to_cstring(context.stock_str(StockMessage::VoiceMessage)), + Viewtype::Image => prefix = context.stock_str(StockMessage::Image).strdup(), + Viewtype::Gif => prefix = context.stock_str(StockMessage::Gif).strdup(), + Viewtype::Video => prefix = context.stock_str(StockMessage::Video).strdup(), + Viewtype::Voice => prefix = context.stock_str(StockMessage::VoiceMessage).strdup(), Viewtype::Audio | Viewtype::File => { if param.get_int(Param::Cmd) == Some(6) { - prefix = to_cstring(context.stock_str(StockMessage::AcSetupMsgSubject)); + prefix = context.stock_str(StockMessage::AcSetupMsgSubject).strdup(); append_text = 0i32 } else { - pathNfilename = to_cstring(param.get(Param::File).unwrap_or_else(|| "ErrFilename")); + pathNfilename = param + .get(Param::File) + .unwrap_or_else(|| "ErrFilename") + .strdup(); value = dc_get_filename(pathNfilename); let label = CString::new( context @@ -888,7 +885,7 @@ pub unsafe fn dc_msg_get_summarytext_by_raw( } _ => { if param.get_int(Param::Cmd) == Some(9) { - prefix = to_cstring(context.stock_str(StockMessage::Location)); + prefix = context.stock_str(StockMessage::Location).strdup(); append_text = 0; } } @@ -1387,7 +1384,7 @@ pub fn dc_rfc724_mid_exists( &[as_str(rfc724_mid)], |row| { if !ret_server_folder.is_null() { - unsafe { *ret_server_folder = to_cstring(row.get::<_, String>(0)?) }; + unsafe { *ret_server_folder = row.get::<_, String>(0)?.strdup() }; } if !ret_server_uid.is_null() { unsafe { *ret_server_uid = row.get(1)? }; diff --git a/src/dc_qr.rs b/src/dc_qr.rs index ac9ad1ffe..5541cd3a4 100644 --- a/src/dc_qr.rs +++ b/src/dc_qr.rs @@ -59,34 +59,34 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc let param: Params = as_str(fragment).parse().expect("invalid params"); addr = param .get(Param::Forwarded) - .map(|s| to_cstring(s)) + .map(|s| s.strdup()) .unwrap_or_else(|| std::ptr::null_mut()); if !addr.is_null() { if let Some(ref name_enc) = param.get(Param::SetLongitude) { let name_r = percent_decode_str(name_enc) .decode_utf8() .expect("invalid name"); - name = to_cstring(name_r); + name = name_r.strdup(); dc_normalize_name(name); } invitenumber = param .get(Param::ProfileImage) - .map(|s| to_cstring(s)) + .map(|s| s.strdup()) .unwrap_or_else(|| std::ptr::null_mut()); auth = param .get(Param::Auth) - .map(|s| to_cstring(s)) + .map(|s| s.strdup()) .unwrap_or_else(|| std::ptr::null_mut()); grpid = param .get(Param::GroupId) - .map(|s| to_cstring(s)) + .map(|s| s.strdup()) .unwrap_or_else(|| std::ptr::null_mut()); if !grpid.is_null() { if let Some(grpname_enc) = param.get(Param::GroupName) { let grpname_r = percent_decode_str(grpname_enc) .decode_utf8() .expect("invalid groupname"); - grpname = to_cstring(grpname_r); + grpname = grpname_r.strdup(); } } } @@ -253,7 +253,7 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc if let Some(peerstate) = peerstate { (*qr_parsed).state = 210i32; let addr_ptr = if let Some(ref addr) = peerstate.addr { - to_cstring(addr) + addr.strdup() } else { std::ptr::null() }; diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 8821cab07..cde7c3615 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -1210,7 +1210,7 @@ unsafe fn create_or_lookup_group( grpimage = (*part) .param .get(Param::File) - .map(|s| to_cstring(s)) + .map(|s| s.strdup()) .unwrap_or_else(|| std::ptr::null_mut()); ok = 1 } @@ -1407,10 +1407,12 @@ unsafe fn create_or_lookup_adhoc_group( { grpname = dc_strdup(mime_parser.subject) } else { - grpname = to_cstring(context.stock_string_repl_int( - StockMessage::Member, - dc_array_get_cnt(member_ids) as libc::c_int, - )); + grpname = context + .stock_string_repl_int( + StockMessage::Member, + dc_array_get_cnt(member_ids) as libc::c_int, + ) + .strdup(); } chat_id = create_group_record(context, grpid, grpname, create_blocked, 0); @@ -1519,7 +1521,7 @@ fn hex_hash(s: impl AsRef) -> *const libc::c_char { let bytes = s.as_ref().as_bytes(); let result = Sha256::digest(bytes); let result_hex = hex::encode(&result[..8]); - unsafe { to_cstring(result_hex) as *const _ } + unsafe { result_hex.strdup() as *const _ } } #[allow(non_snake_case)] @@ -1604,7 +1606,7 @@ unsafe fn check_verified_properties( let contact = dc_contact_new(context); let verify_fail = |reason: String| { - *failure_reason = to_cstring(format!("{}. See \"Info\" for details.", reason)); + *failure_reason = format!("{}. See \"Info\" for details.", reason).strdup(); warn!(context, 0, "{}", reason); }; @@ -1714,7 +1716,7 @@ unsafe fn set_better_msg>(mime_parser: &dc_mimeparser_t, better_ms carray_get(mime_parser.parts, 0 as libc::c_uint) as *mut dc_mimepart_t; if (*part).type_0 == 10 { free((*part).msg as *mut libc::c_void); - (*part).msg = to_cstring(msg); + (*part).msg = msg.strdup(); } }; } diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index d1910212d..3e908a5c1 100644 --- a/src/dc_securejoin.rs +++ b/src/dc_securejoin.rs @@ -40,7 +40,7 @@ pub unsafe fn dc_get_securejoin_qr( let mut chat = 0 as *mut Chat; let mut group_name = 0 as *mut libc::c_char; let mut group_name_urlencoded = 0 as *mut libc::c_char; - let mut qr = None; + let mut qr: Option = None; dc_ensure_secret_key_exists(context); invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id); @@ -64,7 +64,7 @@ pub unsafe fn dc_get_securejoin_qr( free(group_name_urlencoded as *mut libc::c_void); if let Some(qr) = qr { - to_cstring(qr) + qr.strdup() } else { std::ptr::null_mut() } diff --git a/src/dc_simplify.rs b/src/dc_simplify.rs index 34b567105..a95af733b 100644 --- a/src/dc_simplify.rs +++ b/src/dc_simplify.rs @@ -229,7 +229,7 @@ impl dc_simplify_t { } dc_free_splitted_lines(lines); - to_cstring(ret) + ret.strdup() } } diff --git a/src/dc_strencode.rs b/src/dc_strencode.rs index 9bdb5e902..3732d54b0 100644 --- a/src/dc_strencode.rs +++ b/src/dc_strencode.rs @@ -1,4 +1,4 @@ -use std::ffi::CStr; +use std::ffi::{CStr, CString}; use charset::Charset; use mmime::mailmime_decode::*; @@ -710,9 +710,8 @@ unsafe fn print_hex(target: *mut libc::c_char, cur: *const libc::c_char) { assert!(!cur.is_null()); let bytes = std::slice::from_raw_parts(cur as *const _, strlen(cur)); - let raw = to_cstring(format!("={}", &hex::encode_upper(bytes)[..2])); - libc::memcpy(target as *mut _, raw as *const _, 4); - free(raw as *mut libc::c_void); + let raw = CString::yolo(format!("={}", &hex::encode_upper(bytes)[..2])); + libc::memcpy(target as *mut _, raw.as_ptr() as *const _, 4); } #[cfg(test)] diff --git a/src/dc_token.rs b/src/dc_token.rs index 1dd4eccc1..8db5eae34 100644 --- a/src/dc_token.rs +++ b/src/dc_token.rs @@ -42,7 +42,7 @@ pub fn dc_token_lookup( params![namespc as i32, foreign_id as i32], 0, ) - .map(|s| unsafe { to_cstring(s) }) + .map(|s| unsafe { s.strdup() }) .unwrap_or_else(|| std::ptr::null_mut()) } diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 393b66860..5003febc1 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -178,14 +178,13 @@ pub unsafe fn dc_trim(buf: *mut libc::c_char) { /* the result must be free()'d */ pub unsafe fn dc_strlower(in_0: *const libc::c_char) -> *mut libc::c_char { - to_cstring(to_string(in_0).to_lowercase()) + to_string(in_0).to_lowercase().strdup() } pub unsafe fn dc_strlower_in_place(in_0: *mut libc::c_char) { - let raw = to_cstring(to_string(in_0).to_lowercase()); - assert_eq!(strlen(in_0), strlen(raw)); - memcpy(in_0 as *mut _, raw as *const _, strlen(in_0)); - free(raw as *mut _); + let raw = CString::yolo(to_string(in_0).to_lowercase()); + assert_eq!(strlen(in_0), strlen(raw.as_ptr())); + memcpy(in_0 as *mut _, raw.as_ptr() as *const _, strlen(in_0)); } pub unsafe fn dc_str_contains( @@ -233,7 +232,7 @@ pub unsafe fn dc_binary_to_uc_hex(buf: *const uint8_t, bytes: size_t) -> *mut li let buf = std::slice::from_raw_parts(buf, bytes); let raw = hex::encode_upper(buf); - to_cstring(raw) + raw.strdup() } /* remove all \r characters from string */ @@ -527,7 +526,7 @@ pub unsafe fn dc_str_from_clist( } } - to_cstring(res) + res.strdup() } pub unsafe fn dc_str_to_clist( @@ -1236,10 +1235,8 @@ pub unsafe fn dc_write_file( #[allow(non_snake_case)] pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef, buf: &[u8]) -> bool { let pathNfilename_abs = unsafe { - let n = to_cstring(pathNfilename.as_ref()); - let res = dc_get_abs_path(context, n); - free(n as *mut _); - res + let n = CString::yolo(pathNfilename.as_ref()); + dc_get_abs_path(context, n.as_ptr()) }; if pathNfilename_abs.is_null() { return false; @@ -1287,10 +1284,8 @@ pub unsafe fn dc_read_file( #[allow(non_snake_case)] pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef) -> Option> { let pathNfilename_abs = unsafe { - let n = to_cstring(pathNfilename.as_ref()); - let p = dc_get_abs_path(context, n); - free(n as *mut _); - p + let n = CString::yolo(pathNfilename.as_ref()); + dc_get_abs_path(context, n.as_ptr()) }; if pathNfilename_abs.is_null() { @@ -1523,6 +1518,51 @@ fn os_str_to_c_string_unicode( } } +/// Convenience methods/associated functions for working with [CString] +/// +/// This is helps transitioning from unsafe code. +pub trait CStringExt { + /// Create a new [CString], yolo style + /// + /// This unwrap the result, panicking when there are embedded NULL + /// bytes. + fn yolo>>(t: T) -> CString { + CString::new(t).expect("String contains null byte, can not be CString") + } +} + +impl CStringExt for CString {} + +/// Convenience methods to make transitioning from raw C strings easier. +/// +/// To interact with (legacy) C APIs we often need to convert from +/// Rust strings to raw C strings. This can be clumsy to do correctly +/// and the compiler sometimes allows it in an unsafe way. These +/// methods make it more succinct and help you get it right. +pub trait StrExt { + /// Allocate a new raw C `*char` version of this string. + /// + /// This allocates a new raw C string which must be freed using + /// `free`. It takes care of some common pitfalls with using + /// [CString::as_ptr]. + /// + /// [CString::as_ptr]: std::ffi::CString::as_ptr + /// + /// # Panics + /// + /// This function will panic when the original string contains an + /// interior null byte as this can not be represented in raw C + /// strings. + unsafe fn strdup(&self) -> *mut libc::c_char; +} + +impl> StrExt for T { + unsafe fn strdup(&self) -> *mut libc::c_char { + let tmp = CString::yolo(self.as_ref()); + dc_strdup(tmp.as_ptr()) + } +} + /// Needs to free the result after use! pub unsafe fn to_cstring>(s: S) -> *mut libc::c_char { let cstr = CString::new(s.as_ref()).expect("invalid string converted"); @@ -2085,4 +2125,29 @@ mod tests { let ptr = some_path.as_ptr(); assert_eq!(as_path_unicode(ptr), std::ffi::OsString::from("/some/path")); } + + #[test] + fn test_cstring_yolo() { + assert_eq!(CString::new("hello").unwrap(), CString::yolo("hello")); + } + + #[test] + fn test_strdup_str() { + unsafe { + let s = "hello".strdup(); + let cmp = strcmp(s, b"hello\x00" as *const u8 as *const libc::c_char); + free(s as *mut libc::c_void); + assert_eq!(cmp, 0); + } + } + + #[test] + fn test_strdup_string() { + unsafe { + let s = String::from("hello").strdup(); + let cmp = strcmp(s, b"hello\x00" as *const u8 as *const libc::c_char); + free(s as *mut libc::c_void); + assert_eq!(cmp, 0); + } + } } diff --git a/src/imap.rs b/src/imap.rs index 3d6336299..11a0a8bf8 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -1,3 +1,4 @@ +use std::ffi::CString; use std::net; use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::time::{Duration, SystemTime}; @@ -5,10 +6,9 @@ use std::time::{Duration, SystemTime}; use crate::constants::*; use crate::context::Context; use crate::dc_loginparam::*; -use crate::dc_tools::to_cstring; +use crate::dc_tools::CStringExt; use crate::oauth2::dc_get_oauth2_access_token; use crate::types::*; -use crate::x::free; pub const DC_IMAP_SEEN: usize = 0x0001; pub const DC_REGENERATE: usize = 0x01; @@ -843,10 +843,8 @@ impl Imap { .expect("missing message id"); if 0 == unsafe { - let message_id_c = to_cstring(message_id); - let res = (self.precheck_imf)(context, message_id_c, folder.as_ref(), cur_uid); - free(message_id_c as *mut _); - res + let message_id_c = CString::yolo(message_id); + (self.precheck_imf)(context, message_id_c.as_ptr(), folder.as_ref(), cur_uid) } { // check passed, go fetch the rest if self.fetch_single_msg(context, &folder, cur_uid) == 0 { diff --git a/src/log.rs b/src/log.rs index 6ab8c4702..e3605d09b 100644 --- a/src/log.rs +++ b/src/log.rs @@ -7,10 +7,9 @@ macro_rules! info { #[allow(unused_unsafe)] unsafe { let formatted = format!($msg, $($args),*); - let formatted_c = $crate::dc_tools::to_cstring(formatted); + let formatted_c = std::ffi::CString::new(formatted).unwrap(); $ctx.call_cb($crate::constants::Event::INFO, $data1 as libc::uintptr_t, - formatted_c as libc::uintptr_t); - libc::free(formatted_c as *mut libc::c_void); + formatted_c.as_ptr() as libc::uintptr_t); }}; } @@ -23,10 +22,9 @@ macro_rules! warn { #[allow(unused_unsafe)] unsafe { let formatted = format!($msg, $($args),*); - let formatted_c = $crate::dc_tools::to_cstring(formatted); + let formatted_c = std::ffi::CString::new(formatted).unwrap(); $ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t, - formatted_c as libc::uintptr_t); - libc::free(formatted_c as *mut libc::c_void) ; + formatted_c.as_ptr() as libc::uintptr_t); }}; } @@ -39,10 +37,9 @@ macro_rules! error { #[allow(unused_unsafe)] unsafe { let formatted = format!($msg, $($args),*); - let formatted_c = $crate::dc_tools::to_cstring(formatted); + let formatted_c = std::ffi::CString::new(formatted).unwrap(); $ctx.call_cb($crate::constants::Event::ERROR, $data1 as libc::uintptr_t, - formatted_c as libc::uintptr_t); - libc::free(formatted_c as *mut libc::c_void); + formatted_c.as_ptr() as libc::uintptr_t); }}; } @@ -55,9 +52,8 @@ macro_rules! log_event { #[allow(unused_unsafe)] unsafe { let formatted = format!($msg, $($args),*); - let formatted_c = $crate::dc_tools::to_cstring(formatted); + let formatted_c = std::ffi::CString::new(formatted).unwrap(); $ctx.call_cb($event, $data1 as libc::uintptr_t, - formatted_c as libc::uintptr_t); - libc::free(formatted_c as *mut libc::c_void); + formatted_c.as_ptr() as libc::uintptr_t); }}; } diff --git a/src/peerstate.rs b/src/peerstate.rs index b8f9b7724..d7f8009ab 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -462,13 +462,11 @@ mod tests { use super::*; use pretty_assertions::assert_eq; - use tempfile::{tempdir, TempDir}; - - use crate::context::*; + use tempfile::TempDir; #[test] fn test_peerstate_save_to_db() { - let ctx = unsafe { create_test_context() }; + let ctx = crate::test_utils::dummy_context(); let addr = "hello@mail.com"; let pub_key = crate::key::Key::from_base64("xsBNBFztUVkBCADYaQl/UOUpRPd32nLRzx8eU0eI+jQEnG+g5anjYA+3oct1rROGl5SygjMULDKdaUy27O3o9Srsti0YjA7uxZnavIqhSopJhFidqY1M1wA9JZa/duucZdNwUGbjGIRsS/4Cjr5+3svscK24hVYub1dvDWXpwUTnj3K6xOEnJdoM+MhCqtSD5+zcJhFc9vyZm9ZTGWUxAhKh0iJTcCD8V6CQ3XZ2z9GruwzZT/FTFovWrz7m3TUI2OdSSHh0eZLRGEoxMCT/vzflAFGAr8ijCaRsEIfqP6FW8uQWnFTqkjxEUCZG6XkeFHB84aj5jqYG/1KCLjL5vEKwfl1tz/WnPhY7ABEBAAHNEDxoZWxsb0BtYWlsLmNvbT7CwIkEEAEIADMCGQEFAlztUVoCGwMECwkIBwYVCAkKCwIDFgIBFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7ijAwf+PTsuawUax9cNPn1bN90H+g9qyHZJMEwKXtUnNaXJxPW3iB7ThhpCiCzsZwP7+l7ArS8tmLeNDw2bENtcf1XCv4wovP2fdXOP3QOUUFX/GdakcTwv7DzC7CO0grB1HtaPhGw/6UX2o2cx2i9xiUf4Givq2MfCbgAW5zloH6WXGPb6yLQYJXxqDIphr4+uZDb+bMAyWHN/DUkAjHrV8nnVki7PMHqzzZpwglalxMX8RGeiGZE39ALJKL/Og87DMFah87/yoxQWGoS7Wqv0XDcCPKoTCPrpk8pOe2KEsq/lz215nefHd4aRpfUX5YCYa8HPvvfPQbGF73uvyQw5w7qjis7ATQRc7VFZAQgAt8ONdnX6KEEQ5Jw6ilJ+LBtY44SP5t0I3eK+goKepgIiKhjGDa+Mntyi4jdhH+HO6kvK5SHMh2sPp4rRO/WKHJwWFySyM1OdyiywhyH0J9R5rBY4vPHsJjf6vSKJdWLWT+ho1fNet2IIC+jVCYli91MAMbRvk6EKVj1nCc+67giOahXEkHt6xxkeCGlOvbw8hxGj1A8+AC1BLms/OR3oc4JMi9O3kq6uG0z9tlUEerac9HVwcjoO1XLe+hJhoT5H+TbnGjPuhuURP3pFiIKHpbRYgUfdSAY0dTObO7t4I5y/drPOrCTnWrBUg2wXAECUhpRKow9/ai2YemLv9KqhhwARAQABwsB2BBgBCAAgBQJc7VFaAhsMFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7jmyggAhs4QzCzIbT2OsAReBxkxtm0AI+g1HZ1KFKof5NDHfgv9C/Qu1I8mKEjlZzA4qFyPmLqntgwJ0RuFy6gLbljZBNCFO7vB478AhYtnWjuKZmA40HUPwcB1hEJ31c42akzfUbioY1TLLepngdsJg7Cm8O+rhI9+1WRA66haJDgFs793SVUDyJh8f9NX50l5zR87/bsV30CFSw0q4OSSy9VI/z+2g5khn1LnuuOrCfFnYIPYtJED1BfkXkosxGlgbzy79VvGmI9d23x4atDK7oBPCzIj+lP8sytJ0u3HOguXi9OgDitKy+Pt1r8gH8frdktMJr5Ts6DW+tIn2vR23KR8aA==", KeyType::Public).unwrap(); @@ -506,26 +504,4 @@ mod tests { ctx: Context, dir: TempDir, } - - unsafe extern "C" fn cb( - _context: &Context, - _event: Event, - _data1: libc::uintptr_t, - _data2: libc::uintptr_t, - ) -> libc::uintptr_t { - 0 - } - - unsafe fn create_test_context() -> TestContext { - let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), None); - let dir = tempdir().unwrap(); - let dbfile = dir.path().join("db.sqlite"); - assert!( - dc_open(&mut ctx, dbfile.to_str().unwrap(), None), - "Failed to open {}", - dbfile.to_str().unwrap() - ); - - TestContext { ctx: ctx, dir: dir } - } } diff --git a/src/sql.rs b/src/sql.rs index 08382dc9e..2264e3c0e 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -10,7 +10,6 @@ use crate::dc_tools::*; use crate::error::{Error, Result}; use crate::param::*; use crate::peerstate::*; -use crate::x::*; const DC_OPEN_READONLY: usize = 0x01; @@ -1049,9 +1048,8 @@ pub fn housekeeping(context: &Context) { entry.file_name() ); unsafe { - let path = to_cstring(entry.path().to_str().unwrap()); - dc_delete_file(context, path); - free(path as *mut _); + let path = entry.path().to_c_string().unwrap(); + dc_delete_file(context, path.as_ptr()); } } } diff --git a/tests/stress.rs b/tests/stress.rs index c5a56f4f2..38c0723e3 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -671,7 +671,7 @@ fn test_encryption_decryption() { assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----")); let ctext_signed_bytes = ctext.len(); - let ctext_signed = to_cstring(ctext); + let ctext_signed = CString::yolo(ctext); let ctext = dc_pgp_pk_encrypt( original_text as *const libc::c_void, @@ -684,7 +684,7 @@ fn test_encryption_decryption() { assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----")); let ctext_unsigned_bytes = ctext.len(); - let ctext_unsigned = to_cstring(ctext); + let ctext_unsigned = CString::yolo(ctext); let mut keyring = Keyring::default(); keyring.add_owned(private_key); @@ -698,7 +698,7 @@ fn test_encryption_decryption() { let mut valid_signatures: HashSet = Default::default(); let plain = dc_pgp_pk_decrypt( - ctext_signed as *const _, + ctext_signed.as_ptr() as *const _, ctext_signed_bytes, &keyring, &public_keyring, @@ -713,7 +713,7 @@ fn test_encryption_decryption() { let empty_keyring = Keyring::default(); let plain = dc_pgp_pk_decrypt( - ctext_signed as *const _, + ctext_signed.as_ptr() as *const _, ctext_signed_bytes, &keyring, &empty_keyring, @@ -726,7 +726,7 @@ fn test_encryption_decryption() { valid_signatures.clear(); let plain = dc_pgp_pk_decrypt( - ctext_signed as *const _, + ctext_signed.as_ptr() as *const _, ctext_signed_bytes, &keyring, &public_keyring2, @@ -741,7 +741,7 @@ fn test_encryption_decryption() { public_keyring2.add_ref(&public_key); let plain = dc_pgp_pk_decrypt( - ctext_signed as *const _, + ctext_signed.as_ptr() as *const _, ctext_signed_bytes, &keyring, &public_keyring2, @@ -754,7 +754,7 @@ fn test_encryption_decryption() { valid_signatures.clear(); let plain = dc_pgp_pk_decrypt( - ctext_unsigned as *const _, + ctext_unsigned.as_ptr() as *const _, ctext_unsigned_bytes, &keyring, &public_keyring, @@ -762,7 +762,6 @@ fn test_encryption_decryption() { ) .unwrap(); - free(ctext_unsigned as *mut _); assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),); valid_signatures.clear(); @@ -773,7 +772,7 @@ fn test_encryption_decryption() { public_keyring.add_ref(&public_key); let plain = dc_pgp_pk_decrypt( - ctext_signed as *const _, + ctext_signed.as_ptr() as *const _, ctext_signed_bytes, &keyring, &public_keyring, @@ -781,7 +780,6 @@ fn test_encryption_decryption() { ) .unwrap(); - free(ctext_signed as *mut _); assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),); } } @@ -808,7 +806,7 @@ unsafe fn create_test_context() -> TestContext { assert!( dc_open(&mut ctx, dbfile.to_str().unwrap(), None), "Failed to open {}", - dbfile.to_str().unwrap() + dbfile.display() ); TestContext { ctx: ctx, dir: dir } } @@ -931,29 +929,24 @@ fn test_stress_tests() { fn test_get_contacts() { unsafe { let context = create_test_context(); - let name = to_cstring("some2"); - let contacts = dc_get_contacts(&context.ctx, 0, name); + let name = CString::yolo("some2"); + let contacts = dc_get_contacts(&context.ctx, 0, name.as_ptr()); assert_eq!(dc_array_get_cnt(contacts), 0); dc_array_unref(contacts); - free(name as *mut _); - let name = to_cstring("bob"); - let email = to_cstring("bob@mail.de"); - let id = dc_create_contact(&context.ctx, name, email); + let name = CString::yolo("bob"); + let email = CString::yolo("bob@mail.de"); + let id = dc_create_contact(&context.ctx, name.as_ptr(), email.as_ptr()); assert_ne!(id, 0); - let contacts = dc_get_contacts(&context.ctx, 0, name); + let contacts = dc_get_contacts(&context.ctx, 0, name.as_ptr()); assert_eq!(dc_array_get_cnt(contacts), 1); dc_array_unref(contacts); - let name2 = to_cstring("alice"); - let contacts = dc_get_contacts(&context.ctx, 0, name2); + let name2 = CString::yolo("alice"); + let contacts = dc_get_contacts(&context.ctx, 0, name2.as_ptr()); assert_eq!(dc_array_get_cnt(contacts), 0); dc_array_unref(contacts); - - free(name as *mut _); - free(name2 as *mut _); - free(email as *mut _); } } @@ -961,12 +954,10 @@ fn test_get_contacts() { fn test_chat() { unsafe { let context = create_test_context(); - let name = to_cstring("bob"); - let email = to_cstring("bob@mail.de"); + let name = CString::yolo("bob"); + let email = CString::yolo("bob@mail.de"); - let contact1 = dc_create_contact(&context.ctx, name, email); - free(name as *mut _); - free(email as *mut _); + let contact1 = dc_create_contact(&context.ctx, name.as_ptr(), email.as_ptr()); assert_ne!(contact1, 0); let chat_id = dc_create_chat_by_contact_id(&context.ctx, contact1); From a4f94dbf8638b3c39f6dfa34c673c4d2af527fac Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Thu, 1 Aug 2019 00:32:57 +0300 Subject: [PATCH 36/95] Store dc_mimeparser_t::parts as Vec instead of carray --- src/dc_mimeparser.rs | 246 +++++++++++++++++------------------------- src/dc_receive_imf.rs | 52 ++++----- tests/stress.rs | 2 +- 3 files changed, 124 insertions(+), 176 deletions(-) diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index 05c1bec43..89522d047 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -44,7 +44,7 @@ pub struct dc_mimepart_t { #[derive(Clone)] #[allow(non_camel_case_types)] pub struct dc_mimeparser_t<'a> { - pub parts: *mut carray, + pub parts: Vec, pub mimeroot: *mut mailmime, pub header: HashMap, pub header_root: *mut mailimf_fields, @@ -71,7 +71,7 @@ static mut S_GENERATE_COMPOUND_MSGS: libc::c_int = 1i32; pub unsafe fn dc_mimeparser_new(context: &Context) -> dc_mimeparser_t { dc_mimeparser_t { - parts: carray_new(16i32 as libc::c_uint), + parts: Vec::new(), mimeroot: std::ptr::null_mut(), header: Default::default(), header_root: std::ptr::null_mut(), @@ -91,25 +91,13 @@ pub unsafe fn dc_mimeparser_new(context: &Context) -> dc_mimeparser_t { pub unsafe fn dc_mimeparser_unref(mimeparser: &mut dc_mimeparser_t) { dc_mimeparser_empty(mimeparser); - if !(*mimeparser).parts.is_null() { - carray_free((*mimeparser).parts); - } } pub unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) { - if !(*mimeparser).parts.is_null() { - let mut i: libc::c_int; - let cnt: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int; - i = 0i32; - while i < cnt { - let part = carray_get((*mimeparser).parts, i as libc::c_uint) as *mut dc_mimepart_t; - if !part.is_null() { - dc_mimepart_unref(*Box::from_raw(part)); - } - i += 1 - } - carray_set_size((*mimeparser).parts, 0i32 as libc::c_uint); + for part in mimeparser.parts.drain(..) { + dc_mimepart_unref(part); } + assert!(mimeparser.parts.is_empty()); (*mimeparser).header_root = 0 as *mut mailimf_fields; (*mimeparser).header.clear(); if !(*mimeparser).header_protected.is_null() { @@ -183,29 +171,34 @@ pub unsafe fn dc_mimeparser_parse( (*mimeparser).is_send_by_messenger = 1i32 } if !dc_mimeparser_lookup_field(mimeparser, "Autocrypt-Setup-Message").is_null() { - let mut i: libc::c_int; let mut has_setup_file: libc::c_int = 0i32; - i = 0i32; - while (i as libc::c_uint) < carray_count((*mimeparser).parts) { - let part: *mut dc_mimepart_t = - carray_get((*mimeparser).parts, i as libc::c_uint) as *mut dc_mimepart_t; - if (*part).int_mimetype == 111i32 { + for part in &mimeparser.parts { + if part.int_mimetype == 111i32 { has_setup_file = 1i32 } - i += 1 } if 0 != has_setup_file { - (*mimeparser).is_system_message = 6i32; - i = 0i32; - while (i as libc::c_uint) < carray_count((*mimeparser).parts) { - let part_0 = - carray_get((*mimeparser).parts, i as libc::c_uint) as *mut dc_mimepart_t; - if (*part_0).int_mimetype != 111i32 { - dc_mimepart_unref(*Box::from_raw(part_0)); - carray_delete_slow((*mimeparser).parts, i as libc::c_uint); - i -= 1 + mimeparser.is_system_message = 6i32; + + // TODO: replace the following code with this + // once drain_filter stabilizes. + // + // See https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter + // and https://github.com/rust-lang/rust/issues/43244 + // + // mimeparser + // .parts + // .drain_filter(|part| part.int_mimetype != 111) + // .for_each(|part| dc_mimepart_unref(part)); + + let mut i = 0; + while i != mimeparser.parts.len() { + if mimeparser.parts[i].int_mimetype != 111 { + let part = mimeparser.parts.remove(i); + dc_mimepart_unref(part); + } else { + i += 1; } - i += 1 } } } else { @@ -224,40 +217,42 @@ pub unsafe fn dc_mimeparser_parse( } } if !dc_mimeparser_lookup_field(mimeparser, "Chat-Group-Image").is_null() - && carray_count((*mimeparser).parts) >= 1i32 as libc::c_uint + && !mimeparser.parts.is_empty() { - let textpart: *mut dc_mimepart_t = - carray_get((*mimeparser).parts, 0i32 as libc::c_uint) as *mut dc_mimepart_t; - if (*textpart).type_0 == 10i32 { - if carray_count((*mimeparser).parts) >= 2i32 as libc::c_uint { - let mut imgpart: *mut dc_mimepart_t = - carray_get((*mimeparser).parts, 1i32 as libc::c_uint) as *mut dc_mimepart_t; - if (*imgpart).type_0 == 20i32 { - (*imgpart).is_meta = 1i32 + let textpart = &mimeparser.parts[0]; + if textpart.type_0 == 10i32 { + if mimeparser.parts.len() >= 2 { + let imgpart = &mut mimeparser.parts[1]; + if imgpart.type_0 == 20i32 { + imgpart.is_meta = 1i32 } } } } if 0 != (*mimeparser).is_send_by_messenger && 0 != S_GENERATE_COMPOUND_MSGS - && carray_count((*mimeparser).parts) == 2i32 as libc::c_uint + && mimeparser.parts.len() == 2 { - let mut textpart_0 = carray_get((*mimeparser).parts, 0) as *mut dc_mimepart_t; - let mut filepart = carray_get((*mimeparser).parts, 1) as *mut dc_mimepart_t; - if (*textpart_0).type_0 == 10i32 - && ((*filepart).type_0 == 20i32 - || (*filepart).type_0 == 21i32 - || (*filepart).type_0 == 40i32 - || (*filepart).type_0 == 41i32 - || (*filepart).type_0 == 50i32 - || (*filepart).type_0 == 60i32) - && 0 == (*filepart).is_meta + let need_drop: bool; { - free((*filepart).msg as *mut libc::c_void); - (*filepart).msg = (*textpart_0).msg; - (*textpart_0).msg = 0 as *mut libc::c_char; - dc_mimepart_unref(*Box::from_raw(textpart_0)); - carray_delete_slow((*mimeparser).parts, 0i32 as libc::c_uint); + let textpart = &mimeparser.parts[0]; + let filepart = &mimeparser.parts[1]; + need_drop = textpart.type_0 == 10i32 + && (filepart.type_0 == 20i32 + || filepart.type_0 == 21i32 + || filepart.type_0 == 40i32 + || filepart.type_0 == 41i32 + || filepart.type_0 == 50i32 + || filepart.type_0 == 60i32) + && 0 == filepart.is_meta; + } + + if need_drop { + free(mimeparser.parts[1].msg as *mut libc::c_void); + let mut textpart = mimeparser.parts.swap_remove(0); + mimeparser.parts[1].msg = textpart.msg; + textpart.msg = 0 as *mut libc::c_char; + dc_mimepart_unref(textpart); } } if !(*mimeparser).subject.is_null() { @@ -284,24 +279,16 @@ pub unsafe fn dc_mimeparser_parse( } dc_trim(subj); if 0 != *subj.offset(0isize) { - let mut i_0: libc::c_int; - let icnt: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int; - i_0 = 0i32; - while i_0 < icnt { - let mut part_1: *mut dc_mimepart_t = - carray_get((*mimeparser).parts, i_0 as libc::c_uint) - as *mut dc_mimepart_t; - if (*part_1).type_0 == 10i32 { + for part in mimeparser.parts.iter_mut() { + if part.type_0 == 10i32 { let new_txt: *mut libc::c_char = dc_mprintf( b"%s \xe2\x80\x93 %s\x00" as *const u8 as *const libc::c_char, subj, - (*part_1).msg, + part.msg, ); - free((*part_1).msg as *mut libc::c_void); - (*part_1).msg = new_txt; + free(part.msg as *mut libc::c_void); + part.msg = new_txt; break; - } else { - i_0 += 1 } } } @@ -309,30 +296,24 @@ pub unsafe fn dc_mimeparser_parse( } } if 0 != (*mimeparser).is_forwarded { - let mut i_1: libc::c_int; - let icnt_0: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int; - i_1 = 0i32; - while i_1 < icnt_0 { - let part_2 = - carray_get((*mimeparser).parts, i_1 as libc::c_uint) as *mut dc_mimepart_t; - (*part_2).param.set_int(Param::Forwarded, 1); - i_1 += 1 + for part in mimeparser.parts.iter_mut() { + part.param.set_int(Param::Forwarded, 1); } } - if carray_count((*mimeparser).parts) == 1i32 as libc::c_uint { - let mut part_3: *mut dc_mimepart_t = - carray_get((*mimeparser).parts, 0i32 as libc::c_uint) as *mut dc_mimepart_t; - if (*part_3).type_0 == 40i32 { + if mimeparser.parts.len() == 1 { + if mimeparser.parts[0].type_0 == 40i32 { if !dc_mimeparser_lookup_optional_field( mimeparser, b"Chat-Voice-Message\x00" as *const u8 as *const libc::c_char, ) .is_null() { - (*part_3).type_0 = 41i32 + let part_mut = &mut mimeparser.parts[0]; + part_mut.type_0 = 41i32 } } - if (*part_3).type_0 == 40i32 || (*part_3).type_0 == 41i32 || (*part_3).type_0 == 50i32 { + let part = &mimeparser.parts[0]; + if part.type_0 == 40i32 || part.type_0 == 41i32 || part.type_0 == 50i32 { let field_0 = dc_mimeparser_lookup_optional_field( mimeparser, b"Chat-Duration\x00" as *const u8 as *const libc::c_char, @@ -340,7 +321,8 @@ pub unsafe fn dc_mimeparser_parse( if !field_0.is_null() { let duration_ms: libc::c_int = dc_atoi_null_is_0((*field_0).fld_value); if duration_ms > 0i32 && duration_ms < 24i32 * 60i32 * 60i32 * 1000i32 { - (*part_3).param.set_int(Param::Duration, duration_ms); + let part_mut = &mut mimeparser.parts[0]; + part_mut.param.set_int(Param::Duration, duration_ms); } } } @@ -350,7 +332,7 @@ pub unsafe fn dc_mimeparser_parse( mimeparser, b"Chat-Disposition-Notification-To\x00" as *const u8 as *const libc::c_char, ); - if !dn_field.is_null() && !dc_mimeparser_get_last_nonmeta(mimeparser).is_null() { + if !dn_field.is_null() && dc_mimeparser_get_last_nonmeta(mimeparser).is_some() { let mut mb_list: *mut mailimf_mailbox_list = 0 as *mut mailimf_mailbox_list; let mut index_0: size_t = 0i32 as size_t; if mailimf_mailbox_list_parse( @@ -374,10 +356,9 @@ pub unsafe fn dc_mimeparser_parse( ); if !from_addr.is_null() { if strcmp(from_addr, dn_to_addr) == 0i32 { - let part_4: *mut dc_mimepart_t = - dc_mimeparser_get_last_nonmeta(mimeparser); - if !part_4.is_null() { - (*part_4).param.set_int(Param::WantsMdn, 1); + if let Some(part_4) = dc_mimeparser_get_last_nonmeta(mimeparser) + { + part_4.param.set_int(Param::WantsMdn, 1); } } free(from_addr as *mut libc::c_void); @@ -391,7 +372,7 @@ pub unsafe fn dc_mimeparser_parse( } } /* Cleanup - and try to create at least an empty part if there are no parts yet */ - if dc_mimeparser_get_last_nonmeta(mimeparser).is_null() && (*mimeparser).reports.is_empty() { + if dc_mimeparser_get_last_nonmeta(mimeparser).is_none() && (*mimeparser).reports.is_empty() { let mut part_5 = dc_mimepart_new(); part_5.type_0 = 10i32; if !(*mimeparser).subject.is_null() && 0 == (*mimeparser).is_send_by_messenger { @@ -399,11 +380,7 @@ pub unsafe fn dc_mimeparser_parse( } else { part_5.msg = dc_strdup(b"\x00" as *const u8 as *const libc::c_char) } - carray_add( - (*mimeparser).parts, - Box::into_raw(Box::new(part_5)) as *mut libc::c_void, - 0 as *mut libc::c_uint, - ); + mimeparser.parts.push(part_5); }; } @@ -422,22 +399,14 @@ unsafe fn dc_mimepart_new() -> dc_mimepart_t { } } -pub unsafe fn dc_mimeparser_get_last_nonmeta(mimeparser: &dc_mimeparser_t) -> *mut dc_mimepart_t { - if !(*mimeparser).parts.is_null() { - let mut i: libc::c_int; - let icnt: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int; - i = icnt - 1i32; - while i >= 0i32 { - let part: *mut dc_mimepart_t = - carray_get(mimeparser.parts, i as libc::c_uint) as *mut dc_mimepart_t; - if !part.is_null() && 0 == (*part).is_meta { - return part; - } - i -= 1 - } - } - - 0 as *mut dc_mimepart_t +pub fn dc_mimeparser_get_last_nonmeta<'a>( + mimeparser: &'a mut dc_mimeparser_t, +) -> Option<&'a mut dc_mimepart_t> { + mimeparser + .parts + .iter_mut() + .rev() + .find(|part| part.is_meta == 0) } /*the result must be freed*/ @@ -664,11 +633,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive( msg_body.as_ptr(), ); part.msg_raw = dc_strdup(part.msg); - carray_add( - (*mimeparser).parts, - Box::into_raw(Box::new(part)) as *mut libc::c_void, - 0 as *mut libc::c_uint, - ); + mimeparser.parts.push(part); any_part_added = 1i32; (*mimeparser).decrypting_failed = 1i32 } @@ -1125,7 +1090,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known( mime: *mut mailmime, ) -> libc::c_int { let mut current_block: u64; - let old_part_count: libc::c_int = carray_count(mimeparser.parts) as libc::c_int; + let old_part_count = mimeparser.parts.len(); let mime_type: libc::c_int; let mime_data: *mut mailmime_data; let file_suffix: *mut libc::c_char = 0 as *mut libc::c_char; @@ -1418,16 +1383,16 @@ unsafe fn dc_mimeparser_add_single_part_if_known( free(file_suffix as *mut libc::c_void); free(desired_filename as *mut libc::c_void); free(raw_mime as *mut libc::c_void); - return if carray_count((*mimeparser).parts) > old_part_count as libc::c_uint { - 1i32 + return if mimeparser.parts.len() > old_part_count { + 1 } else { - 0i32 + 0 }; } #[allow(non_snake_case)] unsafe fn do_add_single_file_part( - parser: &dc_mimeparser_t, + parser: &mut dc_mimeparser_t, msg_type: libc::c_int, mime_type: libc::c_int, raw_mime: *const libc::c_char, @@ -1476,17 +1441,13 @@ unsafe fn do_add_single_file_part( free(pathNfilename as *mut libc::c_void); } -unsafe fn do_add_single_part(parser: &dc_mimeparser_t, mut part: dc_mimepart_t) { +unsafe fn do_add_single_part(parser: &mut dc_mimeparser_t, mut part: dc_mimepart_t) { if 0 != (*parser).e2ee_helper.encrypted && (*parser).e2ee_helper.signatures.len() > 0 { part.param.set_int(Param::GuranteeE2ee, 1); } else if 0 != (*parser).e2ee_helper.encrypted { part.param.set_int(Param::ErroneousE2ee, 0x2); } - carray_add( - (*parser).parts, - Box::into_raw(Box::new(part)) as *mut libc::c_void, - 0 as *mut libc::c_uint, - ); + parser.parts.push(part); } // TODO should return bool /rtn @@ -1773,27 +1734,20 @@ pub unsafe fn mailimf_find_field( } pub unsafe fn dc_mimeparser_repl_msg_by_error( - mimeparser: &dc_mimeparser_t, + mimeparser: &mut dc_mimeparser_t, error_msg: *const libc::c_char, ) { - let mut part: *mut dc_mimepart_t; - let mut i: libc::c_int; - if (*mimeparser).parts.is_null() || carray_count((*mimeparser).parts) <= 0i32 as libc::c_uint { + if mimeparser.parts.is_empty() { return; } - part = carray_get((*mimeparser).parts, 0i32 as libc::c_uint) as *mut dc_mimepart_t; - (*part).type_0 = 10i32; - free((*part).msg as *mut libc::c_void); - (*part).msg = dc_mprintf(b"[%s]\x00" as *const u8 as *const libc::c_char, error_msg); - i = 1i32; - while (i as libc::c_uint) < carray_count((*mimeparser).parts) { - part = carray_get((*mimeparser).parts, i as libc::c_uint) as *mut dc_mimepart_t; - if !part.is_null() { - dc_mimepart_unref(*Box::from_raw(part)); - } - i += 1 + let part = &mut mimeparser.parts[0]; + part.type_0 = 10i32; + free(part.msg as *mut libc::c_void); + part.msg = dc_mprintf(b"[%s]\x00" as *const u8 as *const libc::c_char, error_msg); + for part in mimeparser.parts.drain(1..) { + dc_mimepart_unref(part); } - carray_set_size((*mimeparser).parts, 1i32 as libc::c_uint); + assert_eq!(mimeparser.parts.len(), 1); } /*the result is a pointer to mime, must not be freed*/ diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index cde7c3615..606ab43de 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -138,7 +138,7 @@ pub unsafe fn dc_receive_imf( ); } } - if !dc_mimeparser_get_last_nonmeta(&mime_parser).is_null() { + if dc_mimeparser_get_last_nonmeta(&mut mime_parser).is_some() { field = dc_mimeparser_lookup_field(&mime_parser, "Cc"); if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_CC as libc::c_int { let fld_cc: *mut mailimf_cc = (*field).fld_data.fld_cc; @@ -435,7 +435,7 @@ pub unsafe fn dc_receive_imf( ) } } - let icnt = carray_count(mime_parser.parts) as size_t; + let icnt = mime_parser.parts.len(); context.sql.prepare( "INSERT INTO msgs \ @@ -450,23 +450,23 @@ pub unsafe fn dc_receive_imf( current_block = 2756754640271984560; break; } - let part = carray_get(mime_parser.parts, i as libc::c_uint) as *mut dc_mimepart_t; - if !(0 != (*part).is_meta) { + let part = &mut mime_parser.parts[i]; + if part.is_meta == 0 { if !mime_parser.location_kml.is_none() && icnt == 1 - && !(*part).msg.is_null() + && !part.msg.is_null() && (strcmp( - (*part).msg, + part.msg, b"-location-\x00" as *const u8 as *const libc::c_char, ) == 0 - || *(*part).msg.offset(0isize) as libc::c_int == 0) + || *part.msg.offset(0isize) as libc::c_int == 0) { hidden = 1; if state == 10 { state = 13 } } - if (*part).type_0 == 10 { + if part.type_0 == 10 { txt_raw = dc_mprintf( b"%s\n\n%s\x00" as *const u8 as *const libc::c_char, if !mime_parser.subject.is_null() { @@ -474,12 +474,12 @@ pub unsafe fn dc_receive_imf( } else { b"\x00" as *const u8 as *const libc::c_char }, - (*part).msg_raw, + part.msg_raw, ) } if 0 != mime_parser.is_system_message { - (*part).param.set_int( Param::Cmd, + part.param.set_int( Param::Cmd, mime_parser.is_system_message, ); } @@ -494,11 +494,11 @@ pub unsafe fn dc_receive_imf( sort_timestamp, sent_timestamp, rcvd_timestamp, - (*part).type_0, + part.type_0, state, msgrmsg, - if !(*part).msg.is_null() { - as_str((*part).msg) + if !part.msg.is_null() { + as_str(part.msg) } else { "" }, @@ -508,8 +508,8 @@ pub unsafe fn dc_receive_imf( } else { String::new() }, - (*part).param.to_string(), - (*part).bytes, + part.param.to_string(), + part.bytes, hidden, if 0 != save_mime_headers { let body_string = std::str::from_utf8(std::slice::from_raw_parts(imf_raw_not_terminated as *const u8, imf_raw_bytes)).unwrap(); @@ -1201,20 +1201,15 @@ unsafe fn create_or_lookup_group( { ok = 1 } else { - let mut i_0: libc::c_int = 0; - while (i_0 as libc::c_uint) < carray_count(mime_parser.parts) { - let part: *mut dc_mimepart_t = - carray_get(mime_parser.parts, i_0 as libc::c_uint) - as *mut dc_mimepart_t; - if (*part).type_0 == 20 { - grpimage = (*part) + for part in &mut mime_parser.parts { + if part.type_0 == 20 { + grpimage = part .param .get(Param::File) .map(|s| s.strdup()) .unwrap_or_else(|| std::ptr::null_mut()); ok = 1 } - i_0 += 1 } } if 0 != ok { @@ -1709,14 +1704,13 @@ unsafe fn check_verified_properties( 1 } -unsafe fn set_better_msg>(mime_parser: &dc_mimeparser_t, better_msg: T) { +unsafe fn set_better_msg>(mime_parser: &mut dc_mimeparser_t, better_msg: T) { let msg = better_msg.as_ref(); - if !(msg.len() > 0) && carray_count((*mime_parser).parts) > 0 { - let mut part: *mut dc_mimepart_t = - carray_get(mime_parser.parts, 0 as libc::c_uint) as *mut dc_mimepart_t; + if !(msg.len() > 0) && !mime_parser.parts.is_empty() { + let part = &mut mime_parser.parts[0]; if (*part).type_0 == 10 { - free((*part).msg as *mut libc::c_void); - (*part).msg = msg.strdup(); + free(part.msg as *mut libc::c_void); + part.msg = msg.strdup(); } }; } diff --git a/tests/stress.rs b/tests/stress.rs index 38c0723e3..f0530e093 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -881,7 +881,7 @@ fn test_dc_mimeparser_with_context() { b"Chat-Version\x00" as *const u8 as *const libc::c_char, ); assert_eq!(as_str((*of).fld_value as *const libc::c_char), "1.0",); - assert_eq!(carray_count(mimeparser.parts), 1); + assert_eq!(mimeparser.parts.len(), 1); dc_mimeparser_unref(&mut mimeparser); } From 1145c3533b814ed3892052b05f05869b9a13b9f9 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 2 Aug 2019 01:34:02 +0300 Subject: [PATCH 37/95] Use Vec instead of carray in dc_forward_msgs() --- src/dc_chat.rs | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/dc_chat.rs b/src/dc_chat.rs index 23b5956dd..c8c0d8a14 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -1973,7 +1973,7 @@ pub unsafe fn dc_forward_msgs( let msg = dc_msg_new_untyped(context); let chat = dc_chat_new(context); let contact = dc_contact_new(context); - let created_db_entries = carray_new(16); + let mut created_db_entries = Vec::new(); let mut curr_timestamp: i64; dc_unarchive_chat(context, chat_id); @@ -2040,31 +2040,17 @@ pub unsafe fn dc_forward_msgs( new_msg_id = prepare_msg_raw(context, chat, msg, fresh10); dc_job_send_msg(context, new_msg_id); } - carray_add( - created_db_entries, - chat_id as uintptr_t as *mut libc::c_void, - 0 as *mut libc::c_uint, - ); - carray_add( - created_db_entries, - new_msg_id as uintptr_t as *mut libc::c_void, - 0 as *mut libc::c_uint, - ); + created_db_entries.push(chat_id); + created_db_entries.push(new_msg_id); } } - if !created_db_entries.is_null() { - let mut i = 0u32; - let icnt = carray_count(created_db_entries); - while i < icnt { - context.call_cb( - Event::MSGS_CHANGED, - carray_get(created_db_entries, i) as uintptr_t, - carray_get(created_db_entries, i.wrapping_add(1)) as uintptr_t, - ); - i = i.wrapping_add(2); - } - carray_free(created_db_entries); + for i in (0..created_db_entries.len()).step_by(2) { + context.call_cb( + Event::MSGS_CHANGED, + created_db_entries[i] as uintptr_t, + created_db_entries[i + 1] as uintptr_t, + ); } dc_contact_unref(contact); dc_msg_unref(msg); From e78b879c9e5817a3c5875da603ed2d18dd8c23b4 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 2 Aug 2019 09:29:40 +0300 Subject: [PATCH 38/95] Remove unused function dc_simplify_simplify --- src/dc_simplify.rs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/dc_simplify.rs b/src/dc_simplify.rs index a95af733b..49896e373 100644 --- a/src/dc_simplify.rs +++ b/src/dc_simplify.rs @@ -20,6 +20,9 @@ impl dc_simplify_t { } } + /// Simplify and normalise text: Remove quotes, signatures, unnecessary + /// lineends etc. + /// The data returned from simplify() must be free()'d when no longer used. pub unsafe fn simplify( &mut self, in_unterminated: *const libc::c_char, @@ -233,22 +236,6 @@ impl dc_simplify_t { } } -/* Simplify and normalise text: Remove quotes, signatures, unnecessary -lineends etc. -The data returned from Simplify() must be free()'d when no longer used, private */ -pub unsafe fn dc_simplify_simplify( - simplify: *mut dc_simplify_t, - in_unterminated: *const libc::c_char, - in_bytes: libc::c_int, - is_html: libc::c_int, - is_msgrmsg: libc::c_int, -) -> *mut libc::c_char { - if simplify.is_null() || in_unterminated.is_null() || in_bytes <= 0i32 { - return dc_strdup(b"\x00" as *const u8 as *const libc::c_char); - } - (*simplify).simplify(in_unterminated, in_bytes, is_html, is_msgrmsg) -} - /** * Tools */ From d64fcece5bcd0e572631de412f2208bcb129e6c1 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 2 Aug 2019 00:28:40 +0300 Subject: [PATCH 39/95] Return Vec instead of carray from dc_split_into_lines --- src/dc_contact.rs | 43 +++++++++------------- src/dc_qr.rs | 8 ++--- src/dc_simplify.rs | 88 ++++++++++++++++++---------------------------- src/dc_tools.rs | 35 +++++------------- 4 files changed, 62 insertions(+), 112 deletions(-) diff --git a/src/dc_contact.rs b/src/dc_contact.rs index 3b5b5b0d4..8e58af568 100644 --- a/src/dc_contact.rs +++ b/src/dc_contact.rs @@ -455,38 +455,29 @@ pub fn dc_add_or_lookup_contact( #[allow(non_snake_case)] pub unsafe fn dc_add_address_book(context: &Context, adr_book: *const libc::c_char) -> libc::c_int { - let mut lines: *mut carray = 0 as *mut carray; - let mut i: size_t; - let iCnt: size_t; let mut sth_modified: libc::c_int = 0i32; let mut modify_cnt: libc::c_int = 0i32; if !(adr_book.is_null()) { - lines = dc_split_into_lines(adr_book); - if !lines.is_null() { - iCnt = carray_count(lines) as size_t; - i = 0i32 as size_t; - while i.wrapping_add(1) < iCnt { - let name: *mut libc::c_char = - carray_get(lines, i as libc::c_uint) as *mut libc::c_char; - let addr: *mut libc::c_char = - carray_get(lines, i.wrapping_add(1) as libc::c_uint) as *mut libc::c_char; - dc_normalize_name(name); - dc_add_or_lookup_contact(context, name, addr, 0x80000i32, &mut sth_modified); - if 0 != sth_modified { - modify_cnt += 1 - } - i = (i as libc::c_ulong).wrapping_add(2i32 as libc::c_ulong) as size_t as size_t - } - if 0 != modify_cnt { - context.call_cb( - Event::CONTACTS_CHANGED, - 0i32 as uintptr_t, - 0i32 as uintptr_t, - ); + let lines = dc_split_into_lines(adr_book); + + for chunk in lines.chunks(2) { + let name: *mut libc::c_char = chunk[0]; + let addr: *mut libc::c_char = chunk[1]; + dc_normalize_name(name); + dc_add_or_lookup_contact(context, name, addr, 0x80000i32, &mut sth_modified); + if 0 != sth_modified { + modify_cnt += 1 } } + if 0 != modify_cnt { + context.call_cb( + Event::CONTACTS_CHANGED, + 0i32 as uintptr_t, + 0i32 as uintptr_t, + ); + } + dc_free_splitted_lines(lines); } - dc_free_splitted_lines(lines); modify_cnt } diff --git a/src/dc_qr.rs b/src/dc_qr.rs index 5541cd3a4..b216822a4 100644 --- a/src/dc_qr.rs +++ b/src/dc_qr.rs @@ -152,11 +152,8 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc strlen(b"BEGIN:VCARD\x00" as *const u8 as *const libc::c_char), ) == 0i32 { - let lines: *mut carray = dc_split_into_lines(qr); - let mut i: libc::c_int = 0i32; - while (i as libc::c_uint) < carray_count(lines) { - let key: *mut libc::c_char = - carray_get(lines, i as libc::c_uint) as *mut libc::c_char; + let lines = dc_split_into_lines(qr); + for &key in &lines { dc_trim(key); let mut value: *mut libc::c_char = strchr(key, ':' as i32); if !value.is_null() { @@ -192,7 +189,6 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc dc_normalize_name(name); } } - i += 1 } dc_free_splitted_lines(lines); } diff --git a/src/dc_simplify.rs b/src/dc_simplify.rs index 49896e373..bca7a7fe5 100644 --- a/src/dc_simplify.rs +++ b/src/dc_simplify.rs @@ -1,6 +1,5 @@ use crate::dc_dehtml::*; use crate::dc_tools::*; -use crate::types::*; use crate::x::*; #[derive(Copy, Clone)] @@ -76,17 +75,13 @@ impl dc_simplify_t { these are all lines starting with the character `>` ... remove a non-empty line before the removed quote (contains sth. like "On 2.9.2016, Bjoern wrote:" in different formats and lanugages) */ /* split the given buffer into lines */ - let lines: *mut carray = dc_split_into_lines(buf_terminated); - let mut l: libc::c_int; - let mut l_first: libc::c_int = 0i32; - /* if l_last is -1, there are no lines */ - let mut l_last: libc::c_int = - carray_count(lines).wrapping_sub(1i32 as libc::c_uint) as libc::c_int; + let lines = dc_split_into_lines(buf_terminated); + let mut l_first: usize = 0; + let mut l_last = lines.len(); let mut line: *mut libc::c_char; let mut footer_mark: libc::c_int = 0i32; - l = l_first; - while l <= l_last { - line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char; + for l in l_first..l_last { + line = lines[l]; if strcmp(line, b"-- \x00" as *const u8 as *const libc::c_char) == 0i32 || strcmp(line, b"-- \x00" as *const u8 as *const libc::c_char) == 0i32 { @@ -100,20 +95,15 @@ impl dc_simplify_t { self.is_cut_at_end = 1i32 } if 0 != footer_mark { - l_last = l - 1i32; + l_last = l; /* done */ break; - } else { - l += 1 } } - if l_last - l_first + 1i32 >= 3i32 { - let line0: *mut libc::c_char = - carray_get(lines, l_first as libc::c_uint) as *mut libc::c_char; - let line1: *mut libc::c_char = - carray_get(lines, (l_first + 1i32) as libc::c_uint) as *mut libc::c_char; - let line2: *mut libc::c_char = - carray_get(lines, (l_first + 2i32) as libc::c_uint) as *mut libc::c_char; + if l_last > l_first + 2 { + let line0: *mut libc::c_char = lines[l_first]; + let line1: *mut libc::c_char = lines[l_first + 1]; + let line2: *mut libc::c_char = lines[l_first + 2]; if strcmp( line0, b"---------- Forwarded message ----------\x00" as *const u8 as *const libc::c_char, @@ -122,49 +112,43 @@ impl dc_simplify_t { && *line2.offset(0isize) as libc::c_int == 0i32 { self.is_forwarded = 1i32; - l_first += 3i32 + l_first += 3 } } - l = l_first; - while l <= l_last { - line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char; + for l in l_first..l_last { + line = lines[l]; if strncmp(line, b"-----\x00" as *const u8 as *const libc::c_char, 5) == 0i32 || strncmp(line, b"_____\x00" as *const u8 as *const libc::c_char, 5) == 0i32 || strncmp(line, b"=====\x00" as *const u8 as *const libc::c_char, 5) == 0i32 || strncmp(line, b"*****\x00" as *const u8 as *const libc::c_char, 5) == 0i32 || strncmp(line, b"~~~~~\x00" as *const u8 as *const libc::c_char, 5) == 0i32 { - l_last = l - 1i32; + l_last = l; self.is_cut_at_end = 1i32; /* done */ break; - } else { - l += 1 } } if 0 == is_msgrmsg { - let mut l_lastQuotedLine: libc::c_int = -1i32; - l = l_last; - while l >= l_first { - line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char; + let mut l_lastQuotedLine = None; + for l in (l_first..l_last).rev() { + line = lines[l]; if is_plain_quote(line) { - l_lastQuotedLine = l + l_lastQuotedLine = Some(l) } else if !is_empty_line(line) { break; } - l -= 1 } - if l_lastQuotedLine != -1i32 { - l_last = l_lastQuotedLine - 1i32; + if l_lastQuotedLine.is_some() { + l_last = l_lastQuotedLine.unwrap(); self.is_cut_at_end = 1i32; - if l_last > 0i32 { - if is_empty_line(carray_get(lines, l_last as libc::c_uint) as *mut libc::c_char) - { + if l_last > 1 { + if is_empty_line(lines[l_last - 1]) { l_last -= 1 } } - if l_last > 0i32 { - line = carray_get(lines, l_last as libc::c_uint) as *mut libc::c_char; + if l_last > 1 { + line = lines[l_last - 1]; if is_quoted_headline(line) { l_last -= 1 } @@ -172,17 +156,16 @@ impl dc_simplify_t { } } if 0 == is_msgrmsg { - let mut l_lastQuotedLine_0: libc::c_int = -1i32; - let mut hasQuotedHeadline: libc::c_int = 0i32; - l = l_first; - while l <= l_last { - line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char; + let mut l_lastQuotedLine_0 = None; + let mut hasQuotedHeadline = 0; + for l in l_first..l_last { + line = lines[l]; if is_plain_quote(line) { - l_lastQuotedLine_0 = l + l_lastQuotedLine_0 = Some(l) } else if !is_empty_line(line) { if is_quoted_headline(line) && 0 == hasQuotedHeadline - && l_lastQuotedLine_0 == -1i32 + && l_lastQuotedLine_0.is_none() { hasQuotedHeadline = 1i32 } else { @@ -190,10 +173,9 @@ impl dc_simplify_t { break; } } - l += 1 } - if l_lastQuotedLine_0 != -1i32 { - l_first = l_lastQuotedLine_0 + 1i32; + if l_lastQuotedLine_0.is_some() { + l_first = l_lastQuotedLine_0.unwrap() + 1; self.is_cut_at_begin = 1i32 } } @@ -205,9 +187,8 @@ impl dc_simplify_t { /* we write empty lines only in case and non-empty line follows */ let mut pending_linebreaks: libc::c_int = 0i32; let mut content_lines_added: libc::c_int = 0i32; - l = l_first; - while l <= l_last { - line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char; + for l in l_first..l_last { + line = lines[l]; if is_empty_line(line) { pending_linebreaks += 1 } else { @@ -225,7 +206,6 @@ impl dc_simplify_t { content_lines_added += 1; pending_linebreaks = 1i32 } - l += 1 } if 0 != self.is_cut_at_end && (0 == self.is_cut_at_begin || 0 != content_lines_added) { ret += " [...]"; diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 5003febc1..41802a73e 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -417,47 +417,30 @@ unsafe fn dc_utf8_strnlen(s: *const libc::c_char, n: size_t) -> size_t { } /* split string into lines*/ -pub unsafe fn dc_split_into_lines(buf_terminated: *const libc::c_char) -> *mut carray { - let lines: *mut carray = carray_new(1024i32 as libc::c_uint); +pub unsafe fn dc_split_into_lines(buf_terminated: *const libc::c_char) -> Vec<*mut libc::c_char> { + let mut lines = Vec::new(); let mut line_chars = 0; let mut p1: *const libc::c_char = buf_terminated; let mut line_start: *const libc::c_char = p1; - let mut l_indx: libc::c_uint = 0i32 as libc::c_uint; while 0 != *p1 { if *p1 as libc::c_int == '\n' as i32 { - carray_add( - lines, - strndup(line_start, line_chars) as *mut libc::c_void, - &mut l_indx, - ); + lines.push(strndup(line_start, line_chars)); p1 = p1.offset(1isize); line_start = p1; line_chars = 0; } else { p1 = p1.offset(1isize); - line_chars = line_chars.wrapping_add(1) + line_chars += 1; } } - carray_add( - lines, - strndup(line_start, line_chars) as *mut libc::c_void, - &mut l_indx, - ); - + lines.push(strndup(line_start, line_chars)); lines } -pub unsafe fn dc_free_splitted_lines(lines: *mut carray) { - if !lines.is_null() { - let mut i: libc::c_int; - let cnt: libc::c_int = carray_count(lines) as libc::c_int; - i = 0i32; - while i < cnt { - free(carray_get(lines, i as libc::c_uint)); - i += 1 - } - carray_free(lines); - }; +pub unsafe fn dc_free_splitted_lines(lines: Vec<*mut libc::c_char>) { + for s in lines { + free(s as *mut libc::c_void); + } } /* insert a break every n characters, the return must be free()'d */ From c5eef216454b8c2fc916cd140c7d2ebdb1e05c01 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 2 Aug 2019 12:14:49 +0300 Subject: [PATCH 40/95] Remove carray use and comment --- src/dc_tools.rs | 1 - src/types.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 41802a73e..ee23c1b9f 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -17,7 +17,6 @@ const ELLIPSE: &'static str = "[...]"; /* Some tools and enhancements to the used libraries, there should be no references to Context and other "larger" classes here. */ -// for carray etc. /* ** library-private **********************************************************/ /* math tools */ pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool { diff --git a/src/types.rs b/src/types.rs index f3d360333..4205006c9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,7 +2,6 @@ use crate::constants::Event; use crate::context::Context; -pub use mmime::carray::*; pub use mmime::clist::*; pub use rusqlite::ffi::*; From a8cea64f39d72bd7a36f76f11670bfc8403d49c4 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Fri, 2 Aug 2019 21:43:25 +0200 Subject: [PATCH 41/95] feat(deps): update rusqlite to official version again A fix for the non utf8 strings has been merged and released in `0.20` --- Cargo.lock | 323 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 8 +- 2 files changed, 160 insertions(+), 171 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca7f78e6d..259e477c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,7 +35,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -44,7 +44,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -101,7 +101,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -115,7 +115,7 @@ name = "backtrace-sys" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -189,16 +189,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "buf_redux" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "slice-deque 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -243,12 +243,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -295,7 +295,7 @@ name = "clear_on_drop" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -328,9 +328,9 @@ dependencies = [ "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -369,21 +369,21 @@ name = "crossbeam-deque" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -391,12 +391,12 @@ name = "crossbeam-queue" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-utils" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -409,19 +409,19 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "curve25519-dalek" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -443,7 +443,7 @@ dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -453,7 +453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -461,10 +461,10 @@ name = "deltachat" version = "1.0.0-alpha.3" dependencies = [ "addr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -480,17 +480,17 @@ dependencies = [ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "pgp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", - "r2d2_sqlite 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2_sqlite 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)", - "rusqlite 0.19.0 (git+http://github.com/dignifiedquire/rusqlite?branch=fix/text)", + "rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -519,7 +519,7 @@ dependencies = [ "derive_builder_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -530,7 +530,7 @@ dependencies = [ "darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -540,7 +540,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -577,7 +577,7 @@ version = "1.0.0-pre.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -611,7 +611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -621,7 +621,7 @@ name = "error-chain" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -630,7 +630,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -641,7 +641,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -675,7 +675,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide_c_api 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -739,25 +739,25 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "h2" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -787,7 +787,7 @@ dependencies = [ [[package]] name = "http" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -802,7 +802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -816,11 +816,11 @@ name = "human-panic" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "os_type 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -843,13 +843,13 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -950,9 +950,6 @@ dependencies = [ name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "lettre" @@ -963,11 +960,11 @@ dependencies = [ "bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "fast_chemail 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -979,10 +976,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libsqlite3-sys" version = "0.16.0" -source = "git+http://github.com/dignifiedquire/rusqlite?branch=fix/text#d81b8cdb175f7c27a3ace9ad46818e2a01434cdc" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1018,7 +1015,7 @@ dependencies = [ [[package]] name = "log" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1052,7 +1049,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1071,8 +1068,11 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.2.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "mime" @@ -1095,7 +1095,7 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1103,13 +1103,13 @@ dependencies = [ [[package]] name = "miniz_oxide_c_api" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1122,7 +1122,7 @@ dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1161,7 +1161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.48 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1187,7 +1187,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1229,7 +1229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1277,7 +1277,7 @@ dependencies = [ [[package]] name = "opaque-debug" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1300,10 +1300,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl-src" -version = "111.3.0+1.1.1c" +version = "111.4.0+1.1.1c" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1312,10 +1312,10 @@ version = "0.9.48" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-src 111.3.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-src 111.4.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1376,7 +1376,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1409,7 +1409,7 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1442,7 +1442,7 @@ dependencies = [ "block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "buf_redux 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "buf_redux 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cast5 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfb-mode 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1459,7 +1459,7 @@ dependencies = [ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "md-5 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint-dig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1514,7 +1514,7 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1540,7 +1540,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1558,7 +1558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "psl-codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1614,18 +1614,18 @@ name = "r2d2" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "scheduled-thread-pool 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "r2d2_sqlite" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "r2d2 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rusqlite 0.19.0 (git+http://github.com/dignifiedquire/rusqlite?branch=fix/text)", + "rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1664,9 +1664,9 @@ name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1682,10 +1682,9 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1708,7 +1707,7 @@ name = "rand_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1843,7 +1842,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1858,14 +1857,14 @@ dependencies = [ "encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.33 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1876,7 +1875,7 @@ dependencies = [ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winreg 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1886,7 +1885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1902,19 +1901,19 @@ dependencies = [ "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "zeroize 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rusqlite" -version = "0.19.0" -source = "git+http://github.com/dignifiedquire/rusqlite?branch=fix/text#d81b8cdb175f7c27a3ace9ad46818e2a01434cdc" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libsqlite3-sys 0.16.0 (git+http://github.com/dignifiedquire/rusqlite?branch=fix/text)", + "libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1940,7 +1939,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1956,7 +1955,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "safemem" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2030,20 +2029,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2053,7 +2052,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2063,7 +2062,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2075,7 +2074,7 @@ dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2086,7 +2085,7 @@ dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2098,7 +2097,7 @@ dependencies = [ "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2126,11 +2125,6 @@ name = "smallvec" version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "spin" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "stable_deref_trait" version = "1.1.1" @@ -2170,12 +2164,12 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "subtle" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2190,7 +2184,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.15.40" +version = "0.15.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2205,7 +2199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2315,7 +2309,7 @@ name = "tokio-executor" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2326,7 +2320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2334,10 +2328,10 @@ name = "tokio-reactor" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2376,9 +2370,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2390,7 +2384,7 @@ name = "tokio-timer" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2401,7 +2395,7 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2429,7 +2423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2555,7 +2549,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2615,7 +2609,7 @@ dependencies = [ [[package]] name = "winreg" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2644,7 +2638,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2663,7 +2657,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] @@ -2679,7 +2673,7 @@ dependencies = [ "checksum ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" -"checksum backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)" = "88fb679bc9af8fa639198790a77f52d345fe13656c08b43afa9424c206b731c6" +"checksum backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)" = "b5164d292487f037ece34ec0de2fcede2faa162f085dd96d2385ab81b12765ba" "checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bitfield 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" @@ -2690,14 +2684,14 @@ dependencies = [ "checksum block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" "checksum blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3" -"checksum buf_redux 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cb6b0b3650a857c5f3eb2083d6a51dc86a9967eafdd42919be63e3b3e6599752" +"checksum buf_redux 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" "checksum bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cast5 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ce5759b4c52ca74f9a98421817c882f1fd9b0071ae41cd61ab9f9d059c04fd6" -"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" +"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46" "checksum cfb-mode 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "190e7b55d3a27cf8879becf61035a141cbc783f3258a41d16d1706719f991345" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4f426e64df1c3de26cbf44593c6ffff5dbfd43bbf9de0d075058558126b3fc73" @@ -2713,11 +2707,11 @@ dependencies = [ "checksum crc24 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fd121741cf3eb82c08dd3023eb55bf2665e5f60ec20f89760cf836ae4562e6a0" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" -"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" +"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3b4c17619643c1252b5f690084b82639dd7fac141c57c8e77a00e0148132092c" -"checksum curve25519-dalek 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5d4b820e8711c211745880150f5fac78ab07d6e3851d8ce9f5a02cedc199174c" +"checksum curve25519-dalek 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "019779982f8518304cfbabd515e77ad6372a9a28a57d22d39478164c5e2b32ee" "checksum darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfbcb0c5961907597a7d1148e3af036268f2b773886b8bb3eeb1e1281d3d3d6" "checksum darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6afc018370c3bff3eb51f89256a6bdb18b4fdcda72d577982a14954a7a0b402c" "checksum darling_macro 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d8dac1c6f1d29a41c4712b4400f878cb4fcc4c7628f298dd75038e024998d1" @@ -2750,12 +2744,12 @@ dependencies = [ "checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" -"checksum h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392" +"checksum getrandom 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8e190892c840661957ba9f32dacfb3eb405e657f9f9f60485605f0bb37d6f8" +"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e" -"checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" +"checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4" "checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21638c5955a6daf3ecc42cae702335fc37a72a4abcc6959ce457b31a7d43bbdd" @@ -2774,23 +2768,23 @@ dependencies = [ "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c66afaa5dfadbb81d4e00fd1d1ab057c7cd4c799c5a44e0009386d553587e728" "checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" -"checksum libsqlite3-sys 0.16.0 (git+http://github.com/dignifiedquire/rusqlite?branch=fix/text)" = "" +"checksum libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5b95e89c330291768dc840238db7f9e204fd208511ab6319b56193a7f2ae25" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" "checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" -"checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" "checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum md-5 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425" "checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed" -"checksum miniz_oxide 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b6c3756d66cf286314d5f7ebe74886188a9a92f5eee68b06f31ac2b4f314c99d" -"checksum miniz_oxide_c_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5b78ca5446dd9fe0dab00e058731b6b08a8c1d2b9cdb8efb10876e24e9ae2494" +"checksum miniz_oxide 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c061edee74a88eb35d876ce88b94d77a0448a201de111c244b70d047f5820516" +"checksum miniz_oxide_c_api 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6c675792957b0d19933816c4e1d56663c341dd9bfa31cb2140ff2267c1d8ecf4" "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum mmime 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d86dea2dd1de25d9087cd7b249214d631393f731896183a6729f747fa80018f" @@ -2806,10 +2800,10 @@ dependencies = [ "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" -"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" +"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)" = "8152bb5a9b5b721538462336e3bef9a539f892715e5037fda0f984577311af15" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-src 111.3.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)" = "53ed5f31d294bdf5f7a4ba0a206c2754b0f60e9a63b7e3076babc5317873c797" +"checksum openssl-src 111.4.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)" = "783a3c5b3c1c28bdd7245e6b7a91de6168994948726b1dd4227199e9e6864383" "checksum openssl-sys 0.9.48 (registry+https://github.com/rust-lang/crates.io-index)" = "b5ba300217253bcc5dc68bed23d782affa45000193866e025329aa8a7a9f05b8" "checksum os_type 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7edc011af0ae98b7f88cf7e4a83b70a54a75d2b8cb013d6efd02e5956207e9eb" "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" @@ -2820,7 +2814,7 @@ dependencies = [ "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" -"checksum parking_lot_core 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a7bbaa05312363e0480e1efee133fff1a09ef4a6406b65e226b9a793c223a32" +"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum percent-encoding 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba4f28a6faf4ffea762ba8f4baef48c61a6db348647c73095034041fc79dd954" "checksum pgp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb80b37b7debf9a98dc0caca3ed40ddf1d383691208763d0458df0b91521020f" @@ -2828,7 +2822,7 @@ dependencies = [ "checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" "checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" "checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" -"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" +"checksum pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c1d2cfa5a714db3b5f24f0915e74fcdf91d09d496ba61329705dda7774d2af" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" "checksum pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61" @@ -2840,12 +2834,12 @@ dependencies = [ "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum r2d2 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bc42ce75d9f4447fb2a04bbe1ed5d18dd949104572850ec19b164e274919f81b" -"checksum r2d2_sqlite 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e09cea6a05f6f05d6f5e7dc52bd5b09d6a24fe7b42cf1d9d87f71f39d43c0b" +"checksum r2d2_sqlite 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "806e268035ce9e5a604bf617ac8a073ef28b59ef2e48e8338db0baf530caef33" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" @@ -2867,12 +2861,12 @@ dependencies = [ "checksum reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0777154c2c3eb54f5c480db01de845652d941e47191277cc673634c3853939" "checksum ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a" "checksum rsa 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6ad8d3632f6745bb671c8637e2aa44015537c5e384789d2ea3235739301ed1e0" -"checksum rusqlite 0.19.0 (git+http://github.com/dignifiedquire/rusqlite?branch=fix/text)" = "" +"checksum rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a194373ef527035645a1bc21b10dc2125f73497e6e155771233eb187aedd051" "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustyline 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f47ea1ceb347d2deae482d655dc8eef4bd82363d3329baffa3818bd76fea48b" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" -"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" +"checksum safemem 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e133ccc4f4d1cd4f89cc8a7ff618287d56dc7f638b8e38fc32c5fdcadc339dd5" "checksum schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339" "checksum scheduled-thread-pool 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd07742e081ff6c077f5f6b283f12f32b9e7cc765b316160d66289b74546fbb3" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" @@ -2883,8 +2877,8 @@ dependencies = [ "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum sequence_trie 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1ee22067b7ccd072eeb64454b9c6e1b33b61cd0d49e895fd48676a184580e0c3" -"checksum serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "d46b3dfedb19360a74316866cef04687cd4d6a70df8e6a506c63512790769b72" -"checksum serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "c22a0820adfe2f257b098714323563dd06426502abbbce4f51b72ef544c5027f" +"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113" +"checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" "checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" @@ -2894,16 +2888,15 @@ dependencies = [ "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum slice-deque 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffddf594f5f597f63533d897427a570dbaa9feabaaa06595b74b71b7014507d7" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8861bc80f649f5b4c9bd38b696ae9af74499d479dbfb327f0607de6b326a36bc" "checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5d1c33039533f051704951680f1adfd468fd37ac46816ded0d9ee068e60f05f" "checksum strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47cd23f5c7dee395a00fa20135e2ec0fffcdfa151c56182966d7a3261343432e" -"checksum subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01dca13cf6c3b179864ab3292bd794e757618d35a7766b7c46050c614ba00829" +"checksum subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01f40907d9ffc762709e4ff3eb4a6f6b41b650375a3f09ac92b641942b7fb082" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)" = "bc945221ccf4a7e8c31222b9d1fc77aefdd6638eb901a6ce457a3dc29d4c31e8" +"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" @@ -2954,7 +2947,7 @@ dependencies = [ "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" -"checksum winreg 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73f1f3c6c4d3cab118551b96c476a2caab920701e28875b64a458f2ecb96ec9d" +"checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" "checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ee1585dc1484373cbc1cee7aafda26634665cf449436fd6e24bfd1fad230538" diff --git a/Cargo.toml b/Cargo.toml index 883ddbd42..dfdfa7fe0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,9 +35,9 @@ failure_derive = "0.1.5" rustyline = "4.1.0" lazy_static = "1.3.0" regex = "1.1.6" -rusqlite = { version = "0.19", features = ["bundled"] } +rusqlite = { version = "0.20", features = ["bundled"] } addr = "0.2.0" -r2d2_sqlite = "0.11.0" +r2d2_sqlite = "0.12.0" r2d2 = "0.8.5" strum = "0.15.0" strum_macros = "0.15.0" @@ -55,10 +55,6 @@ members = [ "deltachat-ffi" ] -[patch.crates-io] -rusqlite = { git = "http://github.com/dignifiedquire/rusqlite", branch = "fix/text", features = ["bundled"] } - - [[example]] name = "simple" path = "examples/simple.rs" From 227ef1b467401c47490da5092704ec6e6de05fce Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Sun, 28 Jul 2019 16:40:33 +0200 Subject: [PATCH 42/95] Add unittest This should give us some confidence in the refactoring. --- src/dc_imex.rs | 164 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/src/dc_imex.rs b/src/dc_imex.rs index 0ca50eb4b..c972def4a 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -1286,3 +1286,167 @@ unsafe fn export_key_to_asc_file( success } + +#[cfg(test)] +mod tests { + use super::*; + + use std::ffi::CStr; + + use crate::config::Config; + use crate::key; + use crate::test_utils::*; + + unsafe extern "C" fn logging_cb( + _ctx: &Context, + evt: Event, + _d1: uintptr_t, + d2: uintptr_t, + ) -> uintptr_t { + let to_str = |x| CStr::from_ptr(x as *const libc::c_char).to_str().unwrap(); + match evt { + Event::INFO => println!("I: {}", to_str(d2)), + Event::WARNING => println!("W: {}", to_str(d2)), + Event::ERROR => println!("E: {}", to_str(d2)), + _ => (), + } + 0 + } + + /// Create Alice with a pre-generated keypair. + fn create_alice_keypair(ctx: &Context) { + ctx.set_config(Config::ConfiguredAddr, Some("alice@example.org")) + .unwrap(); + + // The keypair was created using: + // let (public, private) = crate::pgp::dc_pgp_create_keypair("alice@example.com") + // .unwrap(); + // println!("{}", public.to_base64(64)); + // println!("{}", private.to_base64(64)); + let public = key::Key::from_base64( + concat!( + "xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l", + "FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX", + "AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4", + "Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9", + "iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw", + "oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl", + "LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai", + "x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9", + "OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK", + "A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea", + "6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6", + "GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK", + "u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD", + "Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG", + "9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av", + "62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R", + "noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q", + "4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm", + "jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4", + "AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW", + "qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX", + "FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m", + "MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf", + "qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw", + "sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw", + "jTglkixw+aSTXw==" + ), + KeyType::Public, + ) + .unwrap(); + let private = key::Key::from_base64( + concat!( + "xcLYBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l", + "FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX", + "AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4", + "Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9", + "iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw", + "oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAEACAChqzVOuErmVRqvcYtq", + "m1xt1H+ZjX20z5Sn1fhTLYAcq236AWMqJvwxCXoKlc8bt2UfB+Ls9cQb1YcVq353", + "r0QiExiDeK3YlCxqd/peXJwFYTNKFC3QcnUhtpG9oS/jWjN+BRotGbjtu6Vj3M68", + "JJAq+mHJ0/9OyrqrREvGfo7uLZt7iMGemDlrDakvrbIyZrPLgay+nZ3dEFKeOQ6F", + "FrU05jyUVdoHBy0Tqx/6VpFUX9+IHcMHL2lTJB0nynBj+XZ/G4aX3WYoo3YlixHb", + "Iu35fGFA0TChoGaGPzqcI/kg2Z+b/BryG9NM3LA2cO8iGrGXAE1nPFp91jmCrQ3V", + "WushBADERP+uojjjfdO5J+RkmcFe9mFYDdtkhN+kV+LdePjiNNtcXMBhasstio0S", + "ut0GKnE7DFRhX7mkN9w2apJ2ooeFeVVWot18eSdp6Rzh6/1Z7TmhYFJ3oUxxLbnQ", + "sWIXIec1SzqWBFJUCn3IP0mCnJktFg/uGW6yLs01r5ds52uSBQQA2LSWiTwk9tEm", + "dr9mz3tHnmrkyGiyKhKGM1Z7Rch63D5yQc1s4kUMBlyuLL2QtM/e4dtaz2JAkO8k", + "QrYCnNgJ+2roTAK3kDZgYtymjdvK3HpQNtjVo7dds5RJVb6U618phZwU5WNFAEJW", + "yyImmycGfjLv+18cW/3mq0QVZejkM78D/2kHaIeJAowtBOFY2zDrKyDRoBHaUSgj", + "5BjGoviRC5rYihWDEyYDQ6mBJQstAD0Ty3MYzyUxl6ruB/BMWnMDFq5+TqtdBzu3", + "jCtZ8OEyH8A5Kdo68Wzo/PGxzMtusOdNj9+3PBmSq4yibJxbLSrn59aVUYpGLjeG", + "Kyvm9OTKkrOGN27NEzxhbGljZUBleGFtcGxlLmNvbT7CwIkEEAEIADMCGQEFAl08", + "6fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQ", + "k6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9OHUl3MrXtZ7QmHyOAFvbXE/6n5Ee", + "h+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkKA8e4cJqwDOHsyAnvQXZ7WNje9+BM", + "zcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea6zjGF0/qljTdoxTtsYpv5wXYuhwb", + "YklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6GkquJN814Y+xny4xhZzGOfue6SeP", + "12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUKu5wO9FFbgDySOSlEjByGejSGuBmh", + "o0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxDFcfC2ARdPOnsAQgA5oLxXRLnyugz", + "OmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG9JzDeQql+sYXgUSxOoIayItuXtnF", + "n7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av62n18Venlm0yNKpROPcZ6M/sc4m6", + "uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/RnoW+/fhmwIg08dQ5m8hQe3GEOZEe", + "LrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q4zW8vk2ztB8ngwbnqYy8zrN1DCIC", + "N1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAmjxLZfVDcoObFH3Cv2GB7BEYxv86K", + "C2Y6T74Q/wARAQABAAgAhSvFEYZoj1sSrXrHDjZOrryViGjCCH9t3pmkxLDrGIdd", + "KsFyN8ORUo6KUZS745yx3yFnI9EZ1IZvm9aF+jxk2lGJFtgLvfoxFOvGckwCSy8T", + "/MCiJZkz01hWo5s2VCLJheWL/GqTKjS5wXDcm+y8Wtilh+UawycdlDsSNr/D4MZL", + "j3Chq9K03l5UIR8DcC7SavNi55R2oGOfboXsdvwOlrNZdCkZOlXDI4ZKFwbDHCtp", + "Do5FS30hnJi2TecUPZWB1CaGFWnevINd4ikugVjcAoZj/QAIvfrOCgqisF/Ylg9u", + "RMUPBapmcJUueILwd0iQqvGG0aCqtchvSmlg15/lQQQA9G1NNjNAH+NQrXvDJFJe", + "/V1U3F3pz7jCjQa69c0dxSBUeNX1pG8XXD6tSkkd4Ni1mzZGcZXOmVUM6cA9I7RH", + "95RqV+QIfnXVneCRrlCjV8m6OBlkivkESXc3nW5wtCIfw7oKg9w1xuVNUaAlbCt9", + "QVLaxXJiY7ad0f5U9XJ1+w8EAPFs+M/+GZK1wOZYBL1vo7x0gL9ZggmjC4B+viBJ", + "8Q60mqTrphYFsbXHuwKV0g9aIoZMucKyEE0QLR7imttiLEz1nD8bfEScbGy9ZG//", + "wRfyJmCVAjA0pQ6LtB93d70PSVzzJrMHgbLKrDuSd6RChl7n9BIEdVyk7LEph0Yg", + "9UsRBADm6DvpKL+P3lQ0eLTfAgcQTOqLZDYmI3PvqqSkHb1kHChqOXXs8hGOSSwK", + "Gjcd4CZeNOGWR42rZyRhVgtkt6iYviIaVAWUfme6K+sLQBCeyMlmEGtykAA+LmPB", + "f4zdyUNADfoxgZF3EKHf6I3nlVn5cdT+o/9vjdY2XAOwcls1RzaFwsB2BBgBCAAg", + "BQJdPOn4AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/", + "dXshJnoWqEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJ", + "ywJoupwXFNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJ", + "uiCQvR9mMjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6", + "RDXIeYJfqrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMl", + "ammDliPwsK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKOb", + "zPqgJCGwjTglkixw+aSTXw==" + ), + KeyType::Private, + ) + .unwrap(); + let saved = key::dc_key_save_self_keypair( + &ctx, + &public, + &private, + "alice@example.org", + 1, + &ctx.sql, + ); + assert_eq!(saved, true, "Failed to save Alice's key"); + } + + #[test] + fn test_render_setup_file() { + let t = test_context(Some(logging_cb)); + + create_alice_keypair(&t.ctx); // Trick things to think we're configured. + let msg = unsafe { + to_string(dc_render_setup_file( + &t.ctx, + b"hello\x00" as *const u8 as *const libc::c_char, + )) + }; + println!("{}", &msg); + // Check some substrings, indicating things got substituted. + // In particular note the mixing of `\r\n` and `\n` depending + // on who generated the stings. + assert!(msg.contains("Autocrypt Setup Message</title")); + assert!(msg.contains("<h1>Autocrypt Setup Message</h1>")); + assert!(msg.contains("<p>This is the Autocrypt Setup Message used to")); + assert!(msg.contains("-----BEGIN PGP MESSAGE-----\r\n")); + assert!(msg.contains("Passphrase-Format: numeric9x4\r\n")); + assert!(msg.contains("Passphrase-Begin: he\n")); + assert!(msg.contains("==\n")); + assert!(msg.contains("-----END PGP MESSAGE-----\n")); + } +} From c568d5dcac137bf0a68de1d5ed40cdb77a5ea88a Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe <flub@google.com> Date: Sun, 28 Jul 2019 18:05:17 +0200 Subject: [PATCH 43/95] Safe string usage Mostly safe string usage, but some other minor cleanups: - This isn't used from any C code, so no extern C. - Use Config enums rather than strings. - Clean up old unused sql statements. --- src/dc_imex.rs | 69 ++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/dc_imex.rs b/src/dc_imex.rs index c972def4a..602cabc6b 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -5,6 +5,7 @@ use mmime::mmapstring::*; use mmime::other::*; use rand::{thread_rng, Rng}; +use crate::config::Config; use crate::constants::*; use crate::context::Context; use crate::dc_chat::*; @@ -194,27 +195,22 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { dc_strdup(setup_code.as_ptr()) } -pub unsafe extern "C" fn dc_render_setup_file( +pub unsafe fn dc_render_setup_file( context: &Context, passphrase: *const libc::c_char, ) -> *mut libc::c_char { - let stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; - - let mut passphrase_begin: [libc::c_char; 8] = [0; 8]; let mut ret_setupfilecontent: *mut libc::c_char = 0 as *mut libc::c_char; if !(passphrase.is_null() || strlen(passphrase) < 2) { - strncpy(passphrase_begin.as_mut_ptr(), passphrase, 2); - passphrase_begin[2usize] = 0i32 as libc::c_char; /* create the payload */ if !(0 == dc_ensure_secret_key_exists(context)) { let self_addr = context .sql - .get_config(context, "configured_addr") + .get_config(context, Config::ConfiguredAddr) .unwrap_or_default(); let curr_private_key = Key::from_self_private(context, self_addr, &context.sql); let e2ee_enabled = context .sql - .get_config_int(context, "e2ee_enabled") + .get_config_int(context, Config::E2eeEnabled) .unwrap_or_else(|| 1); let headers = if 0 != e2ee_enabled { @@ -230,39 +226,40 @@ pub unsafe extern "C" fn dc_render_setup_file( payload_key_asc_c.as_ptr() as *const libc::c_void, payload_key_asc_c.as_bytes().len(), ) { - let encr_string_c = CString::new(encr).unwrap(); - let mut encr_string = strdup(encr_string_c.as_ptr()); - - let replacement: *mut libc::c_char = - dc_mprintf(b"-----BEGIN PGP MESSAGE-----\r\nPassphrase-Format: numeric9x4\r\nPassphrase-Begin: %s\x00" - as *const u8 as *const libc::c_char, - passphrase_begin.as_mut_ptr()); - dc_str_replace( - &mut encr_string, - b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, - replacement, + let replacement = format!( + concat!( + "-----BEGIN PGP MESSAGE-----\r\n", + "Passphrase-Format: numeric9x4\r\n", + "Passphrase-Begin: {}" + ), + &as_str(passphrase)[..2] ); - free(replacement as *mut libc::c_void); - let setup_message_title = - CString::new(context.stock_str(StockMessage::AcSetupMsgSubject).as_ref()) - .unwrap(); - let setup_message_body = context.stock_str(StockMessage::AcSetupMsgBody); - let msg_body_head: &str = setup_message_body.split('\r').next().unwrap(); - let msg_body_html = CString::new(msg_body_head.replace("\n", "<br>")).unwrap(); - ret_setupfilecontent = - dc_mprintf(b"<!DOCTYPE html>\r\n<html>\r\n<head>\r\n<title>%s\r\n\r\n\r\n

%s

\r\n

%s

\r\n
\r\n%s\r\n
\r\n\r\n\r\n\x00" - as *const u8 as *const libc::c_char, - setup_message_title.as_ptr(), - setup_message_title.as_ptr(), - msg_body_html.as_ptr(), - encr_string); - free(encr_string as *mut libc::c_void); + let pgp_msg = encr.replace("-----BEGIN PGP MESSAGE-----", &replacement); + + let msg_subj = context.stock_str(StockMessage::AcSetupMsgSubject); + let msg_body = context.stock_str(StockMessage::AcSetupMsgBody); + let msg_body_head: &str = msg_body.split('\r').next().unwrap(); + let msg_body_html = msg_body_head.replace("\n", "
"); + ret_setupfilecontent = to_cstring(format!( + concat!( + "\r\n", + "\r\n", + " \r\n", + " {}\r\n", + " \r\n", + " \r\n", + "

{}

\r\n", + "

{}

\r\n", + "
\r\n{}\r\n
\r\n", + " \r\n", + "\r\n" + ), + msg_subj, msg_subj, msg_body_html, pgp_msg + )); } } } } - sqlite3_finalize(stmt); - ret_setupfilecontent } From d37dda6f5008a73b09f467c92c7403a1ed61adc4 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Thu, 1 Aug 2019 21:29:21 +0200 Subject: [PATCH 44/95] Turn the function safe --- examples/repl/cmdline.rs | 27 ++----- src/dc_imex.rs | 167 +++++++++++++++++++++------------------ tests/stress.rs | 49 ++---------- 3 files changed, 100 insertions(+), 143 deletions(-) diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 2ed21522a..9c2d6f5da 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -561,30 +561,17 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E } "export-setup" => { let setup_code = dc_create_setup_code(context); - let setup_code_c = CString::new(setup_code.clone()).unwrap(); let file_name: *mut libc::c_char = dc_mprintf( b"%s/autocrypt-setup-message.html\x00" as *const u8 as *const libc::c_char, context.get_blobdir(), ); - let file_content: *mut libc::c_char; - file_content = dc_render_setup_file(context, setup_code_c.as_ptr()); - if !file_content.is_null() - && 0 != dc_write_file( - context, - file_name, - file_content as *const libc::c_void, - strlen(file_content), - ) - { - println!( - "Setup message written to: {}\nSetup code: {}", - as_str(file_name), - &setup_code, - ) - } else { - bail!(""); - } - free(file_content as *mut libc::c_void); + let file_content = dc_render_setup_file(context, &setup_code)?; + std::fs::write(as_str(file_name), file_content)?; + println!( + "Setup message written to: {}\nSetup code: {}", + as_str(file_name), + &setup_code, + ); free(file_name as *mut libc::c_void); } "poke" => { diff --git a/src/dc_imex.rs b/src/dc_imex.rs index 602cabc6b..daaed60fb 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -14,6 +14,7 @@ use crate::dc_e2ee::*; use crate::dc_job::*; use crate::dc_msg::*; use crate::dc_tools::*; +use crate::error::*; use crate::key::*; use crate::param::*; use crate::pgp::*; @@ -99,13 +100,12 @@ pub unsafe fn dc_imex_has_backup( } pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { - let mut setup_file_content: *mut libc::c_char = 0 as *mut libc::c_char; let mut setup_file_name: *mut libc::c_char = 0 as *mut libc::c_char; let mut msg: *mut dc_msg_t = 0 as *mut dc_msg_t; if dc_alloc_ongoing(context) == 0 { return std::ptr::null_mut(); } - let setup_code = CString::new(dc_create_setup_code(context)).unwrap(); + let setup_code = dc_create_setup_code(context); /* this may require a keypair to be created. this may take a second ... */ if !context .running_state @@ -114,8 +114,8 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { .unwrap() .shall_stop_ongoing { - setup_file_content = dc_render_setup_file(context, setup_code.as_ptr()); - if !setup_file_content.is_null() { + if let Ok(setup_file_content) = dc_render_setup_file(context, &setup_code) { + let setup_file_content_c = CString::yolo(setup_file_content.as_str()); /* encrypting may also take a while ... */ if !context .running_state @@ -133,8 +133,8 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { || 0 == dc_write_file( context, setup_file_name, - setup_file_content as *const libc::c_void, - strlen(setup_file_content), + setup_file_content_c.as_ptr() as *const libc::c_void, + setup_file_content_c.as_bytes().len(), )) { let chat_id = dc_create_chat_by_contact_id(context, 1i32 as uint32_t); @@ -188,79 +188,78 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { } } free(setup_file_name as *mut libc::c_void); - free(setup_file_content as *mut libc::c_void); dc_msg_unref(msg); dc_free_ongoing(context); - dc_strdup(setup_code.as_ptr()) + setup_code.strdup() } -pub unsafe fn dc_render_setup_file( - context: &Context, - passphrase: *const libc::c_char, -) -> *mut libc::c_char { - let mut ret_setupfilecontent: *mut libc::c_char = 0 as *mut libc::c_char; - if !(passphrase.is_null() || strlen(passphrase) < 2) { - /* create the payload */ - if !(0 == dc_ensure_secret_key_exists(context)) { - let self_addr = context - .sql - .get_config(context, Config::ConfiguredAddr) - .unwrap_or_default(); - let curr_private_key = Key::from_self_private(context, self_addr, &context.sql); - let e2ee_enabled = context - .sql - .get_config_int(context, Config::E2eeEnabled) - .unwrap_or_else(|| 1); - - let headers = if 0 != e2ee_enabled { - Some(("Autocrypt-Prefer-Encrypt", "mutual")) - } else { - None - }; - - if let Some(payload_key_asc) = curr_private_key.map(|k| k.to_asc(headers)) { - let payload_key_asc_c = CString::new(payload_key_asc).unwrap(); - if let Some(encr) = dc_pgp_symm_encrypt( - passphrase, - payload_key_asc_c.as_ptr() as *const libc::c_void, - payload_key_asc_c.as_bytes().len(), - ) { - let replacement = format!( - concat!( - "-----BEGIN PGP MESSAGE-----\r\n", - "Passphrase-Format: numeric9x4\r\n", - "Passphrase-Begin: {}" - ), - &as_str(passphrase)[..2] - ); - let pgp_msg = encr.replace("-----BEGIN PGP MESSAGE-----", &replacement); - - let msg_subj = context.stock_str(StockMessage::AcSetupMsgSubject); - let msg_body = context.stock_str(StockMessage::AcSetupMsgBody); - let msg_body_head: &str = msg_body.split('\r').next().unwrap(); - let msg_body_html = msg_body_head.replace("\n", "
"); - ret_setupfilecontent = to_cstring(format!( - concat!( - "\r\n", - "\r\n", - " \r\n", - " {}\r\n", - " \r\n", - " \r\n", - "

{}

\r\n", - "

{}

\r\n", - "
\r\n{}\r\n
\r\n", - " \r\n", - "\r\n" - ), - msg_subj, msg_subj, msg_body_html, pgp_msg - )); - } - } - } +pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result { + ensure!( + passphrase.len() >= 2, + "Passphrase must be at least 2 chars long." + ); + unsafe { + ensure!( + !(dc_ensure_secret_key_exists(context) == 0), + "No secret key available." + ); } - ret_setupfilecontent + let self_addr = context + .get_config(Config::ConfiguredAddr) + .ok_or(format_err!("Failed to get self address."))?; + let private_key = Key::from_self_private(context, self_addr, &context.sql) + .ok_or(format_err!("Failed to get private key."))?; + let ac_headers = match context + .sql + .get_config_int(context, Config::E2eeEnabled) + .unwrap_or(1) + { + 0 => None, + _ => 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_ptr() as *const libc::c_void, + private_key_asc_c.as_bytes().len(), + ) + .ok_or(format_err!("Failed to encrypt private key."))? + }; + let replacement = format!( + concat!( + "-----BEGIN PGP MESSAGE-----\r\n", + "Passphrase-Format: numeric9x4\r\n", + "Passphrase-Begin: {}" + ), + &passphrase[..2] + ); + let pgp_msg = encr.replace("-----BEGIN PGP MESSAGE-----", &replacement); + + let msg_subj = context.stock_str(StockMessage::AcSetupMsgSubject); + let msg_body = context.stock_str(StockMessage::AcSetupMsgBody); + // let msg_body_head: &str = msg_body.split('\r').next().unwrap(); + // let msg_body_html = msg_body_head.replace("\n", "
"); + let msg_body_html = msg_body.replace("\n", "
"); + Ok(format!( + concat!( + "\r\n", + "\r\n", + " \r\n", + " {}\r\n", + " \r\n", + " \r\n", + "

{}

\r\n", + "

{}

\r\n", + "
\r\n{}\r\n
\r\n", + " \r\n", + "\r\n" + ), + msg_subj, msg_subj, msg_body_html, pgp_msg + )) } pub fn dc_create_setup_code(_context: &Context) -> String { @@ -1427,12 +1426,7 @@ mod tests { let t = test_context(Some(logging_cb)); create_alice_keypair(&t.ctx); // Trick things to think we're configured. - let msg = unsafe { - to_string(dc_render_setup_file( - &t.ctx, - b"hello\x00" as *const u8 as *const libc::c_char, - )) - }; + let msg = dc_render_setup_file(&t.ctx, "hello").unwrap(); println!("{}", &msg); // Check some substrings, indicating things got substituted. // In particular note the mixing of `\r\n` and `\n` depending @@ -1446,4 +1440,19 @@ mod tests { assert!(msg.contains("==\n")); assert!(msg.contains("-----END PGP MESSAGE-----\n")); } + + #[test] + fn test_create_setup_code() { + let t = dummy_context(); + let setupcode = dc_create_setup_code(&t.ctx); + assert_eq!(setupcode.len(), 44); + assert_eq!(setupcode.chars().nth(4).unwrap(), '-'); + assert_eq!(setupcode.chars().nth(9).unwrap(), '-'); + assert_eq!(setupcode.chars().nth(14).unwrap(), '-'); + assert_eq!(setupcode.chars().nth(19).unwrap(), '-'); + assert_eq!(setupcode.chars().nth(24).unwrap(), '-'); + assert_eq!(setupcode.chars().nth(29).unwrap(), '-'); + assert_eq!(setupcode.chars().nth(34).unwrap(), '-'); + assert_eq!(setupcode.chars().nth(39).unwrap(), '-'); + } } diff --git a/tests/stress.rs b/tests/stress.rs index f0530e093..1230dda85 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -521,51 +521,13 @@ unsafe fn stress_functions(context: &Context) { ); free(buf_1 as *mut libc::c_void); if 0 != dc_is_configured(context) { - let setupfile: *mut libc::c_char; - let setupcode_c = - CString::new(dc_create_setup_code(context)).expect("invalid string converted"); - assert_eq!(setupcode_c.to_bytes().len(), 44); - let setupcode = setupcode_c.as_ptr(); - assert!( - 0 != !(*setupcode.offset(4isize) as libc::c_int == '-' as i32 - && *setupcode.offset(9isize) as libc::c_int == '-' as i32 - && *setupcode.offset(14isize) as libc::c_int == '-' as i32 - && *setupcode.offset(19isize) as libc::c_int == '-' as i32 - && *setupcode.offset(24isize) as libc::c_int == '-' as i32 - && *setupcode.offset(29isize) as libc::c_int == '-' as i32 - && *setupcode.offset(34isize) as libc::c_int == '-' as i32 - && *setupcode.offset(39isize) as libc::c_int == '-' as i32) - as usize - ); - setupfile = dc_render_setup_file(context, setupcode); - assert!(!setupfile.is_null()); - let buf_2: *mut libc::c_char = dc_strdup(setupfile); - let mut headerline_1: *const libc::c_char = 0 as *const libc::c_char; - let mut setupcodebegin_1: *const libc::c_char = 0 as *const libc::c_char; - assert!(!dc_split_armored_data( - buf_2, - &mut headerline_1, - &mut setupcodebegin_1, - 0 as *mut *const libc::c_char, - 0 as *mut *const libc::c_char, - )); - assert!(!headerline_1.is_null()); - assert_eq!( - strcmp( - headerline_1, - b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, - ), - 0 - ); - assert!( - !(!setupcodebegin_1.is_null() - && strlen(setupcodebegin_1) == 2 - && strncmp(setupcodebegin_1, setupcode, 2) == 0i32) - ); - free(buf_2 as *mut libc::c_void); + let setupcode = dc_create_setup_code(context); + let setupcode_c = CString::yolo(setupcode.clone()); + let setupfile = dc_render_setup_file(context, &setupcode).unwrap(); + let setupfile_c = CString::yolo(setupfile); let payload: *mut libc::c_char; let mut headerline_2: *const libc::c_char = 0 as *const libc::c_char; - payload = dc_decrypt_setup_file(context, setupcode, setupfile); + payload = dc_decrypt_setup_file(context, setupcode_c.as_ptr(), setupfile_c.as_ptr()); assert!(payload.is_null()); assert!(!dc_split_armored_data( payload, @@ -583,7 +545,6 @@ unsafe fn stress_functions(context: &Context) { 0 ); free(payload as *mut libc::c_void); - free(setupfile as *mut libc::c_void); } if 0 != dc_is_configured(context) { From d2b23b727b630691ca75fe89159104de6bc2241d Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Sat, 3 Aug 2019 00:26:38 +0200 Subject: [PATCH 45/95] Restore carriage-return handling to how it was in dcc Some part of the translation seems to have got this wrong somewhere. Add a test and restore handling to something more sane again. --- src/dc_imex.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/dc_imex.rs b/src/dc_imex.rs index daaed60fb..11d06b9b4 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -241,9 +241,7 @@ pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result"); - let msg_body_html = msg_body.replace("\n", "
"); + let msg_body_html = msg_body.replace("\r", "").replace("\n", "
"); Ok(format!( concat!( "\r\n", @@ -1289,6 +1287,8 @@ mod tests { use std::ffi::CStr; + use num_traits::ToPrimitive; + use crate::config::Config; use crate::key; use crate::test_utils::*; @@ -1441,6 +1441,28 @@ mod tests { assert!(msg.contains("-----END PGP MESSAGE-----\n")); } + unsafe extern "C" fn ac_setup_msg_cb( + ctx: &Context, + evt: Event, + d1: uintptr_t, + d2: uintptr_t, + ) -> uintptr_t { + if evt == Event::GET_STRING && d1 == StockMessage::AcSetupMsgBody.to_usize().unwrap() { + "hello\r\nthere".strdup() as usize + } else { + logging_cb(ctx, evt, d1, d2) + } + } + + #[test] + fn test_render_setup_file_newline_replace() { + let t = test_context(Some(ac_setup_msg_cb)); + create_alice_keypair(&t.ctx); + let msg = dc_render_setup_file(&t.ctx, "pw").unwrap(); + println!("{}", &msg); + assert!(msg.contains("

hello
there

")); + } + #[test] fn test_create_setup_code() { let t = dummy_context(); From 4e1e32df6537d29ae52a01434b30050d616ef4d7 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Sat, 3 Aug 2019 11:12:21 +0200 Subject: [PATCH 46/95] chore: update mmime to 0.1.1 --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 259e477c6..d576a5f59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -474,7 +474,7 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "mmime 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "mmime 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1142,7 +1142,7 @@ dependencies = [ [[package]] name = "mmime" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2787,7 +2787,7 @@ dependencies = [ "checksum miniz_oxide_c_api 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6c675792957b0d19933816c4e1d56663c341dd9bfa31cb2140ff2267c1d8ecf4" "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum mmime 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d86dea2dd1de25d9087cd7b249214d631393f731896183a6729f747fa80018f" +"checksum mmime 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a1246fa340840c36f1fca1507db82463fbc4c2f7763fe84bfde666c7381e0593" "checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b" From 0051720d1bd99100d36aff276646096ea11ba4bf Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Sun, 4 Aug 2019 00:14:49 +0200 Subject: [PATCH 47/95] Kill to_cstring with fire I swear I already did this, see #273. --- src/context.rs | 6 +++--- src/dc_securejoin.rs | 4 ++-- src/dc_tools.rs | 10 ++-------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/context.rs b/src/context.rs index ba12edc21..1480c8181 100644 --- a/src/context.rs +++ b/src/context.rs @@ -310,12 +310,12 @@ pub unsafe fn dc_open(context: &Context, dbfile: &str, blobdir: Option<&str>) -> if 0 != dc_is_open(context) { return false; } - *context.dbfile.write().unwrap() = to_cstring(dbfile); + *context.dbfile.write().unwrap() = dbfile.strdup(); if blobdir.is_some() && blobdir.unwrap().len() > 0 { - let dir = to_cstring(dc_ensure_no_slash_safe(blobdir.unwrap())); + let dir = dc_ensure_no_slash_safe(blobdir.unwrap()).strdup(); *context.blobdir.write().unwrap() = dir; } else { - let dir = to_cstring(dbfile.to_string() + "-blobs"); + let dir = (dbfile.to_string() + "-blobs").strdup(); dc_create_folder(context, dir); *context.blobdir.write().unwrap() = dir; } diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index 3e908a5c1..90573412f 100644 --- a/src/dc_securejoin.rs +++ b/src/dc_securejoin.rs @@ -45,12 +45,12 @@ pub unsafe fn dc_get_securejoin_qr( dc_ensure_secret_key_exists(context); invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id); if invitenumber.is_null() { - invitenumber = to_cstring(dc_create_id()); + invitenumber = dc_create_id().strdup(); dc_token_save(context, DC_TOKEN_INVITENUMBER, group_chat_id, invitenumber); } auth = dc_token_lookup(context, DC_TOKEN_AUTH, group_chat_id); if auth.is_null() { - auth = to_cstring(dc_create_id()); + auth = dc_create_id().strdup(); dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth); } let self_addr = context.sql.get_config(context, "configured_addr"); diff --git a/src/dc_tools.rs b/src/dc_tools.rs index ee23c1b9f..39bfddb01 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -775,7 +775,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( - the message ID should be globally unique - do not add a counter or any private data as as this may give unneeded information to the receiver */ let mut rand1: *mut libc::c_char = 0 as *mut libc::c_char; - let rand2: *mut libc::c_char = to_cstring(dc_create_id()); + let rand2: *mut libc::c_char = dc_create_id().strdup(); let ret: *mut libc::c_char; let mut at_hostname: *const libc::c_char = strchr(from_addr, '@' as i32); if at_hostname.is_null() { @@ -789,7 +789,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( at_hostname, ) } else { - rand1 = to_cstring(dc_create_id()); + rand1 = dc_create_id().strdup(); ret = dc_mprintf( b"Mr.%s.%s%s\x00" as *const u8 as *const libc::c_char, rand1, @@ -1545,12 +1545,6 @@ impl> StrExt for T { } } -/// Needs to free the result after use! -pub unsafe fn to_cstring>(s: S) -> *mut libc::c_char { - let cstr = CString::new(s.as_ref()).expect("invalid string converted"); - dc_strdup(cstr.as_ref().as_ptr()) -} - pub fn to_string(s: *const libc::c_char) -> String { if s.is_null() { return "".into(); From 47b76ceb3effd30bd0845e1f15081bedc2987792 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Sun, 4 Aug 2019 09:17:54 +0000 Subject: [PATCH 48/95] python: assert that underlying dc_msg_t* for Message is not NULL --- python/src/deltachat/message.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/src/deltachat/message.py b/python/src/deltachat/message.py index 8f62dabde..6e3d05625 100644 --- a/python/src/deltachat/message.py +++ b/python/src/deltachat/message.py @@ -20,6 +20,7 @@ class Message(object): self._dc_context = account._dc_context assert isinstance(self._dc_context, ffi.CData) assert isinstance(dc_msg, ffi.CData) + assert dc_msg != ffi.NULL self._dc_msg = dc_msg self.id = lib.dc_msg_get_id(dc_msg) assert self.id is not None and self.id >= 0, repr(self.id) From fc6019e3c9b1be5e5b863c262dd11da86134b192 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sun, 4 Aug 2019 08:50:58 +0200 Subject: [PATCH 49/95] fix sql statement in order to close #163 --- src/dc_chat.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dc_chat.rs b/src/dc_chat.rs index c8c0d8a14..e9b7dc8ba 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -781,9 +781,9 @@ unsafe fn get_parent_mime_headers( .sql .query_row( "SELECT rfc724_mid, mime_in_reply_to, mime_references \ - FROM msgs WHERE timestamp=(SELECT max(timestamp) \ + FROM msgs WHERE chat_id=? AND timestamp=(SELECT max(timestamp) \ FROM msgs WHERE chat_id=? AND from_id!=?);", - params![(*chat).id as i32, 1], + params![(*chat).id as i32, (*chat).id as i32, 1], |row| { *parent_rfc724_mid = row.get::<_, String>(0)?.strdup(); *parent_in_reply_to = row.get::<_, String>(1)?.strdup(); @@ -799,9 +799,9 @@ unsafe fn get_parent_mime_headers( .sql .query_row( "SELECT rfc724_mid, mime_in_reply_to, mime_references \ - FROM msgs WHERE timestamp=(SELECT min(timestamp) \ + FROM msgs WHERE chat_id=? AND timestamp=(SELECT min(timestamp) \ FROM msgs WHERE chat_id=? AND from_id==?);", - params![(*chat).id as i32, 1], + params![(*chat).id as i32, (*chat).id as i32, 1], |row| { *parent_rfc724_mid = row.get::<_, String>(0)?.strdup(); *parent_in_reply_to = row.get::<_, String>(1)?.strdup(); From 81719c4b33efbc3bd497f0403d603b86c4460e13 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sun, 4 Aug 2019 08:51:31 +0200 Subject: [PATCH 50/95] add coment that helps with understanding the code --- src/dc_chat.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dc_chat.rs b/src/dc_chat.rs index e9b7dc8ba..a0ad68002 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -776,6 +776,7 @@ unsafe fn get_parent_mime_headers( || parent_in_reply_to.is_null() || parent_references.is_null()) { + // prefer a last message that isn't from us success = (*chat) .context .sql From ed95752f8fc4f4c21d8b543ebeda8ae9f069153f Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sun, 4 Aug 2019 10:08:28 +0200 Subject: [PATCH 51/95] use DC_CONTACT_ID_SELF constant instead of 1 --- src/dc_chat.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dc_chat.rs b/src/dc_chat.rs index a0ad68002..e495cdeaf 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -784,7 +784,7 @@ unsafe fn get_parent_mime_headers( "SELECT rfc724_mid, mime_in_reply_to, mime_references \ FROM msgs WHERE chat_id=? AND timestamp=(SELECT max(timestamp) \ FROM msgs WHERE chat_id=? AND from_id!=?);", - params![(*chat).id as i32, (*chat).id as i32, 1], + params![(*chat).id as i32, (*chat).id as i32, DC_CONTACT_ID_SELF], |row| { *parent_rfc724_mid = row.get::<_, String>(0)?.strdup(); *parent_in_reply_to = row.get::<_, String>(1)?.strdup(); @@ -802,7 +802,7 @@ unsafe fn get_parent_mime_headers( "SELECT rfc724_mid, mime_in_reply_to, mime_references \ FROM msgs WHERE chat_id=? AND timestamp=(SELECT min(timestamp) \ FROM msgs WHERE chat_id=? AND from_id==?);", - params![(*chat).id as i32, (*chat).id as i32, 1], + params![(*chat).id as i32, (*chat).id as i32, DC_CONTACT_ID_SELF], |row| { *parent_rfc724_mid = row.get::<_, String>(0)?.strdup(); *parent_in_reply_to = row.get::<_, String>(1)?.strdup(); From 59bb9add2af53de1051390b2cca77fc103085a0a Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sun, 4 Aug 2019 15:02:32 +0200 Subject: [PATCH 52/95] fix an type error --- src/dc_chat.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dc_chat.rs b/src/dc_chat.rs index e495cdeaf..34dab3d99 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -784,7 +784,7 @@ unsafe fn get_parent_mime_headers( "SELECT rfc724_mid, mime_in_reply_to, mime_references \ FROM msgs WHERE chat_id=? AND timestamp=(SELECT max(timestamp) \ FROM msgs WHERE chat_id=? AND from_id!=?);", - params![(*chat).id as i32, (*chat).id as i32, DC_CONTACT_ID_SELF], + params![(*chat).id as i32, (*chat).id as i32, DC_CONTACT_ID_SELF as i32], |row| { *parent_rfc724_mid = row.get::<_, String>(0)?.strdup(); *parent_in_reply_to = row.get::<_, String>(1)?.strdup(); @@ -802,7 +802,7 @@ unsafe fn get_parent_mime_headers( "SELECT rfc724_mid, mime_in_reply_to, mime_references \ FROM msgs WHERE chat_id=? AND timestamp=(SELECT min(timestamp) \ FROM msgs WHERE chat_id=? AND from_id==?);", - params![(*chat).id as i32, (*chat).id as i32, DC_CONTACT_ID_SELF], + params![(*chat).id as i32, (*chat).id as i32, DC_CONTACT_ID_SELF as i32], |row| { *parent_rfc724_mid = row.get::<_, String>(0)?.strdup(); *parent_in_reply_to = row.get::<_, String>(1)?.strdup(); From 7b5073b634523a1e7ec3ff4cbea33b040422fc0e Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sun, 4 Aug 2019 15:03:55 +0200 Subject: [PATCH 53/95] ?1 and ?2 --- src/dc_chat.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dc_chat.rs b/src/dc_chat.rs index 34dab3d99..c86e80f23 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -782,9 +782,9 @@ unsafe fn get_parent_mime_headers( .sql .query_row( "SELECT rfc724_mid, mime_in_reply_to, mime_references \ - FROM msgs WHERE chat_id=? AND timestamp=(SELECT max(timestamp) \ - FROM msgs WHERE chat_id=? AND from_id!=?);", - params![(*chat).id as i32, (*chat).id as i32, DC_CONTACT_ID_SELF as i32], + FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT max(timestamp) \ + FROM msgs WHERE chat_id=?1 AND from_id!=?2);", + params![(*chat).id as i32, DC_CONTACT_ID_SELF as i32], |row| { *parent_rfc724_mid = row.get::<_, String>(0)?.strdup(); *parent_in_reply_to = row.get::<_, String>(1)?.strdup(); @@ -800,9 +800,9 @@ unsafe fn get_parent_mime_headers( .sql .query_row( "SELECT rfc724_mid, mime_in_reply_to, mime_references \ - FROM msgs WHERE chat_id=? AND timestamp=(SELECT min(timestamp) \ - FROM msgs WHERE chat_id=? AND from_id==?);", - params![(*chat).id as i32, (*chat).id as i32, DC_CONTACT_ID_SELF as i32], + FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT min(timestamp) \ + FROM msgs WHERE chat_id=?1 AND from_id==?2);", + params![(*chat).id as i32, DC_CONTACT_ID_SELF as i32], |row| { *parent_rfc724_mid = row.get::<_, String>(0)?.strdup(); *parent_in_reply_to = row.get::<_, String>(1)?.strdup(); From 282f964f2fa283571a8ce4bb7df88c3b837d546a Mon Sep 17 00:00:00 2001 From: jikstra Date: Sat, 3 Aug 2019 14:34:38 +0200 Subject: [PATCH 54/95] Add tests for dc_extract_grpid_from_rfc724_mid and implement safe version of dc_extract_grpid_from_rfc724_mid --- src/dc_tools.rs | 83 +++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 39bfddb01..d0aa40148 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -803,38 +803,29 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( ret } -pub unsafe fn dc_extract_grpid_from_rfc724_mid(mid: *const libc::c_char) -> *mut libc::c_char { +pub fn dc_extract_grpid_from_rfc724_mid_r(mid: String) -> Option { /* extract our group ID from Message-IDs as `Gr.12345678901.morerandom@domain.de`; "12345678901" is the wanted ID in this example. */ - let mut success: libc::c_int = 0i32; - let mut grpid: *mut libc::c_char = 0 as *mut libc::c_char; - let p1: *mut libc::c_char; - let grpid_len: libc::c_int; - if !(mid.is_null() - || strlen(mid) < 8 - || *mid.offset(0isize) as libc::c_int != 'G' as i32 - || *mid.offset(1isize) as libc::c_int != 'r' as i32 - || *mid.offset(2isize) as libc::c_int != '.' as i32) - { - grpid = dc_strdup(&*mid.offset(3isize)); - p1 = strchr(grpid, '.' as i32); - if !p1.is_null() { - *p1 = 0i32 as libc::c_char; - grpid_len = strlen(grpid) as libc::c_int; - if !(grpid_len != 11i32 && grpid_len != 16i32) { - /* strict length comparison, the 'Gr.' magic is weak enough */ - success = 1i32 + if !(mid.len() > 8 && mid.starts_with("Gr.")) { + return None; + } + + if let Some(mid_without_offset) = mid.get(3..) { + if let Some(grpid_len) = mid_without_offset.find('.') { + /* strict length comparison, the 'Gr.' magic is weak enough */ + if grpid_len == 11 || grpid_len == 16 { + return Some(mid_without_offset.get(0..grpid_len).unwrap().to_string()); } } } - if success == 0i32 { - free(grpid as *mut libc::c_void); - grpid = 0 as *mut libc::c_char + + None +} + +pub fn dc_extract_grpid_from_rfc724_mid(mid: *const libc::c_char) -> *mut libc::c_char { + if let Some(grpid) = dc_extract_grpid_from_rfc724_mid_r(to_string(mid)) { + return unsafe { to_cstring(grpid) }; } - return if 0 != success { - grpid - } else { - 0 as *mut libc::c_char - }; + 0 as *mut libc::c_char } pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut libc::c_char { @@ -846,9 +837,9 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut } else { 0 as *mut libc::c_void }) as *const libc::c_char; - let grpid: *mut libc::c_char = dc_extract_grpid_from_rfc724_mid(mid); - if !grpid.is_null() { - return grpid; + let grpid = dc_extract_grpid_from_rfc724_mid_r(to_string(mid)); + if !grpid.is_none() { + return to_cstring(grpid.unwrap()); } cur = if !cur.is_null() { (*cur).next @@ -2126,4 +2117,36 @@ mod tests { assert_eq!(cmp, 0); } } + + #[test] + fn test_dto_cstringto_cstringc_extract_grpid_from_rfc724_mid() { + unsafe { + // Should return 0 if we pass invalid mid + let str = b"foobar\x00" as *const u8 as *const libc::c_char; + let grpid: *mut libc::c_char = dc_extract_grpid_from_rfc724_mid(str); + assert_eq!(grpid, 0 as *mut libc::c_char); + free(grpid as *mut libc::c_void); + + // Should return 0 if grpid has a length which is not 11 or 16 + let str = b"Gr.12345678.morerandom@domain.de\x00" as *const u8 as *const libc::c_char; + let grpid: *mut libc::c_char = dc_extract_grpid_from_rfc724_mid(str); + assert_eq!(grpid, 0 as *mut libc::c_char); + free(grpid as *mut libc::c_void); + + // Should return extracted grpid for grpid with length of 11 + let str = + b"Gr.12345678901.morerandom@domain.de\x00" as *const u8 as *const libc::c_char; + let grpid: *mut libc::c_char = dc_extract_grpid_from_rfc724_mid(str); + assert_eq!(to_string(grpid), "12345678901"); + free(grpid as *mut libc::c_void); + + // Should return extracted grpid for grpid with length of 11 + let str = + b"Gr.1234567890123456.morerandom@domain.de\x00" as *const u8 as *const libc::c_char; + let grpid: *mut libc::c_char = dc_extract_grpid_from_rfc724_mid(str); + assert_eq!(to_string(grpid), "1234567890123456"); + free(grpid as *mut libc::c_void); + } + } + } From d5168916dfb611fbd14c5e1fed17b0039e205830 Mon Sep 17 00:00:00 2001 From: jikstra Date: Sat, 3 Aug 2019 14:47:24 +0200 Subject: [PATCH 55/95] Refactor dc_extract_grpid_from_rfc724_mid_list and rename test --- src/dc_tools.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index d0aa40148..957f50f28 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -821,9 +821,9 @@ pub fn dc_extract_grpid_from_rfc724_mid_r(mid: String) -> Option { None } -pub fn dc_extract_grpid_from_rfc724_mid(mid: *const libc::c_char) -> *mut libc::c_char { +pub unsafe fn dc_extract_grpid_from_rfc724_mid(mid: *const libc::c_char) -> *mut libc::c_char { if let Some(grpid) = dc_extract_grpid_from_rfc724_mid_r(to_string(mid)) { - return unsafe { to_cstring(grpid) }; + return to_cstring(grpid); } 0 as *mut libc::c_char } @@ -832,14 +832,14 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut if !list.is_null() { let mut cur: *mut clistiter = (*list).first; while !cur.is_null() { - let mid: *const libc::c_char = (if !cur.is_null() { - (*cur).data + let mid = if !cur.is_null() { + to_string((*cur).data as *const libc::c_char) } else { - 0 as *mut libc::c_void - }) as *const libc::c_char; - let grpid = dc_extract_grpid_from_rfc724_mid_r(to_string(mid)); - if !grpid.is_none() { - return to_cstring(grpid.unwrap()); + "".to_string() + }; + + if let Some(grpid) = dc_extract_grpid_from_rfc724_mid_r(mid) { + return to_cstring(grpid); } cur = if !cur.is_null() { (*cur).next @@ -2119,7 +2119,7 @@ mod tests { } #[test] - fn test_dto_cstringto_cstringc_extract_grpid_from_rfc724_mid() { + fn test_dc_extract_grpid_from_rfc724_mid() { unsafe { // Should return 0 if we pass invalid mid let str = b"foobar\x00" as *const u8 as *const libc::c_char; From ff95c44d51cef080347c0600e2e95da54d501f1a Mon Sep 17 00:00:00 2001 From: jikstra Date: Sat, 3 Aug 2019 15:05:47 +0200 Subject: [PATCH 56/95] Make receive_imf use safe version of dc_extract_grpid_from_rfc724_mid - Remove unused unsafe wrapper - Adjust tests to use safe version --- src/dc_receive_imf.rs | 6 ++++- src/dc_tools.rs | 51 +++++++++++++++---------------------------- 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 606ab43de..817e7cfcc 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -948,7 +948,11 @@ unsafe fn create_or_lookup_group( if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_MESSAGE_ID as libc::c_int { let fld_message_id: *mut mailimf_message_id = (*field).fld_data.fld_message_id; if !fld_message_id.is_null() { - grpid = dc_extract_grpid_from_rfc724_mid((*fld_message_id).mid_value) + if let Some(_grpid) = dc_extract_grpid_from_rfc724_mid(to_string((*fld_message_id).mid_value)) { + grpid = to_cstring(_grpid); + } else { + grpid = 0 as *mut libc::c_char; + } } } if grpid.is_null() { diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 957f50f28..bee2decbf 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -803,7 +803,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( ret } -pub fn dc_extract_grpid_from_rfc724_mid_r(mid: String) -> Option { +pub fn dc_extract_grpid_from_rfc724_mid(mid: String) -> Option { /* extract our group ID from Message-IDs as `Gr.12345678901.morerandom@domain.de`; "12345678901" is the wanted ID in this example. */ if !(mid.len() > 8 && mid.starts_with("Gr.")) { return None; @@ -821,13 +821,6 @@ pub fn dc_extract_grpid_from_rfc724_mid_r(mid: String) -> Option { None } -pub unsafe fn dc_extract_grpid_from_rfc724_mid(mid: *const libc::c_char) -> *mut libc::c_char { - if let Some(grpid) = dc_extract_grpid_from_rfc724_mid_r(to_string(mid)) { - return to_cstring(grpid); - } - 0 as *mut libc::c_char -} - pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut libc::c_char { if !list.is_null() { let mut cur: *mut clistiter = (*list).first; @@ -838,7 +831,7 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut "".to_string() }; - if let Some(grpid) = dc_extract_grpid_from_rfc724_mid_r(mid) { + if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(mid) { return to_cstring(grpid); } cur = if !cur.is_null() { @@ -2120,33 +2113,25 @@ mod tests { #[test] fn test_dc_extract_grpid_from_rfc724_mid() { - unsafe { - // Should return 0 if we pass invalid mid - let str = b"foobar\x00" as *const u8 as *const libc::c_char; - let grpid: *mut libc::c_char = dc_extract_grpid_from_rfc724_mid(str); - assert_eq!(grpid, 0 as *mut libc::c_char); - free(grpid as *mut libc::c_void); + // Should return 0 if we pass invalid mid + let str = "foobar".to_string(); + let grpid = dc_extract_grpid_from_rfc724_mid(str); + assert_eq!(grpid, None); - // Should return 0 if grpid has a length which is not 11 or 16 - let str = b"Gr.12345678.morerandom@domain.de\x00" as *const u8 as *const libc::c_char; - let grpid: *mut libc::c_char = dc_extract_grpid_from_rfc724_mid(str); - assert_eq!(grpid, 0 as *mut libc::c_char); - free(grpid as *mut libc::c_void); + // Should return 0 if grpid has a length which is not 11 or 16 + let str = "Gr.12345678.morerandom@domain.de".to_string(); + let grpid = dc_extract_grpid_from_rfc724_mid(str); + assert_eq!(grpid, None); - // Should return extracted grpid for grpid with length of 11 - let str = - b"Gr.12345678901.morerandom@domain.de\x00" as *const u8 as *const libc::c_char; - let grpid: *mut libc::c_char = dc_extract_grpid_from_rfc724_mid(str); - assert_eq!(to_string(grpid), "12345678901"); - free(grpid as *mut libc::c_void); + // Should return extracted grpid for grpid with length of 11 + let str = "Gr.12345678901.morerandom@domain.de".to_string(); + let grpid = dc_extract_grpid_from_rfc724_mid(str); + assert_eq!(grpid, Some("12345678901".to_string())); - // Should return extracted grpid for grpid with length of 11 - let str = - b"Gr.1234567890123456.morerandom@domain.de\x00" as *const u8 as *const libc::c_char; - let grpid: *mut libc::c_char = dc_extract_grpid_from_rfc724_mid(str); - assert_eq!(to_string(grpid), "1234567890123456"); - free(grpid as *mut libc::c_void); - } + // Should return extracted grpid for grpid with length of 11 + let str = "Gr.1234567890123456.morerandom@domain.de".to_string(); + let grpid = dc_extract_grpid_from_rfc724_mid(str); + assert_eq!(grpid, Some("1234567890123456".to_string())); } } From b74a86f617aea6ee3c0b28166cd5d2b7c85b42b6 Mon Sep 17 00:00:00 2001 From: jikstra Date: Sat, 3 Aug 2019 15:10:36 +0200 Subject: [PATCH 57/95] Run cargo fmt --- src/dc_receive_imf.rs | 4 +++- src/dc_tools.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 817e7cfcc..568a90b19 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -948,7 +948,9 @@ unsafe fn create_or_lookup_group( if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_MESSAGE_ID as libc::c_int { let fld_message_id: *mut mailimf_message_id = (*field).fld_data.fld_message_id; if !fld_message_id.is_null() { - if let Some(_grpid) = dc_extract_grpid_from_rfc724_mid(to_string((*fld_message_id).mid_value)) { + if let Some(_grpid) = + dc_extract_grpid_from_rfc724_mid(to_string((*fld_message_id).mid_value)) + { grpid = to_cstring(_grpid); } else { grpid = 0 as *mut libc::c_char; diff --git a/src/dc_tools.rs b/src/dc_tools.rs index bee2decbf..23391ec86 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -830,7 +830,7 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut } else { "".to_string() }; - + if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(mid) { return to_cstring(grpid); } From 45eec35e6e15d735bb005e87b3bedbe3200691c5 Mon Sep 17 00:00:00 2001 From: jikstra Date: Sat, 3 Aug 2019 15:25:46 +0200 Subject: [PATCH 58/95] Make dc_extract_grpid_from_rfc724_mid take/return &str instead of String --- src/dc_receive_imf.rs | 2 +- src/dc_tools.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 568a90b19..b52baa0b7 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -949,7 +949,7 @@ unsafe fn create_or_lookup_group( let fld_message_id: *mut mailimf_message_id = (*field).fld_data.fld_message_id; if !fld_message_id.is_null() { if let Some(_grpid) = - dc_extract_grpid_from_rfc724_mid(to_string((*fld_message_id).mid_value)) + dc_extract_grpid_from_rfc724_mid(as_str((*fld_message_id).mid_value)) { grpid = to_cstring(_grpid); } else { diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 23391ec86..c55b357d5 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -803,7 +803,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( ret } -pub fn dc_extract_grpid_from_rfc724_mid(mid: String) -> Option { +pub fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> { /* extract our group ID from Message-IDs as `Gr.12345678901.morerandom@domain.de`; "12345678901" is the wanted ID in this example. */ if !(mid.len() > 8 && mid.starts_with("Gr.")) { return None; @@ -813,7 +813,7 @@ pub fn dc_extract_grpid_from_rfc724_mid(mid: String) -> Option { if let Some(grpid_len) = mid_without_offset.find('.') { /* strict length comparison, the 'Gr.' magic is weak enough */ if grpid_len == 11 || grpid_len == 16 { - return Some(mid_without_offset.get(0..grpid_len).unwrap().to_string()); + return Some(mid_without_offset.get(0..grpid_len).unwrap()); } } } @@ -826,9 +826,9 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut let mut cur: *mut clistiter = (*list).first; while !cur.is_null() { let mid = if !cur.is_null() { - to_string((*cur).data as *const libc::c_char) + as_str((*cur).data as *const libc::c_char) } else { - "".to_string() + "" }; if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(mid) { @@ -2114,24 +2114,24 @@ mod tests { #[test] fn test_dc_extract_grpid_from_rfc724_mid() { // Should return 0 if we pass invalid mid - let str = "foobar".to_string(); + let str = "foobar"; let grpid = dc_extract_grpid_from_rfc724_mid(str); assert_eq!(grpid, None); // Should return 0 if grpid has a length which is not 11 or 16 - let str = "Gr.12345678.morerandom@domain.de".to_string(); + let str = "Gr.12345678.morerandom@domain.de"; let grpid = dc_extract_grpid_from_rfc724_mid(str); assert_eq!(grpid, None); // Should return extracted grpid for grpid with length of 11 - let str = "Gr.12345678901.morerandom@domain.de".to_string(); + let str = "Gr.12345678901.morerandom@domain.de"; let grpid = dc_extract_grpid_from_rfc724_mid(str); assert_eq!(grpid, Some("12345678901".to_string())); // Should return extracted grpid for grpid with length of 11 - let str = "Gr.1234567890123456.morerandom@domain.de".to_string(); + let str = "Gr.1234567890123456.morerandom@domain.de"; let grpid = dc_extract_grpid_from_rfc724_mid(str); - assert_eq!(grpid, Some("1234567890123456".to_string())); + assert_eq!(grpid, Some("1234567890123456")); } } From 9ecd0f80dcb709c79fa068e48ca752610080a035 Mon Sep 17 00:00:00 2001 From: jikstra Date: Sat, 3 Aug 2019 15:30:02 +0200 Subject: [PATCH 59/95] Fix test and simplify if gate --- src/dc_tools.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index c55b357d5..e1e5423e6 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -805,7 +805,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( pub fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> { /* extract our group ID from Message-IDs as `Gr.12345678901.morerandom@domain.de`; "12345678901" is the wanted ID in this example. */ - if !(mid.len() > 8 && mid.starts_with("Gr.")) { + if mid.len() < 9 || !mid.starts_with("Gr.") { return None; } @@ -2126,7 +2126,7 @@ mod tests { // Should return extracted grpid for grpid with length of 11 let str = "Gr.12345678901.morerandom@domain.de"; let grpid = dc_extract_grpid_from_rfc724_mid(str); - assert_eq!(grpid, Some("12345678901".to_string())); + assert_eq!(grpid, Some("12345678901")); // Should return extracted grpid for grpid with length of 11 let str = "Gr.1234567890123456.morerandom@domain.de"; From 5b368960c00b70a333254f93b2d3fa4d4cd5d94a Mon Sep 17 00:00:00 2001 From: jikstra Date: Sun, 4 Aug 2019 13:20:04 +0200 Subject: [PATCH 60/95] Apply requested changes --- src/dc_receive_imf.rs | 4 ++-- src/dc_tools.rs | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index b52baa0b7..21010d955 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -948,10 +948,10 @@ unsafe fn create_or_lookup_group( if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_MESSAGE_ID as libc::c_int { let fld_message_id: *mut mailimf_message_id = (*field).fld_data.fld_message_id; if !fld_message_id.is_null() { - if let Some(_grpid) = + if let Some(extracted_grpid) = dc_extract_grpid_from_rfc724_mid(as_str((*fld_message_id).mid_value)) { - grpid = to_cstring(_grpid); + grpid = extracted_grpid.strdup(); } else { grpid = 0 as *mut libc::c_char; } diff --git a/src/dc_tools.rs b/src/dc_tools.rs index e1e5423e6..f84d36d33 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -832,7 +832,7 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut }; if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(mid) { - return to_cstring(grpid); + return grpid.strdup(); } cur = if !cur.is_null() { (*cur).next @@ -2113,24 +2113,24 @@ mod tests { #[test] fn test_dc_extract_grpid_from_rfc724_mid() { - // Should return 0 if we pass invalid mid - let str = "foobar"; - let grpid = dc_extract_grpid_from_rfc724_mid(str); + // Should return None if we pass invalid mid + let mid = "foobar"; + let grpid = dc_extract_grpid_from_rfc724_mid(mid); assert_eq!(grpid, None); - // Should return 0 if grpid has a length which is not 11 or 16 - let str = "Gr.12345678.morerandom@domain.de"; - let grpid = dc_extract_grpid_from_rfc724_mid(str); + // Should return None if grpid has a length which is not 11 or 16 + let mid = "Gr.12345678.morerandom@domain.de"; + let grpid = dc_extract_grpid_from_rfc724_mid(mid); assert_eq!(grpid, None); // Should return extracted grpid for grpid with length of 11 - let str = "Gr.12345678901.morerandom@domain.de"; - let grpid = dc_extract_grpid_from_rfc724_mid(str); + let mid = "Gr.12345678901.morerandom@domain.de"; + let grpid = dc_extract_grpid_from_rfc724_mid(mid); assert_eq!(grpid, Some("12345678901")); // Should return extracted grpid for grpid with length of 11 - let str = "Gr.1234567890123456.morerandom@domain.de"; - let grpid = dc_extract_grpid_from_rfc724_mid(str); + let mid = "Gr.1234567890123456.morerandom@domain.de"; + let grpid = dc_extract_grpid_from_rfc724_mid(mid); assert_eq!(grpid, Some("1234567890123456")); } From 205e2d4e99d9e690e7100857899ac60258b4fc16 Mon Sep 17 00:00:00 2001 From: jikstra Date: Sun, 4 Aug 2019 16:43:59 +0200 Subject: [PATCH 61/95] Fix rustdoc --- src/dc_tools.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index f84d36d33..57da76fef 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -803,8 +803,10 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( ret } + +/// Extract our group ID from Message-IDs as `Gr.12345678901.morerandom@domain.de` +/// `12345678901` is the wanted ID in this example. pub fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> { - /* extract our group ID from Message-IDs as `Gr.12345678901.morerandom@domain.de`; "12345678901" is the wanted ID in this example. */ if mid.len() < 9 || !mid.starts_with("Gr.") { return None; } From 10689f45f4a48826e8972008ce45f2ffe3c7210a Mon Sep 17 00:00:00 2001 From: jikstra Date: Sun, 4 Aug 2019 16:51:18 +0200 Subject: [PATCH 62/95] cargo fmt --- src/dc_tools.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 57da76fef..8f829aee1 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -803,7 +803,6 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( ret } - /// Extract our group ID from Message-IDs as `Gr.12345678901.morerandom@domain.de` /// `12345678901` is the wanted ID in this example. pub fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> { From c0b1e41820ed36ef9730af7e04b313dc6f451897 Mon Sep 17 00:00:00 2001 From: jikstra Date: Mon, 5 Aug 2019 12:10:22 +0200 Subject: [PATCH 63/95] Improve function documentation --- src/dc_tools.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 8f829aee1..40f78c75e 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -803,8 +803,19 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( ret } -/// Extract our group ID from Message-IDs as `Gr.12345678901.morerandom@domain.de` -/// `12345678901` is the wanted ID in this example. +/// Extract the group id (grpid) from a message id (mid) +/// +/// # Arguments +/// +/// * `mid` - A string that holds the message id +/// +/// # Examples +/// +/// ``` +/// let mid = "Gr.12345678901.morerandom@domain.de"; +/// let grpid = dc_extract_grpid_from_rfc724_mid(mid); +/// assert_eq!(grpid, Some("12345678901")); +/// ``` pub fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> { if mid.len() < 9 || !mid.starts_with("Gr.") { return None; From 76d3d86a9e58be45d5a11c02c028a1f179eb23b9 Mon Sep 17 00:00:00 2001 From: jikstra Date: Mon, 5 Aug 2019 12:54:03 +0200 Subject: [PATCH 64/95] import dc_extract... method for rustdoc example --- src/dc_tools.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 40f78c75e..ae63098df 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -812,6 +812,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( /// # Examples /// /// ``` +/// use deltachat::dc_tools::dc_extract_grpid_from_rfc724_mid; /// let mid = "Gr.12345678901.morerandom@domain.de"; /// let grpid = dc_extract_grpid_from_rfc724_mid(mid); /// assert_eq!(grpid, Some("12345678901")); From 4d9bd46c9d48ba8c51effd03ebba56a8b79fc441 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Fri, 26 Jul 2019 23:12:05 +0000 Subject: [PATCH 65/95] Add note about possible cause of lost messages --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 892fdf2bb..546731af3 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,11 @@ Single#10: yourfriends@email.org [yourfriends@email.org] Message sent. ``` +If `yourfriend@email.org` uses DeltaChat, but does not receive message just +sent, it is advisable to check `Spam` folder. It is known that at least +`gmx.com` treat such test messages as spam, unless told otherwise with web +interface. + List messages when inside a chat: ``` From 164130a83fb5d24ade0a37f7210c19d18bb2435e Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 19:00:28 +0200 Subject: [PATCH 66/95] Replace gotos with ok_to_continue (is_valid) approach --- src/dc_saxparser.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/dc_saxparser.rs b/src/dc_saxparser.rs index 57e44fde2..3244a634d 100644 --- a/src/dc_saxparser.rs +++ b/src/dc_saxparser.rs @@ -80,7 +80,7 @@ pub unsafe fn dc_saxparser_set_text_handler( } pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *const libc::c_char) { - let current_block: u64; + let mut is_valid = false; let mut bak: libc::c_char; let buf_start: *mut libc::c_char; let mut last_text_start: *mut libc::c_char; @@ -99,7 +99,7 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c p = buf_start; loop { if !(0 != *p) { - current_block = 13425230902034816933; + is_valid = true; break; } if *p as libc::c_int == '<' as i32 { @@ -113,7 +113,6 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c if strncmp(p, b"!--\x00" as *const u8 as *const libc::c_char, 3) == 0i32 { p = strstr(p, b"-->\x00" as *const u8 as *const libc::c_char); if p.is_null() { - current_block = 7627180618761592946; break; } p = p.offset(3isize) @@ -137,7 +136,6 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c strlen(text_beg), 'c' as i32 as libc::c_char, ); - current_block = 7627180618761592946; break; } } else if strncmp(p, b"!DOCTYPE\x00" as *const u8 as *const libc::c_char, 8) == 0i32 { @@ -149,13 +147,11 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c } if *p as libc::c_int == 0i32 { /* unclosed doctype */ - current_block = 7627180618761592946; break; } else if *p as libc::c_int == '[' as i32 { p = strstr(p, b"]>\x00" as *const u8 as *const libc::c_char); if p.is_null() { /* unclosed inline doctype */ - current_block = 7627180618761592946; break; } else { p = p.offset(2isize) @@ -167,7 +163,6 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c p = strstr(p, b"?>\x00" as *const u8 as *const libc::c_char); if p.is_null() { /* unclosed processing instruction */ - current_block = 7627180618761592946; break; } else { p = p.offset(2isize) @@ -328,7 +323,6 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c p = strchr(p, '>' as i32); if p.is_null() { /* unclosed start-tag or end-tag */ - current_block = 7627180618761592946; break; } else { p = p.offset(1isize) @@ -339,16 +333,13 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c p = p.offset(1isize) } } - match current_block { - 13425230902034816933 => { + if is_valid { call_text_cb( saxparser, last_text_start, p.wrapping_offset_from(last_text_start) as size_t, '&' as i32 as libc::c_char, ); - } - _ => {} } do_free_attr(attr.as_mut_ptr(), free_attr.as_mut_ptr()); free(buf_start as *mut libc::c_void); From c0e3c7a9dfe7d9e671cb6f116a7721aa5d1b6d81 Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 19:01:24 +0200 Subject: [PATCH 67/95] run cargo fmt --- src/dc_saxparser.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/dc_saxparser.rs b/src/dc_saxparser.rs index 3244a634d..2c7b669d7 100644 --- a/src/dc_saxparser.rs +++ b/src/dc_saxparser.rs @@ -80,7 +80,7 @@ pub unsafe fn dc_saxparser_set_text_handler( } pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *const libc::c_char) { - let mut is_valid = false; + let mut is_valid = false; let mut bak: libc::c_char; let buf_start: *mut libc::c_char; let mut last_text_start: *mut libc::c_char; @@ -99,7 +99,7 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c p = buf_start; loop { if !(0 != *p) { - is_valid = true; + is_valid = true; break; } if *p as libc::c_int == '<' as i32 { @@ -333,13 +333,13 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c p = p.offset(1isize) } } - if is_valid { - call_text_cb( - saxparser, - last_text_start, - p.wrapping_offset_from(last_text_start) as size_t, - '&' as i32 as libc::c_char, - ); + if is_valid { + call_text_cb( + saxparser, + last_text_start, + p.wrapping_offset_from(last_text_start) as size_t, + '&' as i32 as libc::c_char, + ); } do_free_attr(attr.as_mut_ptr(), free_attr.as_mut_ptr()); free(buf_start as *mut libc::c_void); From acb3d14d7ddce33e583342ebab62ffd1c82f4163 Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 19:14:35 +0200 Subject: [PATCH 68/95] remove gotos in dc_e2ee in dcrypt_part function --- src/dc_e2ee.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index 70e77544a..d157f76c0 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -835,7 +835,7 @@ unsafe fn decrypt_part( ret_valid_signatures: &mut HashSet, ret_decrypted_mime: *mut *mut mailmime, ) -> libc::c_int { - let current_block: u64; + let ok_to_continue = true; let mime_data: *mut mailmime_data; let mut mime_transfer_encoding: libc::c_int = MAILMIME_MECHANISM_BINARY as libc::c_int; /* mmap_string_unref()'d if set */ @@ -883,9 +883,7 @@ unsafe fn decrypt_part( decoded_data_bytes = (*mime_data).dt_data.dt_text.dt_length; if decoded_data.is_null() || decoded_data_bytes <= 0 { /* no error - but no data */ - current_block = 2554982661806928548; - } else { - current_block = 4488286894823169796; + ok_to_continue = false; } } else { let r: libc::c_int; @@ -902,15 +900,12 @@ unsafe fn decrypt_part( || transfer_decoding_buffer.is_null() || decoded_data_bytes <= 0 { - current_block = 2554982661806928548; + ok_to_continue = false; } else { decoded_data = transfer_decoding_buffer; - current_block = 4488286894823169796; } } - match current_block { - 2554982661806928548 => {} - _ => { + if ok_to_continue { /* encrypted, decoded data in decoded_data now ... */ if !(0 == has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int)) { @@ -950,7 +945,6 @@ unsafe fn decrypt_part( } } } - } } } //mailmime_substitute(mime, new_mime); From b715df9e9708eab11266850d6832a5b0db2d1067 Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 19:16:21 +0200 Subject: [PATCH 69/95] make ok_to_continue variable mutable --- src/dc_e2ee.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index d157f76c0..4194b77a2 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -835,7 +835,7 @@ unsafe fn decrypt_part( ret_valid_signatures: &mut HashSet, ret_decrypted_mime: *mut *mut mailmime, ) -> libc::c_int { - let ok_to_continue = true; + let mut ok_to_continue = true; let mime_data: *mut mailmime_data; let mut mime_transfer_encoding: libc::c_int = MAILMIME_MECHANISM_BINARY as libc::c_int; /* mmap_string_unref()'d if set */ From d4650ba4a984ca81333deaa8064971a361e311dc Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Sun, 4 Aug 2019 13:34:42 +0000 Subject: [PATCH 70/95] Add Rust clone of python `prepare_and_send' test Previous version of patch, that changed type of `dc_msg_t.text' to String had been breaking `prepare_and_send' test in Python. This commit adds same regression test, reimplemented in Rust, since running Rust tests is simplier and faster. --- src/dc_msg.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/dc_msg.rs b/src/dc_msg.rs index 596347610..b0d8bb731 100644 --- a/src/dc_msg.rs +++ b/src/dc_msg.rs @@ -1426,6 +1426,7 @@ pub fn dc_update_server_uid( #[cfg(test)] mod tests { use super::*; + use crate::test_utils as test; use std::ffi::CStr; #[test] @@ -1546,4 +1547,36 @@ mod tests { free(mime_0 as *mut libc::c_void); } } + + #[test] + pub fn test_prepare_message_and_send() { + use crate::config::Config; + + unsafe { + let d = test::dummy_context(); + let ctx = &d.ctx; + + let contact = dc_create_contact( + ctx, + b"\x00".as_ptr().cast(), + b"dest@example.com\x00".as_ptr().cast(), + ); + assert!(contact != 0); + + let res = ctx.set_config(Config::ConfiguredAddr, Some("self@example.com")); + assert!(res.is_ok()); + + let chat = dc_create_chat_by_contact_id(ctx, contact); + assert!(chat != 0); + + let msg = dc_msg_new(ctx, Viewtype::Text); + assert!(!msg.is_null()); + + let msg_id = dc_prepare_msg(ctx, chat, msg); + assert!(msg_id != 0); + + let msg2 = dc_get_msg(ctx, msg_id); + assert!(!msg2.is_null()); + } + } } From 765ac2005e4cbb9264416679b0571a04e791b57b Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Sat, 3 Aug 2019 11:53:46 +0000 Subject: [PATCH 71/95] Change type of dc_msg_t.text to String Also, remove `send-garbage' command from REPL, since it is not possible to send non-utf8 string anymore. --- deltachat-ffi/src/lib.rs | 1 + examples/repl/cmdline.rs | 19 ++----- examples/repl/main.rs | 3 +- examples/simple.rs | 3 +- src/dc_chat.rs | 104 +++++++++++++++------------------------ src/dc_location.rs | 5 +- src/dc_lot.rs | 12 ++++- src/dc_mimefactory.rs | 39 +++++++++------ src/dc_msg.rs | 48 ++++++++++++------ src/dc_securejoin.rs | 5 +- src/lib.rs | 2 +- 11 files changed, 117 insertions(+), 124 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 920a97a38..ea5539b35 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -374,6 +374,7 @@ pub unsafe extern "C" fn dc_send_text_msg( ) -> u32 { assert!(!context.is_null()); let context = &*context; + let text_to_send = dc_tools::to_string_lossy(text_to_send); dc_chat::dc_send_text_msg(context, chat_id, text_to_send) } diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 9c2d6f5da..30f27e67c 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -914,30 +914,17 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E ensure!(!sel_chat.is_null(), "No chat selected."); ensure!(!arg1.is_empty(), "No message text given."); - let msg = CString::yolo(format!("{} {}", arg1, arg2)); + let msg = format!("{} {}", arg1, arg2); - if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg.as_ptr()) { + if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg) { println!("Message sent."); } else { bail!("Sending failed."); } } - "send-garbage" => { - ensure!(!sel_chat.is_null(), "No chat selected."); - let msg = b"\xff\x00"; // NUL-terminated C-string, that is malformed utf-8 - if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg.as_ptr().cast()) { - println!("Malformed utf-8 succesfully send. Not nice."); - } else { - bail!("Garbage sending failed, as expected."); - } - } "sendempty" => { ensure!(!sel_chat.is_null(), "No chat selected."); - if 0 != dc_send_text_msg( - context, - dc_chat_get_id(sel_chat), - b"\x00" as *const u8 as *const libc::c_char, - ) { + if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), "".into()) { println!("Message sent."); } else { bail!("Sending failed."); diff --git a/examples/repl/main.rs b/examples/repl/main.rs index b023c801e..c3a47ccec 100644 --- a/examples/repl/main.rs +++ b/examples/repl/main.rs @@ -291,7 +291,7 @@ const DB_COMMANDS: [&'static str; 11] = [ "housekeeping", ]; -const CHAT_COMMANDS: [&'static str; 25] = [ +const CHAT_COMMANDS: [&'static str; 24] = [ "listchats", "listarchived", "chat", @@ -309,7 +309,6 @@ const CHAT_COMMANDS: [&'static str; 25] = [ "dellocations", "getlocations", "send", - "send-garbage", "sendimage", "sendfile", "draft", diff --git a/examples/simple.rs b/examples/simple.rs index fc80fda68..1ec8da0f1 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -97,8 +97,7 @@ fn main() { println!("sending a message"); let contact_id = dc_create_contact(&ctx, std::ptr::null(), email.as_ptr()); let chat_id = dc_create_chat_by_contact_id(&ctx, contact_id); - let msg_text = CString::new("Hi, here is my first message!").unwrap(); - dc_send_text_msg(&ctx, chat_id, msg_text.as_ptr()); + dc_send_text_msg(&ctx, chat_id, "Hi, here is my first message!".into()); println!("fetching chats.."); let chats = Chatlist::try_load(&ctx, 0, None, None).unwrap(); diff --git a/src/dc_chat.rs b/src/dc_chat.rs index c86e80f23..478f50b64 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -725,7 +725,7 @@ unsafe fn prepare_msg_raw( timestamp, (*msg).type_0, (*msg).state, - if !(*msg).text.is_null() { Some(as_str((*msg).text)) } else { None }, + (*msg).text, (*msg).param.to_string(), (*msg).hidden, to_string(new_in_reply_to), @@ -951,7 +951,7 @@ pub unsafe fn dc_send_msg<'a>( pub unsafe fn dc_send_text_msg( context: &Context, chat_id: uint32_t, - text_to_send: *const libc::c_char, + text_to_send: String, ) -> uint32_t { if chat_id <= 9 { warn!( @@ -961,18 +961,8 @@ pub unsafe fn dc_send_text_msg( return 0; } - if text_to_send.is_null() { - warn!(context, 0, "dc_send_text_msg: text_to_send is emtpy"); - return 0; - } - - if let Err(err) = as_str_safe(text_to_send) { - warn!(context, 0, "{}", err); - return 0; - } - let mut msg = dc_msg_new(context, Viewtype::Text); - (*msg).text = dc_strdup(text_to_send); + (*msg).text = Some(text_to_send); let ret = dc_send_msg(context, chat_id, msg); dc_msg_unref(msg); ret @@ -1002,9 +992,7 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t // save new draft if !msg.is_null() { if (*msg).type_0 == Viewtype::Text { - if (*msg).text.is_null() || *(*msg).text.offset(0isize) as libc::c_int == 0i32 { - OK_TO_CONTINUE = false; - } + OK_TO_CONTINUE = (*msg).text.as_ref().map_or(false, |s| !s.is_empty()); } else if msgtype_has_file((*msg).type_0) { let mut pathNfilename = (*msg) .param @@ -1037,11 +1025,7 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t time(), (*msg).type_0, DC_STATE_OUT_DRAFT, - if !(*msg).text.is_null() { - as_str((*msg).text) - } else { - "" - }, + (*msg).text.deref().unwrap_or(""), (*msg).param.to_string(), 1, ], @@ -1617,14 +1601,12 @@ pub unsafe fn dc_add_contact_to_chat_ex( if OK_TO_CONTINUE { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { (*msg).type_0 = Viewtype::Text; - (*msg).text = context - .stock_system_msg( - StockMessage::MsgAddMember, - as_str((*contact).addr), - "", - DC_CONTACT_ID_SELF as uint32_t, - ) - .strdup(); + (*msg).text = Some(context.stock_system_msg( + StockMessage::MsgAddMember, + as_str((*contact).addr), + "", + DC_CONTACT_ID_SELF as uint32_t, + )); (*msg).param.set_int(Param::Cmd, 4); if !(*contact).addr.is_null() { (*msg).param.set(Param::Arg, as_str((*contact).addr)); @@ -1732,23 +1714,19 @@ pub unsafe fn dc_remove_contact_from_chat( (*msg).type_0 = Viewtype::Text; if (*contact).id == 1 as libc::c_uint { dc_set_group_explicitly_left(context, (*chat).grpid); - (*msg).text = context - .stock_system_msg( - StockMessage::MsgGroupLeft, - "", - "", - DC_CONTACT_ID_SELF as u32, - ) - .strdup(); + (*msg).text = Some(context.stock_system_msg( + StockMessage::MsgGroupLeft, + "", + "", + DC_CONTACT_ID_SELF as u32, + )); } else { - (*msg).text = context - .stock_system_msg( - StockMessage::MsgDelMember, - as_str((*contact).addr), - "", - DC_CONTACT_ID_SELF as u32, - ) - .strdup(); + (*msg).text = Some(context.stock_system_msg( + StockMessage::MsgDelMember, + as_str((*contact).addr), + "", + DC_CONTACT_ID_SELF as u32, + )); } (*msg).param.set_int(Param::Cmd, 5); if !(*contact).addr.is_null() { @@ -1849,14 +1827,12 @@ pub unsafe fn dc_set_chat_name( { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { (*msg).type_0 = Viewtype::Text; - (*msg).text = context - .stock_system_msg( - StockMessage::MsgGrpName, - as_str((*chat).name), - as_str(new_name), - DC_CONTACT_ID_SELF as u32, - ) - .strdup(); + (*msg).text = Some(context.stock_system_msg( + StockMessage::MsgGrpName, + as_str((*chat).name), + as_str(new_name), + DC_CONTACT_ID_SELF as u32, + )); (*msg).param.set_int(Param::Cmd, 2); if !(*chat).name.is_null() { (*msg).param.set(Param::Arg, as_str((*chat).name)); @@ -1923,18 +1899,16 @@ pub unsafe fn dc_set_chat_profile_image( (*msg).param.set_int(Param::Cmd, 3); (*msg).param.set(Param::Arg, as_str(new_image_rel)); (*msg).type_0 = Viewtype::Text; - (*msg).text = context - .stock_system_msg( - if !new_image_rel.is_null() { - StockMessage::MsgGrpImgChanged - } else { - StockMessage::MsgGrpImgDeleted - }, - "", - "", - DC_CONTACT_ID_SELF as uint32_t, - ) - .strdup(); + (*msg).text = Some(context.stock_system_msg( + if !new_image_rel.is_null() { + StockMessage::MsgGrpImgChanged + } else { + StockMessage::MsgGrpImgDeleted + }, + "", + "", + DC_CONTACT_ID_SELF as uint32_t, + )); (*msg).id = dc_send_msg(context, chat_id, msg); context.call_cb( Event::MSGS_CHANGED, diff --git a/src/dc_location.rs b/src/dc_location.rs index c9e3ee66e..5e6e599ca 100644 --- a/src/dc_location.rs +++ b/src/dc_location.rs @@ -100,9 +100,8 @@ pub unsafe fn dc_send_locations_to_chat( { if 0 != seconds && !is_sending_locations_before { msg = dc_msg_new(context, Viewtype::Text); - (*msg).text = context - .stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0) - .strdup(); + (*msg).text = + Some(context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0)); (*msg).param.set_int(Param::Cmd, 8); dc_send_msg(context, chat_id, msg); } else if 0 == seconds && is_sending_locations_before { diff --git a/src/dc_lot.rs b/src/dc_lot.rs index 3d4c714de..8741b4341 100644 --- a/src/dc_lot.rs +++ b/src/dc_lot.rs @@ -6,6 +6,8 @@ use crate::dc_tools::*; use crate::stock::StockMessage; use crate::types::*; use crate::x::*; +use std::ffi::CString; +use std::ptr; /* * Structure behind dc_lot_t */ #[derive(Copy, Clone)] @@ -160,8 +162,16 @@ pub unsafe fn dc_lot_fill( (*lot).text1_meaning = 2i32 } } + + let msgtext_c = (*msg) + .text + .as_ref() + .map(|s| CString::yolo(String::as_str(s))); + let msgtext_ptr = msgtext_c.map_or(ptr::null(), |s| s.as_ptr()); + (*lot).text2 = - dc_msg_get_summarytext_by_raw((*msg).type_0, (*msg).text, &mut (*msg).param, 160, context); + dc_msg_get_summarytext_by_raw((*msg).type_0, msgtext_ptr, &mut (*msg).param, 160, context); + (*lot).timestamp = dc_msg_get_timestamp(msg); (*lot).state = (*msg).state; } diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 0cb95d780..5d0d9d3ad 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -9,6 +9,7 @@ use mmime::mailmime_types_helper::*; use mmime::mailmime_write_mem::*; use mmime::mmapstring::*; use mmime::other::*; +use std::ptr; use crate::constants::*; use crate::context::Context; @@ -799,12 +800,17 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: ) } - let mut final_text: *const libc::c_char = 0 as *const libc::c_char; - if !placeholdertext.is_null() { - final_text = placeholdertext - } else if !(*msg).text.is_null() && 0 != *(*msg).text.offset(0isize) as libc::c_int { - final_text = (*msg).text - } + let final_text = { + if !placeholdertext.is_null() { + to_string(placeholdertext) + } else if let Some(ref text) = (*msg).text { + text.clone() + } else { + "".into() + } + }; + let final_text = CString::yolo(final_text); + let footer: *mut libc::c_char = (*factory).selfstatus; message_text = dc_mprintf( b"%s%s%s%s%s\x00" as *const u8 as *const libc::c_char, @@ -813,12 +819,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: } else { b"\x00" as *const u8 as *const libc::c_char }, - if !final_text.is_null() { - final_text - } else { - b"\x00" as *const u8 as *const libc::c_char - }, - if !final_text.is_null() + final_text.as_ptr(), + if final_text != CString::yolo("") && !footer.is_null() && 0 != *footer.offset(0isize) as libc::c_int { @@ -1094,8 +1096,17 @@ unsafe fn get_subject( ) -> *mut libc::c_char { let context = (*chat).context; let ret: *mut libc::c_char; - let raw_subject = - dc_msg_get_summarytext_by_raw((*msg).type_0, (*msg).text, &mut (*msg).param, 32, context); + + let raw_subject = { + let msgtext_c = (*msg) + .text + .as_ref() + .map(|s| CString::yolo(String::as_str(s))); + let msgtext_ptr = msgtext_c.map_or(ptr::null(), |s| s.as_ptr()); + + dc_msg_get_summarytext_by_raw((*msg).type_0, msgtext_ptr, &mut (*msg).param, 32, context) + }; + let fwd = if 0 != afwd_email { b"Fwd: \x00" as *const u8 as *const libc::c_char } else { diff --git a/src/dc_msg.rs b/src/dc_msg.rs index b0d8bb731..109d5ebae 100644 --- a/src/dc_msg.rs +++ b/src/dc_msg.rs @@ -14,6 +14,7 @@ use crate::sql; use crate::stock::StockMessage; use crate::types::*; use crate::x::*; +use std::ptr; /* * the structure behind dc_msg_t */ #[derive(Clone)] @@ -31,7 +32,7 @@ pub struct dc_msg_t<'a> { pub timestamp_sort: i64, pub timestamp_sent: i64, pub timestamp_rcvd: i64, - pub text: *mut libc::c_char, + pub text: Option, pub context: &'a Context, pub rfc724_mid: *mut libc::c_char, pub in_reply_to: *mut libc::c_char, @@ -241,7 +242,7 @@ pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut d timestamp_sort: 0, timestamp_sent: 0, timestamp_rcvd: 0, - text: std::ptr::null_mut(), + text: None, context, rfc724_mid: std::ptr::null_mut(), in_reply_to: std::ptr::null_mut(), @@ -270,8 +271,6 @@ pub unsafe fn dc_msg_empty(mut msg: *mut dc_msg_t) { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { return; } - free((*msg).text as *mut libc::c_void); - (*msg).text = 0 as *mut libc::c_char; free((*msg).rfc724_mid as *mut libc::c_void); (*msg).rfc724_mid = 0 as *mut libc::c_char; free((*msg).in_reply_to as *mut libc::c_void); @@ -479,19 +478,25 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id: (*msg).type_0 = row.get(12)?; (*msg).state = row.get(13)?; (*msg).is_dc_message = row.get(14)?; - (*msg).text = row.get::<_, String>(15).unwrap_or_default().strdup(); + (*msg).text = row.get::<_, Option>(15)?; (*msg).param = row.get::<_, String>(16)?.parse().unwrap_or_default(); (*msg).starred = row.get(17)?; (*msg).hidden = row.get(18)?; (*msg).location_id = row.get(19)?; (*msg).chat_blocked = row.get::<_, Option>(20)?.unwrap_or_default(); if (*msg).chat_blocked == 2 { - dc_truncate_n_unwrap_str((*msg).text, 256, 0); - } - } + if let Some(ref text) = (*msg).text { + let ptr = text.strdup(); + + dc_truncate_n_unwrap_str(ptr, 256, 0); + + (*msg).text = Some(to_string(ptr)); + free(ptr.cast()); + } + }; Ok(()) - } - ); + } + }); res.is_ok() } @@ -705,9 +710,11 @@ pub unsafe fn dc_msg_get_text(msg: *const dc_msg_t) -> *mut libc::c_char { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { return dc_strdup(0 as *const libc::c_char); } - - let res = dc_truncate_str(as_str((*msg).text), 30000); - res.strdup() + if let Some(ref text) = (*msg).text { + dc_truncate_str(text, 30000).strdup() + } else { + ptr::null_mut() + } } #[allow(non_snake_case)] @@ -827,9 +834,15 @@ pub unsafe fn dc_msg_get_summarytext( return dc_strdup(0 as *const libc::c_char); } + let msgtext_c = (*msg) + .text + .as_ref() + .map(|s| CString::yolo(String::as_str(s))); + let msgtext_ptr = msgtext_c.map_or(ptr::null(), |s| s.as_ptr()); + dc_msg_get_summarytext_by_raw( (*msg).type_0, - (*msg).text, + msgtext_ptr, &mut (*msg).param, approx_characters, (*msg).context, @@ -1049,8 +1062,11 @@ pub unsafe fn dc_msg_set_text(mut msg: *mut dc_msg_t, text: *const libc::c_char) if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { return; } - free((*msg).text as *mut libc::c_void); - (*msg).text = dc_strdup(text); + (*msg).text = if text.is_null() { + None + } else { + Some(to_string(text)) + }; } pub unsafe fn dc_msg_set_file( diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index 90573412f..edcdacffa 100644 --- a/src/dc_securejoin.rs +++ b/src/dc_securejoin.rs @@ -264,10 +264,7 @@ unsafe fn send_handshake_msg( ) { let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context); (*msg).type_0 = Viewtype::Text; - (*msg).text = dc_mprintf( - b"Secure-Join: %s\x00" as *const u8 as *const libc::c_char, - step, - ); + (*msg).text = Some(format!("Secure-Join: {}", to_string(step))); (*msg).hidden = 1; (*msg).param.set_int(Param::Cmd, 7); if step.is_null() { diff --git a/src/lib.rs b/src/lib.rs index f735de035..34a2fd496 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(c_variadic, ptr_wrapping_offset_from, ptr_cast)] +#![feature(c_variadic, ptr_wrapping_offset_from, ptr_cast, inner_deref)] #[macro_use] extern crate failure_derive; From bc2314586ccc4d725e3bb9ea2dcdaf5b27d824ae Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Sun, 4 Aug 2019 17:40:29 +0000 Subject: [PATCH 72/95] Avoid unstable `inner_deref' feature --- src/dc_chat.rs | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dc_chat.rs b/src/dc_chat.rs index 478f50b64..ec38aeb80 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -1025,7 +1025,7 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t time(), (*msg).type_0, DC_STATE_OUT_DRAFT, - (*msg).text.deref().unwrap_or(""), + (*msg).text.as_ref().map(String::as_str).unwrap_or(""), (*msg).param.to_string(), 1, ], diff --git a/src/lib.rs b/src/lib.rs index 34a2fd496..f735de035 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(c_variadic, ptr_wrapping_offset_from, ptr_cast, inner_deref)] +#![feature(c_variadic, ptr_wrapping_offset_from, ptr_cast)] #[macro_use] extern crate failure_derive; From 760332262d48031d48b2b3048820b76cd50e234e Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Mon, 5 Aug 2019 14:14:54 +0000 Subject: [PATCH 73/95] Add more assertions to `deltachat-ffi' library Change code to panic! on invalid input (null pointers, out-of-range identifiers) instead of silently doing nothing. --- deltachat-ffi/src/lib.rs | 251 ++++++++++++++++++++++++++++++++++----- 1 file changed, 222 insertions(+), 29 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index ea5539b35..5652c450c 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -12,7 +12,6 @@ extern crate human_panic; extern crate num_traits; use num_traits::{FromPrimitive, ToPrimitive}; -use std::ptr; use std::str::FromStr; use deltachat::dc_tools::StrExt; @@ -123,13 +122,14 @@ pub unsafe extern "C" fn dc_get_config( key: *mut libc::c_char, ) -> *mut libc::c_char { assert!(!context.is_null()); - assert!(!key.is_null(), "invalid key"); let context = &*context; - match config::Config::from_str(dc_tools::as_str(key)) { - Ok(key) => context.get_config(key).unwrap_or_default().strdup(), - Err(_) => std::ptr::null_mut(), - } + assert!(!key.is_null(), "invalid key pointer"); + let key = config::Config::from_str(dc_tools::as_str(key)).expect("invalid key"); + + // TODO: Translating None to NULL would be more sensible than translating None + // to "", as it is now. + context.get_config(key).unwrap_or_default().strdup() } #[no_mangle] @@ -349,6 +349,7 @@ pub unsafe extern "C" fn dc_prepare_msg( msg: *mut dc_msg::dc_msg_t, ) -> u32 { assert!(!context.is_null()); + assert!(!msg.is_null()); let context = &*context; dc_chat::dc_prepare_msg(context, chat_id, msg) @@ -361,6 +362,7 @@ pub unsafe extern "C" fn dc_send_msg( msg: *mut dc_msg::dc_msg_t, ) -> u32 { assert!(!context.is_null()); + assert!(!msg.is_null()); let context = &*context; dc_chat::dc_send_msg(context, chat_id, msg) @@ -373,6 +375,7 @@ pub unsafe extern "C" fn dc_send_text_msg( text_to_send: *mut libc::c_char, ) -> u32 { assert!(!context.is_null()); + assert!(!text_to_send.is_null()); let context = &*context; let text_to_send = dc_tools::to_string_lossy(text_to_send); @@ -479,15 +482,13 @@ pub unsafe extern "C" fn dc_get_chat_media( assert!(!context.is_null()); let context = &*context; - if let (Some(msg_type), Some(or_msg_type2), Some(or_msg_type3)) = ( - from_prim(msg_type), - from_prim(or_msg_type2), - from_prim(or_msg_type3), - ) { - dc_chat::dc_get_chat_media(context, chat_id, msg_type, or_msg_type2, or_msg_type3) - } else { - ptr::null_mut() - } + let msg_type = from_prim(msg_type).expect(&format!("invalid msg_type = {}", msg_type)); + let or_msg_type2 = + from_prim(or_msg_type2).expect(&format!("incorrect or_msg_type2 = {}", or_msg_type2)); + let or_msg_type3 = + from_prim(or_msg_type3).expect(&format!("incorrect or_msg_type3 = {}", or_msg_type3)); + + dc_chat::dc_get_chat_media(context, chat_id, msg_type, or_msg_type2, or_msg_type3) } #[no_mangle] @@ -502,15 +503,13 @@ pub unsafe extern "C" fn dc_get_next_media( assert!(!context.is_null()); let context = &*context; - if let (Some(msg_type), Some(or_msg_type2), Some(or_msg_type3)) = ( - from_prim(msg_type), - from_prim(or_msg_type2), - from_prim(or_msg_type3), - ) { - dc_chat::dc_get_next_media(context, msg_id, dir, msg_type, or_msg_type2, or_msg_type3) - } else { - 0 - } + let msg_type = from_prim(msg_type).expect(&format!("invalid msg_type = {}", msg_type)); + let or_msg_type2 = + from_prim(or_msg_type2).expect(&format!("incorrect or_msg_type2 = {}", or_msg_type2)); + let or_msg_type3 = + from_prim(or_msg_type3).expect(&format!("incorrect or_msg_type3 = {}", or_msg_type3)); + + dc_chat::dc_get_next_media(context, msg_id, dir, msg_type, or_msg_type2, or_msg_type3) } #[no_mangle] @@ -552,6 +551,7 @@ pub unsafe extern "C" fn dc_search_msgs( query: *mut libc::c_char, ) -> *mut dc_array::dc_array_t { assert!(!context.is_null()); + assert!(!query.is_null()); let context = &*context; context::dc_search_msgs(context, chat_id, query) @@ -575,6 +575,7 @@ pub unsafe extern "C" fn dc_create_group_chat( name: *mut libc::c_char, ) -> u32 { assert!(!context.is_null()); + assert!(!name.is_null()); let context = &*context; dc_chat::dc_create_group_chat(context, verified, name) @@ -623,6 +624,8 @@ pub unsafe extern "C" fn dc_set_chat_name( name: *mut libc::c_char, ) -> libc::c_int { assert!(!context.is_null()); + assert!(!name.is_null()); + assert!(chat_id > constants::DC_CHAT_ID_LAST_SPECIAL as u32); let context = &*context; dc_chat::dc_set_chat_name(context, chat_id, name) @@ -635,6 +638,7 @@ pub unsafe extern "C" fn dc_set_chat_profile_image( image: *mut libc::c_char, ) -> libc::c_int { assert!(!context.is_null()); + assert!(chat_id > constants::DC_CHAT_ID_LAST_SPECIAL as u32); let context = &*context; dc_chat::dc_set_chat_profile_image(context, chat_id, image) @@ -669,6 +673,8 @@ pub unsafe extern "C" fn dc_delete_msgs( msg_cnt: libc::c_int, ) { assert!(!context.is_null()); + assert!(!msg_ids.is_null()); + assert!(msg_cnt > 0); let context = &*context; dc_msg::dc_delete_msgs(context, msg_ids, msg_cnt) @@ -682,6 +688,9 @@ pub unsafe extern "C" fn dc_forward_msgs( chat_id: u32, ) { assert!(!context.is_null()); + assert!(!msg_ids.is_null()); + assert!(msg_cnt > 0); + assert!(chat_id > constants::DC_CHAT_ID_LAST_SPECIAL as u32); let context = &*context; dc_chat::dc_forward_msgs(context, msg_ids, msg_cnt, chat_id) @@ -702,6 +711,8 @@ pub unsafe extern "C" fn dc_markseen_msgs( msg_cnt: libc::c_int, ) { assert!(!context.is_null()); + assert!(!msg_ids.is_null()); + assert!(msg_cnt > 0); let context = &*context; dc_msg::dc_markseen_msgs(context, msg_ids, msg_cnt as usize); @@ -715,6 +726,9 @@ pub unsafe extern "C" fn dc_star_msgs( star: libc::c_int, ) { assert!(!context.is_null()); + assert!(!msg_ids.is_null()); + assert!(msg_cnt > 0); + let context = &*context; dc_msg::dc_star_msgs(context, msg_ids, msg_cnt, star); @@ -733,6 +747,7 @@ pub unsafe extern "C" fn dc_get_msg<'a>( #[no_mangle] pub unsafe extern "C" fn dc_may_be_valid_addr(addr: *mut libc::c_char) -> libc::c_int { + assert!(!addr.is_null()); dc_contact::dc_may_be_valid_addr(addr) as libc::c_int } @@ -742,6 +757,7 @@ pub unsafe extern "C" fn dc_lookup_contact_id_by_addr( addr: *mut libc::c_char, ) -> u32 { assert!(!context.is_null()); + assert!(!addr.is_null()); let context = &*context; dc_contact::dc_lookup_contact_id_by_addr(context, addr) @@ -754,6 +770,7 @@ pub unsafe extern "C" fn dc_create_contact( addr: *mut libc::c_char, ) -> u32 { assert!(!context.is_null()); + assert!(!addr.is_null()); let context = &*context; dc_contact::dc_create_contact(context, name, addr) @@ -765,6 +782,7 @@ pub unsafe extern "C" fn dc_add_address_book( addr_book: *mut libc::c_char, ) -> libc::c_int { assert!(!context.is_null()); + assert!(!addr_book.is_null()); let context = &*context; dc_contact::dc_add_address_book(context, addr_book) @@ -864,6 +882,7 @@ pub unsafe extern "C" fn dc_imex_has_backup( dir: *mut libc::c_char, ) -> *mut libc::c_char { assert!(!context.is_null()); + assert!(!dir.is_null()); let context = &*context; dc_imex::dc_imex_has_backup(context, dir) @@ -884,6 +903,7 @@ pub unsafe extern "C" fn dc_continue_key_transfer( setup_code: *mut libc::c_char, ) -> libc::c_int { assert!(!context.is_null()); + assert!(!setup_code.is_null()); let context = &*context; dc_imex::dc_continue_key_transfer(context, msg_id, setup_code) @@ -903,6 +923,7 @@ pub unsafe extern "C" fn dc_check_qr( qr: *mut libc::c_char, ) -> *mut dc_lot::dc_lot_t { assert!(!context.is_null()); + assert!(!qr.is_null()); let context = &*context; dc_qr::dc_check_qr(context, qr) @@ -925,6 +946,7 @@ pub unsafe extern "C" fn dc_join_securejoin( qr: *mut libc::c_char, ) -> u32 { assert!(!context.is_null()); + assert!(!qr.is_null()); let context = &*context; dc_securejoin::dc_join_securejoin(context, qr) @@ -1001,24 +1023,34 @@ pub type dc_array_t = dc_array::dc_array_t; #[no_mangle] pub unsafe extern "C" fn dc_array_unref(a: *mut dc_array::dc_array_t) { + assert!(!a.is_null()); + dc_array::dc_array_unref(a) } #[no_mangle] pub unsafe extern "C" fn dc_array_add_uint(array: *mut dc_array_t, item: libc::uintptr_t) { + assert!(!array.is_null()); + dc_array::dc_array_add_uint(array, item) } #[no_mangle] pub unsafe extern "C" fn dc_array_add_id(array: *mut dc_array_t, item: libc::c_uint) { + assert!(!array.is_null()); + dc_array::dc_array_add_id(array, item) } #[no_mangle] pub unsafe extern "C" fn dc_array_add_ptr(array: *mut dc_array_t, item: *mut libc::c_void) { + assert!(!array.is_null()); + dc_array::dc_array_add_ptr(array, item) } #[no_mangle] pub unsafe extern "C" fn dc_array_get_cnt(array: *const dc_array_t) -> libc::size_t { + assert!(!array.is_null()); + dc_array::dc_array_get_cnt(array) } #[no_mangle] @@ -1026,6 +1058,8 @@ pub unsafe extern "C" fn dc_array_get_uint( array: *const dc_array_t, index: libc::size_t, ) -> libc::uintptr_t { + assert!(!array.is_null()); + dc_array::dc_array_get_uint(array, index) } #[no_mangle] @@ -1033,6 +1067,8 @@ pub unsafe extern "C" fn dc_array_get_id( array: *const dc_array_t, index: libc::size_t, ) -> libc::c_uint { + assert!(!array.is_null()); + dc_array::dc_array_get_id(array, index) } #[no_mangle] @@ -1040,6 +1076,8 @@ pub unsafe extern "C" fn dc_array_get_ptr( array: *const dc_array_t, index: libc::size_t, ) -> *mut libc::c_void { + assert!(!array.is_null()); + dc_array::dc_array_get_ptr(array, index) } #[no_mangle] @@ -1047,6 +1085,8 @@ pub unsafe extern "C" fn dc_array_get_latitude( array: *const dc_array_t, index: libc::size_t, ) -> libc::c_double { + assert!(!array.is_null()); + dc_array::dc_array_get_latitude(array, index) } #[no_mangle] @@ -1054,6 +1094,8 @@ pub unsafe extern "C" fn dc_array_get_longitude( array: *const dc_array_t, index: libc::size_t, ) -> libc::c_double { + assert!(!array.is_null()); + dc_array::dc_array_get_longitude(array, index) } #[no_mangle] @@ -1061,6 +1103,8 @@ pub unsafe extern "C" fn dc_array_get_accuracy( array: *const dc_array_t, index: libc::size_t, ) -> libc::c_double { + assert!(!array.is_null()); + dc_array::dc_array_get_accuracy(array, index) } #[no_mangle] @@ -1068,6 +1112,8 @@ pub unsafe extern "C" fn dc_array_get_timestamp( array: *const dc_array_t, index: libc::size_t, ) -> i64 { + assert!(!array.is_null()); + dc_array::dc_array_get_timestamp(array, index) } #[no_mangle] @@ -1075,6 +1121,8 @@ pub unsafe extern "C" fn dc_array_get_chat_id( array: *const dc_array_t, index: libc::size_t, ) -> libc::c_uint { + assert!(!array.is_null()); + dc_array::dc_array_get_chat_id(array, index) } #[no_mangle] @@ -1082,6 +1130,8 @@ pub unsafe extern "C" fn dc_array_get_contact_id( array: *const dc_array_t, index: libc::size_t, ) -> libc::c_uint { + assert!(!array.is_null()); + dc_array::dc_array_get_contact_id(array, index) } #[no_mangle] @@ -1089,6 +1139,8 @@ pub unsafe extern "C" fn dc_array_get_msg_id( array: *const dc_array_t, index: libc::size_t, ) -> libc::c_uint { + assert!(!array.is_null()); + dc_array::dc_array_get_msg_id(array, index) } #[no_mangle] @@ -1096,6 +1148,8 @@ pub unsafe extern "C" fn dc_array_get_marker( array: *const dc_array_t, index: libc::size_t, ) -> *mut libc::c_char { + assert!(!array.is_null()); + dc_array::dc_array_get_marker(array, index) } @@ -1105,11 +1159,15 @@ pub unsafe extern "C" fn dc_array_search_id( needle: libc::c_uint, ret_index: *mut libc::size_t, ) -> libc::c_int { + assert!(!array.is_null()); + dc_array::dc_array_search_id(array, needle, ret_index) as libc::c_int } #[no_mangle] pub unsafe extern "C" fn dc_array_get_raw(array: *const dc_array_t) -> *const libc::size_t { + assert!(!array.is_null()); + dc_array::dc_array_get_raw(array) } @@ -1118,6 +1176,8 @@ pub unsafe fn dc_array_is_independent( array: *const dc_array_t, index: libc::size_t, ) -> libc::c_int { + assert!(!array.is_null()); + dc_array::dc_array_is_independent(array, index) } @@ -1192,61 +1252,85 @@ pub type dc_chat_t<'a> = dc_chat::Chat<'a>; #[no_mangle] pub unsafe extern "C" fn dc_chat_unref(chat: *mut dc_chat_t) { + assert!(!chat.is_null()); + dc_chat::dc_chat_unref(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_get_id(chat: *mut dc_chat_t) -> u32 { + assert!(!chat.is_null()); + dc_chat::dc_chat_get_id(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_get_type(chat: *mut dc_chat_t) -> libc::c_int { + assert!(!chat.is_null()); + dc_chat::dc_chat_get_type(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_get_name(chat: *mut dc_chat_t) -> *mut libc::c_char { + assert!(!chat.is_null()); + dc_chat::dc_chat_get_name(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_get_subtitle(chat: *mut dc_chat_t) -> *mut libc::c_char { + assert!(!chat.is_null()); + dc_chat::dc_chat_get_subtitle(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_get_profile_image(chat: *mut dc_chat_t) -> *mut libc::c_char { + assert!(!chat.is_null()); + dc_chat::dc_chat_get_profile_image(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_get_color(chat: *mut dc_chat_t) -> u32 { + assert!(!chat.is_null()); + dc_chat::dc_chat_get_color(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_get_archived(chat: *mut dc_chat_t) -> libc::c_int { + assert!(!chat.is_null()); + dc_chat::dc_chat_get_archived(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_is_unpromoted(chat: *mut dc_chat_t) -> libc::c_int { + assert!(!chat.is_null()); + dc_chat::dc_chat_is_unpromoted(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_is_self_talk(chat: *mut dc_chat_t) -> libc::c_int { + assert!(!chat.is_null()); + dc_chat::dc_chat_is_self_talk(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_is_verified(chat: *mut dc_chat_t) -> libc::c_int { + assert!(!chat.is_null()); + dc_chat::dc_chat_is_verified(chat) } #[no_mangle] pub unsafe extern "C" fn dc_chat_is_sending_locations(chat: *mut dc_chat_t) -> libc::c_int { + assert!(!chat.is_null()); + dc_chat::dc_chat_is_sending_locations(chat) } @@ -1262,40 +1346,50 @@ pub unsafe extern "C" fn dc_msg_new<'a>( ) -> *mut dc_msg::dc_msg_t<'a> { assert!(!context.is_null()); let context = &*context; - if let Some(viewtype) = from_prim(viewtype) { - dc_msg::dc_msg_new(context, viewtype) - } else { - ptr::null_mut() - } + let viewtype = from_prim(viewtype).expect(&format!("invalid viewtype = {}", viewtype)); + + dc_msg::dc_msg_new(context, viewtype) } #[no_mangle] pub unsafe extern "C" fn dc_msg_unref(msg: *mut dc_msg::dc_msg_t) { + assert!(!msg.is_null()); + dc_msg::dc_msg_unref(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_empty(msg: *mut dc_msg::dc_msg_t) { + assert!(!msg.is_null()); + dc_msg::dc_msg_empty(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_id(msg: *mut dc_msg::dc_msg_t) -> u32 { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_id(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_from_id(msg: *mut dc_msg::dc_msg_t) -> u32 { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_from_id(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_chat_id(msg: *mut dc_msg::dc_msg_t) -> u32 { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_chat_id(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_viewtype(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_viewtype(msg) .to_i64() .expect("impossible: Viewtype -> i64 conversion failed") as libc::c_int @@ -1303,66 +1397,92 @@ pub unsafe extern "C" fn dc_msg_get_viewtype(msg: *mut dc_msg::dc_msg_t) -> libc #[no_mangle] pub unsafe extern "C" fn dc_msg_get_state(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_state(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_timestamp(msg: *mut dc_msg::dc_msg_t) -> i64 { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_timestamp(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_received_timestamp(msg: *mut dc_msg::dc_msg_t) -> i64 { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_received_timestamp(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_sort_timestamp(msg: *mut dc_msg::dc_msg_t) -> i64 { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_sort_timestamp(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_text(msg: *mut dc_msg::dc_msg_t) -> *mut libc::c_char { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_text(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_file(msg: *mut dc_msg::dc_msg_t) -> *mut libc::c_char { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_file(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_filename(msg: *mut dc_msg::dc_msg_t) -> *mut libc::c_char { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_filename(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_filemime(msg: *mut dc_msg::dc_msg_t) -> *mut libc::c_char { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_filemime(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_filebytes(msg: *mut dc_msg::dc_msg_t) -> u64 { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_filebytes(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_width(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_width(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_height(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_height(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_duration(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_duration(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_get_showpadlock(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_showpadlock(msg) } @@ -1371,6 +1491,8 @@ pub unsafe extern "C" fn dc_msg_get_summary<'a>( msg: *mut dc_msg::dc_msg_t<'a>, chat: *mut dc_chat_t<'a>, ) -> *mut dc_lot::dc_lot_t { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_summary(msg, chat) } @@ -1379,46 +1501,64 @@ pub unsafe extern "C" fn dc_msg_get_summarytext( msg: *mut dc_msg::dc_msg_t, approx_characters: libc::c_int, ) -> *mut libc::c_char { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_summarytext(msg, approx_characters) } #[no_mangle] pub unsafe extern "C" fn dc_msg_has_deviating_timestamp(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_has_deviating_timestamp(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_has_location(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_has_location(msg) as libc::c_int } #[no_mangle] pub unsafe extern "C" fn dc_msg_is_sent(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_is_sent(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_is_starred(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_is_starred(msg).into() } #[no_mangle] pub unsafe extern "C" fn dc_msg_is_forwarded(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_is_forwarded(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_is_info(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_is_info(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_is_increation(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_is_increation(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_is_setupmessage(msg: *mut dc_msg::dc_msg_t) -> libc::c_int { + assert!(!msg.is_null()); + dc_msg::dc_msg_is_setupmessage(msg) as libc::c_int } @@ -1426,11 +1566,16 @@ pub unsafe extern "C" fn dc_msg_is_setupmessage(msg: *mut dc_msg::dc_msg_t) -> l pub unsafe extern "C" fn dc_msg_get_setupcodebegin( msg: *mut dc_msg::dc_msg_t, ) -> *mut libc::c_char { + assert!(!msg.is_null()); + dc_msg::dc_msg_get_setupcodebegin(msg) } #[no_mangle] pub unsafe extern "C" fn dc_msg_set_text(msg: *mut dc_msg::dc_msg_t, text: *mut libc::c_char) { + assert!(!msg.is_null()); + + // TODO: {text} equal to NULL is treated as "", which is strange. Does anyone rely on it? dc_msg::dc_msg_set_text(msg, text) } @@ -1440,6 +1585,8 @@ pub unsafe extern "C" fn dc_msg_set_file( file: *mut libc::c_char, filemime: *mut libc::c_char, ) { + assert!(!msg.is_null()); + dc_msg::dc_msg_set_file(msg, file, filemime) } @@ -1449,11 +1596,15 @@ pub unsafe extern "C" fn dc_msg_set_dimension( width: libc::c_int, height: libc::c_int, ) { + assert!(!msg.is_null()); + dc_msg::dc_msg_set_dimension(msg, width, height) } #[no_mangle] pub unsafe extern "C" fn dc_msg_set_duration(msg: *mut dc_msg::dc_msg_t, duration: libc::c_int) { + assert!(!msg.is_null()); + dc_msg::dc_msg_set_duration(msg, duration) } @@ -1463,6 +1614,8 @@ pub unsafe extern "C" fn dc_msg_set_location( latitude: libc::c_double, longitude: libc::c_double, ) { + assert!(!msg.is_null()); + dc_msg::dc_msg_set_location(msg, latitude, longitude) } @@ -1473,6 +1626,8 @@ pub unsafe extern "C" fn dc_msg_latefiling_mediasize( height: libc::c_int, duration: libc::c_int, ) { + assert!(!msg.is_null()); + dc_msg::dc_msg_latefiling_mediasize(msg, width, height, duration) } @@ -1483,11 +1638,15 @@ pub type dc_contact_t<'a> = dc_contact::dc_contact_t<'a>; #[no_mangle] pub unsafe extern "C" fn dc_contact_unref(contact: *mut dc_contact::dc_contact_t) { + assert!(!contact.is_null()); + dc_contact::dc_contact_unref(contact) } #[no_mangle] pub unsafe extern "C" fn dc_contact_get_id(contact: *mut dc_contact::dc_contact_t) -> u32 { + assert!(!contact.is_null()); + dc_contact::dc_contact_get_id(contact) } @@ -1495,6 +1654,8 @@ pub unsafe extern "C" fn dc_contact_get_id(contact: *mut dc_contact::dc_contact_ pub unsafe extern "C" fn dc_contact_get_addr( contact: *mut dc_contact::dc_contact_t, ) -> *mut libc::c_char { + assert!(!contact.is_null()); + dc_contact::dc_contact_get_addr(contact) } @@ -1502,6 +1663,8 @@ pub unsafe extern "C" fn dc_contact_get_addr( pub unsafe extern "C" fn dc_contact_get_name( contact: *mut dc_contact::dc_contact_t, ) -> *mut libc::c_char { + assert!(!contact.is_null()); + dc_contact::dc_contact_get_name(contact) } @@ -1509,6 +1672,8 @@ pub unsafe extern "C" fn dc_contact_get_name( pub unsafe extern "C" fn dc_contact_get_display_name( contact: *mut dc_contact::dc_contact_t, ) -> *mut libc::c_char { + assert!(!contact.is_null()); + dc_contact::dc_contact_get_display_name(contact) } @@ -1516,6 +1681,8 @@ pub unsafe extern "C" fn dc_contact_get_display_name( pub unsafe extern "C" fn dc_contact_get_name_n_addr( contact: *mut dc_contact::dc_contact_t, ) -> *mut libc::c_char { + assert!(!contact.is_null()); + dc_contact::dc_contact_get_name_n_addr(contact) } @@ -1523,6 +1690,8 @@ pub unsafe extern "C" fn dc_contact_get_name_n_addr( pub unsafe extern "C" fn dc_contact_get_first_name( contact: *mut dc_contact::dc_contact_t, ) -> *mut libc::c_char { + assert!(!contact.is_null()); + dc_contact::dc_contact_get_first_name(contact) } @@ -1530,11 +1699,15 @@ pub unsafe extern "C" fn dc_contact_get_first_name( pub unsafe extern "C" fn dc_contact_get_profile_image( contact: *mut dc_contact::dc_contact_t, ) -> *mut libc::c_char { + assert!(!contact.is_null()); + dc_contact::dc_contact_get_profile_image(contact) } #[no_mangle] pub unsafe extern "C" fn dc_contact_get_color(contact: *mut dc_contact::dc_contact_t) -> u32 { + assert!(!contact.is_null()); + dc_contact::dc_contact_get_color(contact) } @@ -1542,6 +1715,8 @@ pub unsafe extern "C" fn dc_contact_get_color(contact: *mut dc_contact::dc_conta pub unsafe extern "C" fn dc_contact_is_blocked( contact: *mut dc_contact::dc_contact_t, ) -> libc::c_int { + assert!(!contact.is_null()); + dc_contact::dc_contact_is_blocked(contact) } @@ -1549,6 +1724,8 @@ pub unsafe extern "C" fn dc_contact_is_blocked( pub unsafe extern "C" fn dc_contact_is_verified( contact: *mut dc_contact::dc_contact_t, ) -> libc::c_int { + assert!(!contact.is_null()); + dc_contact::dc_contact_is_verified(contact) } @@ -1564,41 +1741,57 @@ pub unsafe extern "C" fn dc_lot_new() -> *mut dc_lot::dc_lot_t { #[no_mangle] pub unsafe extern "C" fn dc_lot_empty(lot: *mut dc_lot::dc_lot_t) { + assert!(!lot.is_null()); + dc_lot::dc_lot_empty(lot) } #[no_mangle] pub unsafe extern "C" fn dc_lot_unref(lot: *mut dc_lot::dc_lot_t) { + assert!(!lot.is_null()); + dc_lot::dc_lot_unref(lot) } #[no_mangle] pub unsafe extern "C" fn dc_lot_get_text1(lot: *mut dc_lot::dc_lot_t) -> *mut libc::c_char { + assert!(!lot.is_null()); + dc_lot::dc_lot_get_text1(lot) } #[no_mangle] pub unsafe extern "C" fn dc_lot_get_text2(lot: *mut dc_lot::dc_lot_t) -> *mut libc::c_char { + assert!(!lot.is_null()); + dc_lot::dc_lot_get_text2(lot) } #[no_mangle] pub unsafe extern "C" fn dc_lot_get_text1_meaning(lot: *mut dc_lot::dc_lot_t) -> libc::c_int { + assert!(!lot.is_null()); + dc_lot::dc_lot_get_text1_meaning(lot) } #[no_mangle] pub unsafe extern "C" fn dc_lot_get_state(lot: *mut dc_lot::dc_lot_t) -> libc::c_int { + assert!(!lot.is_null()); + dc_lot::dc_lot_get_state(lot) } #[no_mangle] pub unsafe extern "C" fn dc_lot_get_id(lot: *mut dc_lot::dc_lot_t) -> u32 { + assert!(!lot.is_null()); + dc_lot::dc_lot_get_id(lot) } #[no_mangle] pub unsafe extern "C" fn dc_lot_get_timestamp(lot: *mut dc_lot::dc_lot_t) -> i64 { + assert!(!lot.is_null()); + dc_lot::dc_lot_get_timestamp(lot) } From 76b3c532b16a5710563f5e34c3e602fac90376e8 Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 20:40:50 +0200 Subject: [PATCH 74/95] run cargo fmt --- src/dc_e2ee.rs | 67 +++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index 4194b77a2..d77d4d8ec 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -906,45 +906,44 @@ unsafe fn decrypt_part( } } if ok_to_continue { - /* encrypted, decoded data in decoded_data now ... */ - if !(0 == has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int)) - { - let add_signatures = if ret_valid_signatures.is_empty() { - Some(ret_valid_signatures) - } else { - None - }; + /* encrypted, decoded data in decoded_data now ... */ + if !(0 == has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int)) { + let add_signatures = if ret_valid_signatures.is_empty() { + Some(ret_valid_signatures) + } else { + None + }; - /*if we already have fingerprints, do not add more; this ensures, only the fingerprints from the outer-most part are collected */ - if let Some(plain) = dc_pgp_pk_decrypt( - decoded_data as *const libc::c_void, - decoded_data_bytes, - &private_keyring, - &public_keyring_for_validate, - add_signatures, - ) { - let plain_bytes = plain.len(); - let plain_buf = plain.as_ptr() as *const libc::c_char; + /*if we already have fingerprints, do not add more; this ensures, only the fingerprints from the outer-most part are collected */ + if let Some(plain) = dc_pgp_pk_decrypt( + decoded_data as *const libc::c_void, + decoded_data_bytes, + &private_keyring, + &public_keyring_for_validate, + add_signatures, + ) { + let plain_bytes = plain.len(); + let plain_buf = plain.as_ptr() as *const libc::c_char; - let mut index: size_t = 0i32 as size_t; - let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime; - if mailmime_parse( - plain_buf as *const _, - plain_bytes, - &mut index, - &mut decrypted_mime, - ) != MAIL_NO_ERROR as libc::c_int - || decrypted_mime.is_null() - { - if !decrypted_mime.is_null() { - mailmime_free(decrypted_mime); - } - } else { - *ret_decrypted_mime = decrypted_mime; - sth_decrypted = 1i32 + let mut index: size_t = 0i32 as size_t; + let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime; + if mailmime_parse( + plain_buf as *const _, + plain_bytes, + &mut index, + &mut decrypted_mime, + ) != MAIL_NO_ERROR as libc::c_int + || decrypted_mime.is_null() + { + if !decrypted_mime.is_null() { + mailmime_free(decrypted_mime); } + } else { + *ret_decrypted_mime = decrypted_mime; + sth_decrypted = 1i32 } } + } } } //mailmime_substitute(mime, new_mime); From ac2f9fdee5b0cc519c80b78ad072a5982bf6d3c6 Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 20:52:18 +0200 Subject: [PATCH 75/95] remove gotos from new_data_part function --- src/dc_e2ee.rs | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index d77d4d8ec..cf22f4532 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -378,7 +378,7 @@ unsafe fn new_data_part( default_content_type: *mut libc::c_char, default_encoding: libc::c_int, ) -> *mut mailmime { - let mut current_block: u64; + let mut ok_to_continue = true; //char basename_buf[PATH_MAX]; let mut encoding: *mut mailmime_mechanism; let content: *mut mailmime_content; @@ -398,7 +398,7 @@ unsafe fn new_data_part( } content = mailmime_content_new_with_str(content_type_str); if content.is_null() { - current_block = 16266721588079097885; + ok_to_continue = false; } else { do_encoding = 1i32; if (*(*content).ct_type).tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int { @@ -426,16 +426,10 @@ unsafe fn new_data_part( } encoding = mailmime_mechanism_new(encoding_type, 0 as *mut libc::c_char); if encoding.is_null() { - current_block = 16266721588079097885; - } else { - current_block = 11057878835866523405; - } - } else { - current_block = 11057878835866523405; + ok_to_continue = false; + } } - match current_block { - 16266721588079097885 => {} - _ => { + if ok_to_continue { mime_fields = mailmime_fields_new_with_data( encoding, 0 as *mut libc::c_char, @@ -444,7 +438,7 @@ unsafe fn new_data_part( 0 as *mut mailmime_language, ); if mime_fields.is_null() { - current_block = 16266721588079097885; + ok_to_continue = false; } else { mime = mailmime_new_empty(content, mime_fields); if mime.is_null() { @@ -459,21 +453,17 @@ unsafe fn new_data_part( } return mime; } - current_block = 13668317689588454213; } - } } } - match current_block { - 16266721588079097885 => { + + if ok_to_continue == false { if !encoding.is_null() { mailmime_mechanism_free(encoding); } if !content.is_null() { mailmime_content_free(content); } - } - _ => {} } return 0 as *mut mailmime; } From 0276f97d9607a8112d5f38ffc987fb63599d5899 Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 20:52:38 +0200 Subject: [PATCH 76/95] run cargo fmt --- src/dc_e2ee.rs | 66 +++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index cf22f4532..4e4678b50 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -378,7 +378,7 @@ unsafe fn new_data_part( default_content_type: *mut libc::c_char, default_encoding: libc::c_int, ) -> *mut mailmime { - let mut ok_to_continue = true; + let mut ok_to_continue = true; //char basename_buf[PATH_MAX]; let mut encoding: *mut mailmime_mechanism; let content: *mut mailmime_content; @@ -398,7 +398,7 @@ unsafe fn new_data_part( } content = mailmime_content_new_with_str(content_type_str); if content.is_null() { - ok_to_continue = false; + ok_to_continue = false; } else { do_encoding = 1i32; if (*(*content).ct_type).tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int { @@ -426,44 +426,44 @@ unsafe fn new_data_part( } encoding = mailmime_mechanism_new(encoding_type, 0 as *mut libc::c_char); if encoding.is_null() { - ok_to_continue = false; - } + ok_to_continue = false; + } } - if ok_to_continue { - mime_fields = mailmime_fields_new_with_data( - encoding, - 0 as *mut libc::c_char, - 0 as *mut libc::c_char, - 0 as *mut mailmime_disposition, - 0 as *mut mailmime_language, - ); - if mime_fields.is_null() { - ok_to_continue = false; + if ok_to_continue { + mime_fields = mailmime_fields_new_with_data( + encoding, + 0 as *mut libc::c_char, + 0 as *mut libc::c_char, + 0 as *mut mailmime_disposition, + 0 as *mut mailmime_language, + ); + if mime_fields.is_null() { + ok_to_continue = false; + } else { + mime = mailmime_new_empty(content, mime_fields); + if mime.is_null() { + mailmime_fields_free(mime_fields); + mailmime_content_free(content); } else { - mime = mailmime_new_empty(content, mime_fields); - if mime.is_null() { - mailmime_fields_free(mime_fields); - mailmime_content_free(content); - } else { - if !data.is_null() - && data_bytes > 0 - && (*mime).mm_type == MAILMIME_SINGLE as libc::c_int - { - mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes); - } - return mime; + if !data.is_null() + && data_bytes > 0 + && (*mime).mm_type == MAILMIME_SINGLE as libc::c_int + { + mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes); } + return mime; } + } } } - if ok_to_continue == false { - if !encoding.is_null() { - mailmime_mechanism_free(encoding); - } - if !content.is_null() { - mailmime_content_free(content); - } + if ok_to_continue == false { + if !encoding.is_null() { + mailmime_mechanism_free(encoding); + } + if !content.is_null() { + mailmime_content_free(content); + } } return 0 as *mut mailmime; } From 9034f316ba380173302458c07e332bf6cf5346c5 Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 20:57:42 +0200 Subject: [PATCH 77/95] Remove gotos from dc_e2ee_encrypt function --- src/dc_e2ee.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index 4e4678b50..e44e8e767 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -66,7 +66,7 @@ pub unsafe fn dc_e2ee_encrypt( mut in_out_message: *mut mailmime, helper: &mut dc_e2ee_helper_t, ) { - let mut current_block: u64 = 0; + let mut ok_to_continue = true; let mut col: libc::c_int = 0i32; let mut do_encrypt: libc::c_int = 0i32; /*just a pointer into mailmime structure, must not be freed*/ @@ -283,7 +283,7 @@ pub unsafe fn dc_e2ee_encrypt( ); mailmime_write_mem(plain, &mut col, message_to_encrypt); if (*plain).str_0.is_null() || (*plain).len <= 0 { - current_block = 14181132614457621749; + ok_to_continue = false; } else { if let Some(ctext_v) = dc_pgp_pk_encrypt( (*plain).str_0 as *const libc::c_void, @@ -340,15 +340,11 @@ pub unsafe fn dc_e2ee_encrypt( (*encrypted_part).mm_parent = in_out_message; mailmime_free(message_to_encrypt); (*helper).encryption_successfull = 1i32; - current_block = 13824533195664196414; } } - } else { - current_block = 13824533195664196414; } - match current_block { - 14181132614457621749 => {} - _ => { + // ok_to_continue = false = 14181132614457621749 + if ok_to_continue { let aheader = Aheader::new(addr, public_key, prefer_encrypt); mailimf_fields_add( imffields_unprotected, @@ -357,7 +353,6 @@ pub unsafe fn dc_e2ee_encrypt( aheader.to_string().strdup(), ), ); - } } } } From 925759a9223df452920da3843b720166b70b4eee Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 20:57:58 +0200 Subject: [PATCH 78/95] run cargo fmt --- src/dc_e2ee.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index e44e8e767..954f4904b 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -343,16 +343,16 @@ pub unsafe fn dc_e2ee_encrypt( } } } - // ok_to_continue = false = 14181132614457621749 + // ok_to_continue = false = 14181132614457621749 if ok_to_continue { - let aheader = Aheader::new(addr, public_key, prefer_encrypt); - mailimf_fields_add( - imffields_unprotected, - mailimf_field_new_custom( - "Autocrypt".strdup(), - aheader.to_string().strdup(), - ), - ); + let aheader = Aheader::new(addr, public_key, prefer_encrypt); + mailimf_fields_add( + imffields_unprotected, + mailimf_field_new_custom( + "Autocrypt".strdup(), + aheader.to_string().strdup(), + ), + ); } } } From e0dbd47185493b691f918a08b530e65f5277710e Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 21:13:20 +0200 Subject: [PATCH 79/95] Remove gotos from dc_mimefactory --- src/dc_mimefactory.rs | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 0cb95d780..0e17780f5 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -353,7 +353,7 @@ pub unsafe fn dc_mimefactory_load_mdn( // TODO should return bool /rtn pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc::c_int { let subject: *mut mailimf_subject; - let mut current_block: u64; + let mut ok_to_continue = true; let imf_fields: *mut mailimf_fields; let mut message: *mut mailmime = 0 as *mut mailmime; let mut message_text: *mut libc::c_char = 0 as *mut libc::c_char; @@ -853,7 +853,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: ); set_error(factory, error); free(error as *mut libc::c_void); - current_block = 11328123142868406523; + ok_to_continue = false; } else { let file_part: *mut mailmime = build_body_file(msg, 0 as *const libc::c_char, 0 as *mut *mut libc::c_char); @@ -861,20 +861,16 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: mailmime_smart_add_part(message, file_part); parts += 1 } - current_block = 13000670339742628194; } - } else { - current_block = 13000670339742628194; } - match current_block { - 11328123142868406523 => {} - _ => { + // ok_to_continue = false = 11328123142868406523 + if ok_to_continue { if parts == 0 { set_error( factory, b"Empty message.\x00" as *const u8 as *const libc::c_char, ); - current_block = 11328123142868406523; + ok_to_continue = false; } else { if !meta_part.is_null() { mailmime_smart_add_part(message, meta_part); @@ -940,9 +936,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: } } } - current_block = 9952640327414195044; } - } } } else if (*factory).loaded as libc::c_uint == DC_MF_MDN_LOADED as libc::c_int as libc::c_uint @@ -994,18 +988,15 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: mailmime_set_body_text(mach_mime_part, message_text2, strlen(message_text2)); mailmime_add_part(multipart, mach_mime_part); force_plaintext = 2; - current_block = 9952640327414195044; } else { set_error( factory, b"No message loaded.\x00" as *const u8 as *const libc::c_char, ); - current_block = 11328123142868406523; + ok_to_continue = false; } - match current_block { - 11328123142868406523 => {} - _ => { + if ok_to_continue { if (*factory).loaded as libc::c_uint == DC_MF_MDN_LOADED as libc::c_int as libc::c_uint { @@ -1073,7 +1064,6 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: (*factory).out = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char); mailmime_write_mem((*factory).out, &mut col, message); success = 1 - } } } if !message.is_null() { From 655884b559b74d6e0f068e16c710f9ccec3b42c6 Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 21:13:54 +0200 Subject: [PATCH 80/95] run cargo fmt --- src/dc_mimefactory.rs | 259 ++++++++++++++++++++---------------------- 1 file changed, 126 insertions(+), 133 deletions(-) diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 0e17780f5..47920343c 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -865,78 +865,72 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: } // ok_to_continue = false = 11328123142868406523 if ok_to_continue { - if parts == 0 { - set_error( - factory, - b"Empty message.\x00" as *const u8 as *const libc::c_char, - ); - ok_to_continue = false; - } else { - if !meta_part.is_null() { - mailmime_smart_add_part(message, meta_part); - } - if (*msg).param.exists(Param::SetLatitude) { - let latitude = (*msg) - .param - .get_float(Param::SetLatitude) - .unwrap_or_default(); - let longitude = (*msg) - .param - .get_float(Param::SetLongitude) - .unwrap_or_default(); - let kml_file = - dc_get_message_kml((*msg).timestamp_sort, latitude, longitude); - if !kml_file.is_null() { - let content_type = mailmime_content_new_with_str( - b"application/vnd.google-earth.kml+xml\x00" as *const u8 - as *const libc::c_char, - ); - let mime_fields = mailmime_fields_new_filename( - MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int, - dc_strdup( - b"message.kml\x00" as *const u8 as *const libc::c_char, - ), - MAILMIME_MECHANISM_8BIT as libc::c_int, - ); - let kml_mime_part = mailmime_new_empty(content_type, mime_fields); - mailmime_set_body_text(kml_mime_part, kml_file, strlen(kml_file)); - - mailmime_smart_add_part(message, kml_mime_part); - } - } - - if dc_is_sending_locations_to_chat((*msg).context, (*msg).chat_id) { - let mut last_added_location_id: uint32_t = 0 as uint32_t; - let kml_file: *mut libc::c_char = dc_get_location_kml( - (*msg).context, - (*msg).chat_id, - &mut last_added_location_id, + if parts == 0 { + set_error( + factory, + b"Empty message.\x00" as *const u8 as *const libc::c_char, + ); + ok_to_continue = false; + } else { + if !meta_part.is_null() { + mailmime_smart_add_part(message, meta_part); + } + if (*msg).param.exists(Param::SetLatitude) { + let latitude = (*msg) + .param + .get_float(Param::SetLatitude) + .unwrap_or_default(); + let longitude = (*msg) + .param + .get_float(Param::SetLongitude) + .unwrap_or_default(); + let kml_file = + dc_get_message_kml((*msg).timestamp_sort, latitude, longitude); + if !kml_file.is_null() { + let content_type = mailmime_content_new_with_str( + b"application/vnd.google-earth.kml+xml\x00" as *const u8 + as *const libc::c_char, ); - if !kml_file.is_null() { - let content_type: *mut mailmime_content = - mailmime_content_new_with_str( - b"application/vnd.google-earth.kml+xml\x00" as *const u8 - as *const libc::c_char, - ); - let mime_fields: *mut mailmime_fields = - mailmime_fields_new_filename( - MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int, - dc_strdup( - b"location.kml\x00" as *const u8 as *const libc::c_char, - ), - MAILMIME_MECHANISM_8BIT as libc::c_int, - ); - let kml_mime_part: *mut mailmime = - mailmime_new_empty(content_type, mime_fields); - mailmime_set_body_text(kml_mime_part, kml_file, strlen(kml_file)); - mailmime_smart_add_part(message, kml_mime_part); - if !(*msg).param.exists(Param::SetLatitude) { - // otherwise, the independent location is already filed - (*factory).out_last_added_location_id = last_added_location_id; - } + let mime_fields = mailmime_fields_new_filename( + MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int, + dc_strdup(b"message.kml\x00" as *const u8 as *const libc::c_char), + MAILMIME_MECHANISM_8BIT as libc::c_int, + ); + let kml_mime_part = mailmime_new_empty(content_type, mime_fields); + mailmime_set_body_text(kml_mime_part, kml_file, strlen(kml_file)); + + mailmime_smart_add_part(message, kml_mime_part); + } + } + + if dc_is_sending_locations_to_chat((*msg).context, (*msg).chat_id) { + let mut last_added_location_id: uint32_t = 0 as uint32_t; + let kml_file: *mut libc::c_char = dc_get_location_kml( + (*msg).context, + (*msg).chat_id, + &mut last_added_location_id, + ); + if !kml_file.is_null() { + let content_type: *mut mailmime_content = mailmime_content_new_with_str( + b"application/vnd.google-earth.kml+xml\x00" as *const u8 + as *const libc::c_char, + ); + let mime_fields: *mut mailmime_fields = mailmime_fields_new_filename( + MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int, + dc_strdup(b"location.kml\x00" as *const u8 as *const libc::c_char), + MAILMIME_MECHANISM_8BIT as libc::c_int, + ); + let kml_mime_part: *mut mailmime = + mailmime_new_empty(content_type, mime_fields); + mailmime_set_body_text(kml_mime_part, kml_file, strlen(kml_file)); + mailmime_smart_add_part(message, kml_mime_part); + if !(*msg).param.exists(Param::SetLatitude) { + // otherwise, the independent location is already filed + (*factory).out_last_added_location_id = last_added_location_id; } } } + } } } else if (*factory).loaded as libc::c_uint == DC_MF_MDN_LOADED as libc::c_int as libc::c_uint @@ -997,73 +991,72 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: } if ok_to_continue { - if (*factory).loaded as libc::c_uint - == DC_MF_MDN_LOADED as libc::c_int as libc::c_uint - { - let e = CString::new( - (*factory) - .context - .stock_str(StockMessage::ReadRcpt) - .as_ref(), - ) - .unwrap(); - subject_str = dc_mprintf( - b"Chat: %s\x00" as *const u8 as *const libc::c_char, - e.as_ptr(), - ); - } else { - subject_str = get_subject((*factory).chat, (*factory).msg, afwd_email) - } - subject = mailimf_subject_new(dc_encode_header_words(subject_str)); - mailimf_fields_add( - imf_fields, - mailimf_field_new( - MAILIMF_FIELD_SUBJECT as libc::c_int, - 0 as *mut mailimf_return, - 0 as *mut mailimf_orig_date, - 0 as *mut mailimf_from, - 0 as *mut mailimf_sender, - 0 as *mut mailimf_to, - 0 as *mut mailimf_cc, - 0 as *mut mailimf_bcc, - 0 as *mut mailimf_message_id, - 0 as *mut mailimf_orig_date, - 0 as *mut mailimf_from, - 0 as *mut mailimf_sender, - 0 as *mut mailimf_reply_to, - 0 as *mut mailimf_to, - 0 as *mut mailimf_cc, - 0 as *mut mailimf_bcc, - 0 as *mut mailimf_message_id, - 0 as *mut mailimf_in_reply_to, - 0 as *mut mailimf_references, - subject, - 0 as *mut mailimf_comments, - 0 as *mut mailimf_keywords, - 0 as *mut mailimf_optional_field, - ), + if (*factory).loaded as libc::c_uint == DC_MF_MDN_LOADED as libc::c_int as libc::c_uint + { + let e = CString::new( + (*factory) + .context + .stock_str(StockMessage::ReadRcpt) + .as_ref(), + ) + .unwrap(); + subject_str = dc_mprintf( + b"Chat: %s\x00" as *const u8 as *const libc::c_char, + e.as_ptr(), ); - if force_plaintext != 2 { - dc_e2ee_encrypt( - (*factory).context, - (*factory).recipients_addr, - force_plaintext, - e2ee_guaranteed, - min_verified, - do_gossip, - message, - &mut e2ee_helper, - ); + } else { + subject_str = get_subject((*factory).chat, (*factory).msg, afwd_email) + } + subject = mailimf_subject_new(dc_encode_header_words(subject_str)); + mailimf_fields_add( + imf_fields, + mailimf_field_new( + MAILIMF_FIELD_SUBJECT as libc::c_int, + 0 as *mut mailimf_return, + 0 as *mut mailimf_orig_date, + 0 as *mut mailimf_from, + 0 as *mut mailimf_sender, + 0 as *mut mailimf_to, + 0 as *mut mailimf_cc, + 0 as *mut mailimf_bcc, + 0 as *mut mailimf_message_id, + 0 as *mut mailimf_orig_date, + 0 as *mut mailimf_from, + 0 as *mut mailimf_sender, + 0 as *mut mailimf_reply_to, + 0 as *mut mailimf_to, + 0 as *mut mailimf_cc, + 0 as *mut mailimf_bcc, + 0 as *mut mailimf_message_id, + 0 as *mut mailimf_in_reply_to, + 0 as *mut mailimf_references, + subject, + 0 as *mut mailimf_comments, + 0 as *mut mailimf_keywords, + 0 as *mut mailimf_optional_field, + ), + ); + if force_plaintext != 2 { + dc_e2ee_encrypt( + (*factory).context, + (*factory).recipients_addr, + force_plaintext, + e2ee_guaranteed, + min_verified, + do_gossip, + message, + &mut e2ee_helper, + ); + } + if 0 != e2ee_helper.encryption_successfull { + (*factory).out_encrypted = 1; + if 0 != do_gossip { + (*factory).out_gossiped = 1 } - if 0 != e2ee_helper.encryption_successfull { - (*factory).out_encrypted = 1; - if 0 != do_gossip { - (*factory).out_gossiped = 1 - } - } - (*factory).out = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char); - mailmime_write_mem((*factory).out, &mut col, message); - success = 1 + } + (*factory).out = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char); + mailmime_write_mem((*factory).out, &mut col, message); + success = 1 } } if !message.is_null() { From e1d78717546d66791a42a1703df9dc53fc81fead Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 21:20:35 +0200 Subject: [PATCH 81/95] Remove gotos in dc_strencode --- src/dc_strencode.rs | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/dc_strencode.rs b/src/dc_strencode.rs index 3732d54b0..d7421da75 100644 --- a/src/dc_strencode.rs +++ b/src/dc_strencode.rs @@ -120,24 +120,20 @@ fn hex_2_int(ch: libc::c_char) -> libc::c_char { } pub unsafe fn dc_encode_header_words(to_encode: *const libc::c_char) -> *mut libc::c_char { - let mut current_block: u64; + let mut ok_to_continue = true; let mut ret_str: *mut libc::c_char = 0 as *mut libc::c_char; let mut cur: *const libc::c_char = to_encode; let mmapstr: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char); if to_encode.is_null() || mmapstr.is_null() { - current_block = 8550051112593613029; - } else { - current_block = 4644295000439058019; + ok_to_continue = false; } loop { - match current_block { - 8550051112593613029 => { + if !ok_to_continue { if !mmapstr.is_null() { mmap_string_free(mmapstr); } break; - } - _ => { + } else { if *cur as libc::c_int != '\u{0}' as i32 { let begin: *const libc::c_char; let mut end: *const libc::c_char; @@ -165,12 +161,12 @@ pub unsafe fn dc_encode_header_words(to_encode: *const libc::c_char) -> *mut lib begin, end.wrapping_offset_from(begin) as size_t, ) { - current_block = 8550051112593613029; + ok_to_continue = false; continue; } if *end as libc::c_int == ' ' as i32 || *end as libc::c_int == '\t' as i32 { if mmap_string_append_c(mmapstr, *end).is_null() { - current_block = 8550051112593613029; + ok_to_continue = false; continue; } end = end.offset(1isize) @@ -183,7 +179,7 @@ pub unsafe fn dc_encode_header_words(to_encode: *const libc::c_char) -> *mut lib ) .is_null() { - current_block = 8550051112593613029; + ok_to_continue = false; continue; } } @@ -194,24 +190,21 @@ pub unsafe fn dc_encode_header_words(to_encode: *const libc::c_char) -> *mut lib ) .is_null() { - current_block = 8550051112593613029; + ok_to_continue = false; continue; } if !(*cur as libc::c_int == ' ' as i32 || *cur as libc::c_int == '\t' as i32) { - current_block = 4644295000439058019; continue; } if mmap_string_append_c(mmapstr, *cur).is_null() { - current_block = 8550051112593613029; + ok_to_continue = false; continue; } cur = cur.offset(1isize); - current_block = 4644295000439058019; } else { ret_str = strdup((*mmapstr).str_0); - current_block = 8550051112593613029; + ok_to_continue = false; } - } } } From 70f6aa9d3a29a30dbe0f26baa511ad29dc9769e9 Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 21:21:13 +0200 Subject: [PATCH 82/95] run cargo fmt --- src/dc_strencode.rs | 134 ++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/src/dc_strencode.rs b/src/dc_strencode.rs index d7421da75..43396b6bc 100644 --- a/src/dc_strencode.rs +++ b/src/dc_strencode.rs @@ -129,82 +129,82 @@ pub unsafe fn dc_encode_header_words(to_encode: *const libc::c_char) -> *mut lib } loop { if !ok_to_continue { - if !mmapstr.is_null() { - mmap_string_free(mmapstr); - } - break; + if !mmapstr.is_null() { + mmap_string_free(mmapstr); + } + break; } else { - if *cur as libc::c_int != '\u{0}' as i32 { - let begin: *const libc::c_char; - let mut end: *const libc::c_char; - let mut do_quote: bool; - let mut quote_words: libc::c_int; - begin = cur; - end = begin; - quote_words = 0i32; - do_quote = true; - while *cur as libc::c_int != '\u{0}' as i32 { - get_word(cur, &mut cur, &mut do_quote); - if !do_quote { - break; - } - quote_words = 1i32; - end = cur; - if *cur as libc::c_int != '\u{0}' as i32 { - cur = cur.offset(1isize) - } + if *cur as libc::c_int != '\u{0}' as i32 { + let begin: *const libc::c_char; + let mut end: *const libc::c_char; + let mut do_quote: bool; + let mut quote_words: libc::c_int; + begin = cur; + end = begin; + quote_words = 0i32; + do_quote = true; + while *cur as libc::c_int != '\u{0}' as i32 { + get_word(cur, &mut cur, &mut do_quote); + if !do_quote { + break; } - if 0 != quote_words { - if !quote_word( - b"utf-8\x00" as *const u8 as *const libc::c_char, - mmapstr, - begin, - end.wrapping_offset_from(begin) as size_t, - ) { + quote_words = 1i32; + end = cur; + if *cur as libc::c_int != '\u{0}' as i32 { + cur = cur.offset(1isize) + } + } + if 0 != quote_words { + if !quote_word( + b"utf-8\x00" as *const u8 as *const libc::c_char, + mmapstr, + begin, + end.wrapping_offset_from(begin) as size_t, + ) { + ok_to_continue = false; + continue; + } + if *end as libc::c_int == ' ' as i32 || *end as libc::c_int == '\t' as i32 { + if mmap_string_append_c(mmapstr, *end).is_null() { ok_to_continue = false; continue; } - if *end as libc::c_int == ' ' as i32 || *end as libc::c_int == '\t' as i32 { - if mmap_string_append_c(mmapstr, *end).is_null() { - ok_to_continue = false; - continue; - } - end = end.offset(1isize) + end = end.offset(1isize) + } + if *end as libc::c_int != '\u{0}' as i32 { + if mmap_string_append_len( + mmapstr, + end, + cur.wrapping_offset_from(end) as size_t, + ) + .is_null() + { + ok_to_continue = false; + continue; } - if *end as libc::c_int != '\u{0}' as i32 { - if mmap_string_append_len( - mmapstr, - end, - cur.wrapping_offset_from(end) as size_t, - ) - .is_null() - { - ok_to_continue = false; - continue; - } - } - } else if mmap_string_append_len( - mmapstr, - begin, - cur.wrapping_offset_from(begin) as size_t, - ) - .is_null() - { - ok_to_continue = false; - continue; } - if !(*cur as libc::c_int == ' ' as i32 || *cur as libc::c_int == '\t' as i32) { - continue; - } - if mmap_string_append_c(mmapstr, *cur).is_null() { - ok_to_continue = false; - continue; - } - cur = cur.offset(1isize); - } else { - ret_str = strdup((*mmapstr).str_0); + } else if mmap_string_append_len( + mmapstr, + begin, + cur.wrapping_offset_from(begin) as size_t, + ) + .is_null() + { ok_to_continue = false; + continue; } + if !(*cur as libc::c_int == ' ' as i32 || *cur as libc::c_int == '\t' as i32) { + continue; + } + if mmap_string_append_c(mmapstr, *cur).is_null() { + ok_to_continue = false; + continue; + } + cur = cur.offset(1isize); + } else { + ret_str = strdup((*mmapstr).str_0); + ok_to_continue = false; + } } } From ea6972118a81a096a8c43aff175185ebfb2716e0 Mon Sep 17 00:00:00 2001 From: Friedel Ziegelmayer Date: Wed, 7 Aug 2019 22:20:48 +0200 Subject: [PATCH 83/95] refactor: rusty contact * refactor(contact): rename and rusty memory allocations * refactor(contact): use enum to indidcate origin * refactor(contact): safe blocking and unblocking api * refactor(contact): only safe and no more cstrings --- Cargo.lock | 10 + Cargo.toml | 1 + deltachat-ffi/src/lib.rs | 124 +++-- examples/repl/cmdline.rs | 78 +-- examples/simple.rs | 8 +- src/aheader.rs | 4 +- src/chatlist.rs | 10 +- src/contact.rs | 1093 ++++++++++++++++++++++++++++++++++++ src/context.rs | 4 +- src/dc_chat.rs | 89 ++- src/dc_contact.rs | 1137 -------------------------------------- src/dc_lot.rs | 20 +- src/dc_mimefactory.rs | 28 +- src/dc_mimeparser.rs | 17 +- src/dc_msg.rs | 51 +- src/dc_qr.rs | 59 +- src/dc_receive_imf.rs | 190 ++++--- src/dc_securejoin.rs | 114 ++-- src/dc_tools.rs | 48 +- src/lib.rs | 2 +- src/stock.rs | 91 ++- tests/stress.rs | 19 +- 22 files changed, 1566 insertions(+), 1631 deletions(-) create mode 100644 src/contact.rs delete mode 100644 src/dc_contact.rs diff --git a/Cargo.lock b/Cargo.lock index d576a5f59..9a7559b4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -471,6 +471,7 @@ dependencies = [ "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "imap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", @@ -927,6 +928,14 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itertools" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.4.4" @@ -2762,6 +2771,7 @@ dependencies = [ "checksum imap-proto 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4e77b1d61faf028893531b071cc5584cdd02b6186cebe7f7168ffd8d591339a" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" +"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" diff --git a/Cargo.toml b/Cargo.toml index dfdfa7fe0..94ddf9337 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ strum_macros = "0.15.0" thread-local-object = "0.1.0" backtrace = "0.3.33" byteorder = "1.3.1" +itertools = "0.8.0" [dev-dependencies] tempfile = "3.0" diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 5652c450c..82098cb35 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -14,7 +14,8 @@ extern crate num_traits; use num_traits::{FromPrimitive, ToPrimitive}; use std::str::FromStr; -use deltachat::dc_tools::StrExt; +use deltachat::contact::Contact; +use deltachat::dc_tools::{as_str, StrExt}; use deltachat::*; // TODO: constants @@ -701,7 +702,7 @@ pub unsafe extern "C" fn dc_marknoticed_contact(context: *mut dc_context_t, cont assert!(!context.is_null()); let context = &*context; - dc_contact::dc_marknoticed_contact(context, contact_id) + Contact::mark_noticed(context, contact_id) } #[no_mangle] @@ -748,7 +749,7 @@ pub unsafe extern "C" fn dc_get_msg<'a>( #[no_mangle] pub unsafe extern "C" fn dc_may_be_valid_addr(addr: *mut libc::c_char) -> libc::c_int { assert!(!addr.is_null()); - dc_contact::dc_may_be_valid_addr(addr) as libc::c_int + contact::may_be_valid_addr(as_str(addr)) as libc::c_int } #[no_mangle] @@ -760,7 +761,7 @@ pub unsafe extern "C" fn dc_lookup_contact_id_by_addr( assert!(!addr.is_null()); let context = &*context; - dc_contact::dc_lookup_contact_id_by_addr(context, addr) + Contact::lookup_id_by_addr(context, as_str(addr)) } #[no_mangle] @@ -771,9 +772,15 @@ pub unsafe extern "C" fn dc_create_contact( ) -> u32 { assert!(!context.is_null()); assert!(!addr.is_null()); + let context = &*context; - dc_contact::dc_create_contact(context, name, addr) + let name = if name.is_null() { "" } else { as_str(name) }; + + match Contact::create(context, name, as_str(addr)) { + Ok(id) => id, + Err(_) => 0, + } } #[no_mangle] @@ -785,7 +792,10 @@ pub unsafe extern "C" fn dc_add_address_book( assert!(!addr_book.is_null()); let context = &*context; - dc_contact::dc_add_address_book(context, addr_book) + match Contact::add_address_book(context, as_str(addr_book)) { + Ok(cnt) => cnt as libc::c_int, + Err(_) => 0, + } } #[no_mangle] @@ -797,7 +807,16 @@ pub unsafe extern "C" fn dc_get_contacts( assert!(!context.is_null()); let context = &*context; - dc_contact::dc_get_contacts(context, flags, query) + let query = if query.is_null() { + None + } else { + Some(as_str(query)) + }; + + match Contact::get_all(context, flags, query) { + Ok(contacts) => contacts, + Err(_) => std::ptr::null_mut(), + } } #[no_mangle] @@ -805,7 +824,7 @@ pub unsafe extern "C" fn dc_get_blocked_cnt(context: *mut dc_context_t) -> libc: assert!(!context.is_null()); let context = &*context; - dc_contact::dc_get_blocked_cnt(context) + Contact::get_blocked_cnt(context) as libc::c_int } #[no_mangle] @@ -815,7 +834,7 @@ pub unsafe extern "C" fn dc_get_blocked_contacts( assert!(!context.is_null()); let context = &*context; - dc_contact::dc_get_blocked_contacts(context) + Contact::get_all_blocked(context) } #[no_mangle] @@ -827,7 +846,11 @@ pub unsafe extern "C" fn dc_block_contact( assert!(!context.is_null()); let context = &*context; - dc_contact::dc_block_contact(context, contact_id, block) + if block == 0 { + Contact::unblock(context, contact_id); + } else { + Contact::block(context, contact_id); + } } #[no_mangle] @@ -838,7 +861,7 @@ pub unsafe extern "C" fn dc_get_contact_encrinfo( assert!(!context.is_null()); let context = &*context; - dc_contact::dc_get_contact_encrinfo(context, contact_id) + Contact::get_encrinfo(context, contact_id).strdup() } #[no_mangle] @@ -849,18 +872,23 @@ pub unsafe extern "C" fn dc_delete_contact( assert!(!context.is_null()); let context = &*context; - dc_contact::dc_delete_contact(context, contact_id) as libc::c_int + match Contact::delete(context, contact_id) { + Ok(_) => 1, + Err(_) => 0, + } } #[no_mangle] pub unsafe extern "C" fn dc_get_contact<'a>( context: *mut dc_context_t, contact_id: u32, -) -> *mut dc_contact::dc_contact_t<'a> { +) -> *mut dc_contact_t<'a> { assert!(!context.is_null()); let context = &*context; - dc_contact::dc_get_contact(context, contact_id) + Contact::get_by_id(context, contact_id) + .map(|contact| Box::into_raw(Box::new(contact))) + .unwrap_or_else(|_| std::ptr::null_mut()) } #[no_mangle] @@ -1634,99 +1662,103 @@ pub unsafe extern "C" fn dc_msg_latefiling_mediasize( // dc_contact_t #[no_mangle] -pub type dc_contact_t<'a> = dc_contact::dc_contact_t<'a>; +pub type dc_contact_t<'a> = contact::Contact<'a>; #[no_mangle] -pub unsafe extern "C" fn dc_contact_unref(contact: *mut dc_contact::dc_contact_t) { +pub unsafe extern "C" fn dc_contact_unref(contact: *mut dc_contact_t) { assert!(!contact.is_null()); - - dc_contact::dc_contact_unref(contact) + Box::from_raw(contact); } #[no_mangle] -pub unsafe extern "C" fn dc_contact_get_id(contact: *mut dc_contact::dc_contact_t) -> u32 { +pub unsafe extern "C" fn dc_contact_get_id(contact: *mut dc_contact_t) -> u32 { assert!(!contact.is_null()); + let contact = &*contact; - dc_contact::dc_contact_get_id(contact) + contact.get_id() } #[no_mangle] -pub unsafe extern "C" fn dc_contact_get_addr( - contact: *mut dc_contact::dc_contact_t, -) -> *mut libc::c_char { +pub unsafe extern "C" fn dc_contact_get_addr(contact: *mut dc_contact_t) -> *mut libc::c_char { assert!(!contact.is_null()); + let contact = &*contact; - dc_contact::dc_contact_get_addr(contact) + contact.get_addr().strdup() } #[no_mangle] -pub unsafe extern "C" fn dc_contact_get_name( - contact: *mut dc_contact::dc_contact_t, -) -> *mut libc::c_char { +pub unsafe extern "C" fn dc_contact_get_name(contact: *mut dc_contact_t) -> *mut libc::c_char { assert!(!contact.is_null()); + let contact = &*contact; - dc_contact::dc_contact_get_name(contact) + contact.get_name().strdup() } #[no_mangle] pub unsafe extern "C" fn dc_contact_get_display_name( - contact: *mut dc_contact::dc_contact_t, + contact: *mut dc_contact_t, ) -> *mut libc::c_char { assert!(!contact.is_null()); + let contact = &*contact; - dc_contact::dc_contact_get_display_name(contact) + contact.get_display_name().strdup() } #[no_mangle] pub unsafe extern "C" fn dc_contact_get_name_n_addr( - contact: *mut dc_contact::dc_contact_t, + contact: *mut dc_contact_t, ) -> *mut libc::c_char { assert!(!contact.is_null()); + let contact = &*contact; - dc_contact::dc_contact_get_name_n_addr(contact) + contact.get_name_n_addr().strdup() } #[no_mangle] pub unsafe extern "C" fn dc_contact_get_first_name( - contact: *mut dc_contact::dc_contact_t, + contact: *mut dc_contact_t, ) -> *mut libc::c_char { assert!(!contact.is_null()); + let contact = &*contact; - dc_contact::dc_contact_get_first_name(contact) + contact.get_first_name().strdup() } #[no_mangle] pub unsafe extern "C" fn dc_contact_get_profile_image( - contact: *mut dc_contact::dc_contact_t, + contact: *mut dc_contact_t, ) -> *mut libc::c_char { assert!(!contact.is_null()); + let contact = &*contact; - dc_contact::dc_contact_get_profile_image(contact) + contact + .get_profile_image() + .map(|s| s.strdup()) + .unwrap_or_else(|| std::ptr::null_mut()) } #[no_mangle] -pub unsafe extern "C" fn dc_contact_get_color(contact: *mut dc_contact::dc_contact_t) -> u32 { +pub unsafe extern "C" fn dc_contact_get_color(contact: *mut dc_contact_t) -> u32 { assert!(!contact.is_null()); + let contact = &*contact; - dc_contact::dc_contact_get_color(contact) + contact.get_color() } #[no_mangle] -pub unsafe extern "C" fn dc_contact_is_blocked( - contact: *mut dc_contact::dc_contact_t, -) -> libc::c_int { +pub unsafe extern "C" fn dc_contact_is_blocked(contact: *mut dc_contact_t) -> libc::c_int { assert!(!contact.is_null()); + let contact = &*contact; - dc_contact::dc_contact_is_blocked(contact) + contact.is_blocked() as libc::c_int } #[no_mangle] -pub unsafe extern "C" fn dc_contact_is_verified( - contact: *mut dc_contact::dc_contact_t, -) -> libc::c_int { +pub unsafe extern "C" fn dc_contact_is_verified(contact: *mut dc_contact_t) -> libc::c_int { assert!(!contact.is_null()); + let contact = &*contact; - dc_contact::dc_contact_is_verified(contact) + contact.is_verified() as libc::c_int } // dc_lot_t diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 30f27e67c..b30f1e763 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -4,11 +4,11 @@ use std::str::FromStr; use deltachat::chatlist::*; use deltachat::config; use deltachat::constants::*; +use deltachat::contact::*; use deltachat::context::*; use deltachat::dc_array::*; use deltachat::dc_chat::*; use deltachat::dc_configure::*; -use deltachat::dc_contact::*; use deltachat::dc_imex::*; use deltachat::dc_job::*; use deltachat::dc_location::*; @@ -218,9 +218,10 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int } unsafe fn log_msg(context: &Context, prefix: impl AsRef, msg: *mut dc_msg_t) { - let contact: *mut dc_contact_t = dc_get_contact(context, dc_msg_get_from_id(msg)); - let contact_name: *mut libc::c_char = dc_contact_get_name(contact); - let contact_id: libc::c_int = dc_contact_get_id(contact) as libc::c_int; + let contact = Contact::get_by_id(context, dc_msg_get_from_id(msg)).expect("invalid contact"); + let contact_name = contact.get_name(); + let contact_id = contact.get_id(); + let statestr = match dc_msg_get_state(msg) { DC_STATE_OUT_PENDING => " o", DC_STATE_OUT_DELIVERED => " √", @@ -229,7 +230,7 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef, msg: *mut dc_msg_t _ => "", }; let temp2 = dc_timestamp_to_str(dc_msg_get_timestamp(msg)); - let msgtext: *mut libc::c_char = dc_msg_get_text(msg); + let msgtext = dc_msg_get_text(msg); info!( context, 0, @@ -242,7 +243,7 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef, msg: *mut dc_msg_t "" }, if dc_msg_has_location(msg) { "📍" } else { "" }, - as_str(contact_name), + &contact_name, contact_id, as_str(msgtext), if dc_msg_is_starred(msg) { "★" } else { "" }, @@ -264,8 +265,6 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef, msg: *mut dc_msg_t &temp2, ); free(msgtext as *mut libc::c_void); - free(contact_name as *mut libc::c_void); - dc_contact_unref(contact); } unsafe fn log_msglist(context: &Context, msglist: *mut dc_array_t) { @@ -303,7 +302,6 @@ unsafe fn log_msglist(context: &Context, msglist: *mut dc_array_t) { } unsafe fn log_contactlist(context: &Context, contacts: *mut dc_array_t) { - let mut contact: *mut dc_contact_t; if !dc_array_search_id(contacts, 1 as uint32_t, 0 as *mut size_t) { dc_array_add_id(contacts, 1 as uint32_t); } @@ -312,13 +310,12 @@ unsafe fn log_contactlist(context: &Context, contacts: *mut dc_array_t) { let contact_id = dc_array_get_id(contacts, i as size_t); let line; let mut line2 = "".to_string(); - contact = dc_get_contact(context, contact_id); - if !contact.is_null() { - let name: *mut libc::c_char = dc_contact_get_name(contact); - let addr: *mut libc::c_char = dc_contact_get_addr(contact); - let verified_state: libc::c_int = dc_contact_is_verified(contact); - let verified_str = if 0 != verified_state { - if verified_state == 2 { + 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_str = if VerifiedStatus::Unverified != verified_state { + if verified_state == VerifiedStatus::BidirectVerified { " √√" } else { " √" @@ -328,28 +325,26 @@ unsafe fn log_contactlist(context: &Context, contacts: *mut dc_array_t) { }; line = format!( "{}{} <{}>", - if !name.is_null() && 0 != *name.offset(0isize) as libc::c_int { - as_str(name) + if !name.is_empty() { + &name } else { "" }, verified_str, - if !addr.is_null() && 0 != *addr.offset(0isize) as libc::c_int { - as_str(addr) + if !addr.is_empty() { + &addr } else { "addr unset" } ); - let peerstate = Peerstate::from_addr(context, &context.sql, as_str(addr)); + let peerstate = Peerstate::from_addr(context, &context.sql, &addr); if peerstate.is_some() && contact_id != 1 as libc::c_uint { line2 = format!( ", prefer-encrypt={}", peerstate.as_ref().unwrap().prefer_encrypt ); } - dc_contact_unref(contact); - free(name as *mut libc::c_void); - free(addr as *mut libc::c_void); + info!(context, 0, "Contact#{}: {}{}", contact_id, line, line2); } } @@ -1060,15 +1055,15 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E dc_delete_msgs(context, ids.as_mut_ptr(), 1); } "listcontacts" | "contacts" | "listverified" => { - let contacts = dc_get_contacts( + let contacts = Contact::get_all( context, if arg0 == "listverified" { 0x1 | 0x2 } else { 0x2 }, - arg1_c, - ); + Some(arg1), + )?; if !contacts.is_null() { log_contactlist(context, contacts); println!("{} contacts.", dc_array_get_cnt(contacts) as libc::c_int,); @@ -1081,33 +1076,22 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E ensure!(!arg1.is_empty(), "Arguments [] expected."); if !arg2.is_empty() { - let book = dc_mprintf( - b"%s\n%s\x00" as *const u8 as *const libc::c_char, - arg1_c, - arg2_c, - ); - dc_add_address_book(context, book); - free(book as *mut libc::c_void); + let book = format!("{}\n{}", arg1, arg2); + Contact::add_address_book(context, book)?; } else { - if 0 == dc_create_contact(context, 0 as *const libc::c_char, arg1_c) { - bail!("Failed to create contact"); - } + Contact::create(context, "", arg1)?; } } "contactinfo" => { ensure!(!arg1.is_empty(), "Argument missing."); let contact_id = arg1.parse()?; - let contact = dc_get_contact(context, contact_id); - let name_n_addr = dc_contact_get_name_n_addr(contact); + let contact = Contact::get_by_id(context, contact_id)?; + let name_n_addr = contact.get_name_n_addr(); - let mut res = format!("Contact info for: {}:\n\n", as_str(name_n_addr),); - free(name_n_addr as *mut libc::c_void); - dc_contact_unref(contact); + let mut res = format!("Contact info for: {}:\n\n", name_n_addr); - let encrinfo = dc_get_contact_encrinfo(context, contact_id); - res += as_str(encrinfo); - free(encrinfo as *mut libc::c_void); + res += &Contact::get_encrinfo(context, contact_id); let chatlist = Chatlist::try_load(context, 0, None, Some(contact_id))?; let chatlist_cnt = chatlist.len(); @@ -1130,9 +1114,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E } "delcontact" => { ensure!(!arg1.is_empty(), "Argument missing."); - if !dc_delete_contact(context, arg1.parse()?) { - bail!("Failed to delete contact"); - } + Contact::delete(context, arg1.parse()?)?; } "checkqr" => { ensure!(!arg1.is_empty(), "Argument missing."); diff --git a/examples/simple.rs b/examples/simple.rs index 1ec8da0f1..628414c93 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,6 +1,6 @@ extern crate deltachat; -use std::ffi::{CStr, CString}; +use std::ffi::CStr; use std::sync::{Arc, RwLock}; use std::{thread, time}; use tempfile::tempdir; @@ -8,10 +8,10 @@ use tempfile::tempdir; use deltachat::chatlist::*; use deltachat::config; use deltachat::constants::Event; +use deltachat::contact::*; use deltachat::context::*; use deltachat::dc_chat::*; use deltachat::dc_configure::*; -use deltachat::dc_contact::*; use deltachat::dc_job::{ dc_perform_imap_fetch, dc_perform_imap_idle, dc_perform_imap_jobs, dc_perform_smtp_idle, dc_perform_smtp_jobs, @@ -93,9 +93,9 @@ fn main() { thread::sleep(duration); - let email = CString::new("dignifiedquire@gmail.com").unwrap(); println!("sending a message"); - let contact_id = dc_create_contact(&ctx, std::ptr::null(), email.as_ptr()); + let contact_id = + Contact::create(&ctx, "dignifiedquire", "dignifiedquire@gmail.com").unwrap(); let chat_id = dc_create_chat_by_contact_id(&ctx, contact_id); dc_send_text_msg(&ctx, chat_id, "Hi, here is my first message!".into()); diff --git a/src/aheader.rs b/src/aheader.rs index 35fcb25ca..20a2daa2c 100644 --- a/src/aheader.rs +++ b/src/aheader.rs @@ -6,7 +6,7 @@ use std::{fmt, str}; use mmime::mailimf_types::*; use crate::constants::*; -use crate::dc_contact::*; +use crate::contact::*; use crate::dc_tools::as_str; use crate::key::*; @@ -94,7 +94,7 @@ impl Aheader { match Self::from_str(value) { Ok(test) => { - if dc_addr_cmp(&test.addr, as_str(wanted_from)) { + if addr_cmp(&test.addr, as_str(wanted_from)) { if fine_header.is_none() { fine_header = Some(test); } else { diff --git a/src/chatlist.rs b/src/chatlist.rs index 6b93fe8fc..901e0b35b 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -1,7 +1,7 @@ use crate::constants::*; +use crate::contact::*; use crate::context::*; use crate::dc_chat::*; -use crate::dc_contact::*; use crate::dc_lot::*; use crate::dc_msg::*; use crate::dc_tools::*; @@ -261,7 +261,7 @@ impl<'a> Chatlist<'a> { } let lastmsg_id = self.ids[index].1; - let mut lastcontact = 0 as *mut dc_contact_t; + let mut lastcontact = None; if chat.is_null() { chat = dc_chat_new(self.context); @@ -282,8 +282,7 @@ impl<'a> Chatlist<'a> { && ((*chat).type_0 == DC_CHAT_TYPE_GROUP || (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP) { - lastcontact = dc_contact_new(self.context); - dc_contact_load_from_db(lastcontact, &self.context.sql, (*lastmsg).from_id); + lastcontact = Contact::load_from_db(self.context, (*lastmsg).from_id).ok(); } lastmsg } else { @@ -295,11 +294,10 @@ impl<'a> Chatlist<'a> { } else if lastmsg.is_null() || (*lastmsg).from_id == DC_CONTACT_ID_SELF as u32 { (*ret).text2 = self.context.stock_str(StockMessage::NoMessages).strdup(); } else { - dc_lot_fill(ret, lastmsg, chat, lastcontact, self.context); + dc_lot_fill(ret, lastmsg, chat, lastcontact.as_ref(), self.context); } dc_msg_unref(lastmsg); - dc_contact_unref(lastcontact); ret } diff --git a/src/contact.rs b/src/contact.rs new file mode 100644 index 000000000..30d4ed42c --- /dev/null +++ b/src/contact.rs @@ -0,0 +1,1093 @@ +use itertools::Itertools; +use num_traits::{FromPrimitive, ToPrimitive}; +use rusqlite; +use rusqlite::types::*; + +use crate::aheader::EncryptPreference; +use crate::config::Config; +use crate::constants::*; +use crate::context::Context; +use crate::dc_array::*; +use crate::dc_e2ee::*; +use crate::dc_loginparam::*; +use crate::dc_tools::*; +use crate::error::Result; +use crate::key::*; +use crate::peerstate::*; +use crate::sql; +use crate::stock::StockMessage; +use crate::types::*; + +const DC_GCL_VERIFIED_ONLY: u32 = 0x01; + +/// Contacts with at least this origin value are shown in the contact list. +const DC_ORIGIN_MIN_CONTACT_LIST: i32 = 0x100; + +/// An object representing a single contact in memory. +/// The contact object is not updated. +/// If you want an update, you have to recreate the object. +/// +/// The library makes sure +/// only to use names _authorized_ by the contact in `To:` or `Cc:`. +/// _Given-names _as "Daddy" or "Honey" are not used there. +/// 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, + /// The contact ID. + /// + /// Special message IDs: + /// - DC_CONTACT_ID_SELF (1) - this is the owner of the account with the email-address set by + /// `dc_set_config` using "addr". + /// + /// Normal contact IDs are larger than these special ones (larger than DC_CONTACT_ID_LAST_SPECIAL). + pub id: u32, + /// Contact name. It is recommended to use `Contact::get_name`, + /// `Contact::get_display_name` or `Contact::get_name_n_addr` to access this field. + /// May be empty, initially set to `authname`. + name: String, + /// Name authorized by the contact himself. Only this name may be spread to others, + /// e.g. in To:-lists. May be empty. It is recommended to use `Contact::get_name`, + /// `Contact::get_display_name` or `Contact::get_name_n_addr` to access this field. + authname: String, + /// E-Mail-Address of the contact. It is recommended to use `Contact::get_addr`` to access this field. + addr: String, + /// Blocked state. Use dc_contact_is_blocked to access this field. + blocked: bool, + /// The origin/source of the contact. + pub origin: Origin, +} + +/// Possible origins of a contact. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromPrimitive, ToPrimitive)] +#[repr(i32)] +pub enum Origin { + Unknown = 0, + /// From: of incoming messages of unknown sender + IncomingUnknownFrom = 0x10, + /// Cc: of incoming messages of unknown sender + IncomingUnknownCc = 0x20, + /// To: of incoming messages of unknown sender + IncomingUnknownTo = 0x40, + /// address scanned but not verified + UnhandledQrScan = 0x80, + /// Reply-To: of incoming message of known sender + IncomingReplyTo = 0x100, + /// Cc: of incoming message of known sender + IncomingCc = 0x200, + /// additional To:'s of incoming message of known sender + IncomingTo = 0x400, + /// a chat was manually created for this user, but no message yet sent + CreateChat = 0x800, + /// message sent by us + OutgoingBcc = 0x1000, + /// message sent by us + OutgoingCc = 0x2000, + /// message sent by us + OutgoingTo = 0x4000, + /// internal use + Internal = 0x40000, + /// address is in our address book + AdressBook = 0x80000, + /// set on Alice's side for contacts like Bob that have scanned the QR code offered by her. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling dc_contact_is_verified() ! + SecurejoinInvited = 0x1000000, + /// set on Bob's side for contacts scanned and verified from a QR code. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling dc_contact_is_verified() ! + SecurejoinJoined = 0x2000000, + /// contact added mannually by dc_create_contact(), this should be the largets origin as otherwise the user cannot modify the names + ManuallyCreated = 0x4000000, +} + +impl ToSql for Origin { + fn to_sql(&self) -> rusqlite::Result { + let num: i64 = self + .to_i64() + .expect("impossible: Origin -> i64 conversion failed"); + + Ok(ToSqlOutput::Owned(Value::Integer(num))) + } +} + +impl FromSql for Origin { + fn column_result(col: ValueRef) -> FromSqlResult { + let inner = FromSql::column_result(col)?; + FromPrimitive::from_i64(inner).ok_or(FromSqlError::InvalidType) + } +} + +impl Origin { + /// Contacts that start a new "normal" chat, defaults to off. + pub fn is_start_new_chat(self) -> bool { + self as i32 >= 0x7FFFFFFF + } + + /// Contacts that are verified and known not to be spam. + pub fn is_verified(self) -> bool { + self as i32 >= 0x100 + } + + /// Contacts that are shown in the contact list. + pub fn include_in_contactlist(self) -> bool { + self as i32 >= DC_ORIGIN_MIN_CONTACT_LIST + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum Modifier { + None, + Modified, + Created, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[repr(u8)] +pub enum VerifiedStatus { + /// Contact is not verified. + Unverified = 0, + // TODO: is this a thing? + Verified = 1, + /// SELF and contact have verified their fingerprints in both directions; in the UI typically checkmarks are shown. + BidirectVerified = 2, +} + +impl<'a> Contact<'a> { + pub fn load_from_db(context: &'a Context, contact_id: u32) -> Result { + if contact_id == DC_CONTACT_ID_SELF as u32 { + let contact = Contact { + context, + id: contact_id, + name: context.stock_str(StockMessage::SelfMsg).into(), + authname: "".into(), + addr: context + .get_config(Config::ConfiguredAddr) + .unwrap_or_default(), + blocked: false, + origin: Origin::Unknown, + }; + + return Ok(contact); + } + + context.sql.query_row( + "SELECT c.name, c.addr, c.origin, c.blocked, c.authname FROM contacts c WHERE c.id=?;", + params![contact_id as i32], + |row| { + let contact = Self { + context, + id: contact_id, + name: row.get::<_, String>(0)?, + authname: row.get::<_, String>(4)?, + addr: row.get::<_, String>(1)?, + blocked: row.get::<_, Option>(3)?.unwrap_or_default() != 0, + origin: row.get(2)?, + }; + Ok(contact) + } + ) + } + + /// Returns `true` if this contact is blocked. + pub fn is_blocked(&self) -> bool { + self.blocked + } + + /// Check if a contact is blocked. + pub fn is_blocked_load(context: &'a Context, id: u32) -> bool { + Self::load_from_db(context, id) + .map(|contact| contact.blocked) + .unwrap_or_default() + } + + /// Block the given contact. + pub fn block(context: &Context, id: u32) { + set_block_contact(context, id, true); + } + + /// Unblock the given contact. + pub fn unblock(context: &Context, id: u32) { + set_block_contact(context, id, false); + } + + /// Add a single contact as a result of an _explicit_ user action. + /// + /// We assume, the contact name, if any, is entered by the user and is used "as is" therefore, + /// normalize() is _not_ called for the name. If the contact is blocked, it is unblocked. + /// + /// To add a number of contacts, see `dc_add_address_book()` which is much faster for adding + /// a bunch of addresses. + /// + /// May result in a `#DC_EVENT_CONTACTS_CHANGED` event. + pub fn create(context: &Context, name: impl AsRef, addr: impl AsRef) -> Result { + ensure!( + !addr.as_ref().is_empty(), + "Cannot create contact with empty address" + ); + + let (contact_id, sth_modified) = + Contact::add_or_lookup(context, name, addr, Origin::ManuallyCreated)?; + let blocked = Contact::is_blocked_load(context, contact_id); + context.call_cb( + Event::CONTACTS_CHANGED, + (if sth_modified == Modifier::Created { + contact_id + } else { + 0 + }) as uintptr_t, + 0 as uintptr_t, + ); + if blocked { + Contact::unblock(context, contact_id); + } + + Ok(contact_id) + } + + /// Mark all messages sent by the given contact + /// as _noticed_. See also dc_marknoticed_chat() and dc_markseen_msgs() + /// + /// Calling this function usually results in the event `#DC_EVENT_MSGS_CHANGED`. + pub fn mark_noticed(context: &Context, id: u32) { + if sql::execute( + context, + &context.sql, + "UPDATE msgs SET state=? WHERE from_id=? AND state=?;", + params![DC_STATE_IN_NOTICED, id as i32, DC_STATE_IN_FRESH], + ) + .is_ok() + { + context.call_cb(Event::MSGS_CHANGED, 0, 0); + } + } + + /// Check if an e-mail address belongs to a known and unblocked contact. + /// Known and unblocked contacts will be returned by `dc_get_contacts()`. + /// + /// To validate an e-mail address independently of the contact database + /// use `dc_may_be_valid_addr()`. + pub fn lookup_id_by_addr(context: &Context, addr: impl AsRef) -> u32 { + if addr.as_ref().is_empty() { + return 0; + } + + let addr_normalized = addr_normalize(addr.as_ref()); + let addr_self = context + .get_config(Config::ConfiguredAddr) + .unwrap_or_default(); + + if addr_normalized == addr_self { + return 1; + } + + context.sql.query_row_col( + context, + "SELECT id FROM contacts WHERE addr=?1 COLLATE NOCASE AND id>?2 AND origin>=?3 AND blocked=0;", + params![ + addr_normalized, + DC_CONTACT_ID_LAST_SPECIAL as i32, + DC_ORIGIN_MIN_CONTACT_LIST, + ], + 0 + ).unwrap_or_default() + } + + /// Lookup a contact and create it if it does not exist yet. + /// + /// Returns the contact_id and a `Modifier` value indicating if a modification occured. + pub fn add_or_lookup( + context: &Context, + name: impl AsRef, + addr: impl AsRef, + origin: Origin, + ) -> Result<(u32, Modifier)> { + let mut sth_modified = Modifier::None; + + ensure!( + !addr.as_ref().is_empty(), + "Can not add_or_lookup empty address" + ); + ensure!(origin != Origin::Unknown, "Missing valid origin"); + + let addr = addr_normalize(addr.as_ref()); + let addr_self = context + .get_config(Config::ConfiguredAddr) + .unwrap_or_default(); + + if addr == addr_self { + return Ok((1, sth_modified)); + } + + if !may_be_valid_addr(&addr) { + warn!( + context, + 0, + "Bad address \"{}\" for contact \"{}\".", + addr, + if !name.as_ref().is_empty() { + name.as_ref() + } else { + "" + }, + ); + bail!("Bad address supplied"); + } + + let mut update_addr = false; + let mut update_name = false; + let mut update_authname = false; + let mut row_id = 0; + + if let Ok((id, row_name, row_addr, row_origin, row_authname)) = context.sql.query_row( + "SELECT id, name, addr, origin, authname FROM contacts WHERE addr=? COLLATE NOCASE;", + params![addr], + |row| { + let row_id = row.get(0)?; + let row_name: String = row.get(1)?; + let row_addr: String = row.get(2)?; + let row_origin = row.get(3)?; + let row_authname: String = row.get(4)?; + + if !name.as_ref().is_empty() && !row_name.is_empty() { + if origin >= row_origin && name.as_ref() != row_name { + update_name = true; + } + } else { + update_name = true; + } + if origin == Origin::IncomingUnknownFrom && name.as_ref() != row_authname { + update_authname = true; + } + Ok((row_id, row_name, row_addr, row_origin, row_authname)) + }, + ) { + row_id = id; + if origin as i32 >= row_origin as i32 && addr != row_addr { + update_addr = true; + } + if update_name || update_authname || update_addr || origin > row_origin { + sql::execute( + context, + &context.sql, + "UPDATE contacts SET name=?, addr=?, origin=?, authname=? WHERE id=?;", + params![ + if update_name { + name.as_ref() + } else { + &row_name + }, + if update_addr { addr } else { &row_addr }, + if origin > row_origin { + origin + } else { + row_origin + }, + if update_authname { + name.as_ref() + } else { + &row_authname + }, + row_id + ], + ) + .ok(); + + if update_name { + sql::execute( + context, + &context.sql, + "UPDATE chats SET name=? WHERE type=? AND id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?);", + params![name.as_ref(), 100, row_id] + ).ok(); + } + sth_modified = Modifier::Modified; + } + } else { + if sql::execute( + context, + &context.sql, + "INSERT INTO contacts (name, addr, origin) VALUES(?, ?, ?);", + params![name.as_ref(), addr, origin,], + ) + .is_ok() + { + row_id = sql::get_rowid(context, &context.sql, "contacts", "addr", addr); + sth_modified = Modifier::Created; + } else { + error!(context, 0, "Cannot add contact."); + } + } + + Ok((row_id, sth_modified)) + } + + /// Add a number of contacts. + /// + /// Typically used to add the whole address book from the OS. As names here are typically not + /// well formatted, we call `normalize()` for each name given. + /// + /// No email-address is added twice. + /// Trying to add email-addresses that are already in the contact list, + /// results in updating the name unless the name was changed manually by the user. + /// If any email-address or any name is really updated, + /// the event `DC_EVENT_CONTACTS_CHANGED` is sent. + /// + /// To add a single contact entered by the user, you should prefer `Contact::create`, + /// however, for adding a bunch of addresses, this function is _much_ faster. + /// + /// The `adr_book` is a multiline string in the format `Name one\nAddress one\nName two\nAddress two`. + /// + /// Returns the number of modified contacts. + pub fn add_address_book(context: &Context, adr_book: impl AsRef) -> Result { + let mut modify_cnt = 0; + + for chunk in &adr_book.as_ref().lines().chunks(2) { + let chunk = chunk.collect::>(); + if chunk.len() < 2 { + break; + } + let name = chunk[0]; + let addr = chunk[1]; + let name = normalize_name(name); + let (_, modified) = Contact::add_or_lookup(context, name, addr, Origin::AdressBook)?; + if modified != Modifier::None { + modify_cnt += 1 + } + } + if modify_cnt > 0 { + context.call_cb(Event::CONTACTS_CHANGED, 0 as uintptr_t, 0 as uintptr_t); + } + + Ok(modify_cnt) + } + + /// Returns known and unblocked contacts. + /// + /// To get information about a single contact, see dc_get_contact(). + /// + /// `listflags` is a combination of flags: + /// - if the flag DC_GCL_ADD_SELF is set, SELF is added to the list unless filtered by other parameters + /// - if the flag DC_GCL_VERIFIED_ONLY is set, only verified contacts are returned. + /// if DC_GCL_VERIFIED_ONLY is not set, verified and unverified contacts are returned. + /// `query` is a string to filter the list. + pub fn get_all( + context: &Context, + listflags: u32, + query: Option>, + ) -> Result<*mut dc_array_t> { + let self_addr = context + .get_config(Config::ConfiguredAddr) + .unwrap_or_default(); + + let mut add_self = false; + let mut ret = dc_array_t::new(100); + + if (listflags & DC_GCL_VERIFIED_ONLY) > 0 || query.is_some() { + let s3str_like_cmd = format!( + "%{}%", + query + .as_ref() + .map(|s| s.as_ref().to_string()) + .unwrap_or_default() + ); + context.sql.query_map( + "SELECT c.id FROM contacts c \ + LEFT JOIN acpeerstates ps ON c.addr=ps.addr \ + WHERE c.addr!=?1 \ + AND c.id>?2 \ + AND c.origin>=?3 \ + AND c.blocked=0 \ + AND (c.name LIKE ?4 OR c.addr LIKE ?5) \ + AND (1=?6 OR LENGTH(ps.verified_key_fingerprint)!=0) \ + ORDER BY LOWER(c.name||c.addr),c.id;", + params![ + self_addr, + DC_CONTACT_ID_LAST_SPECIAL as i32, + 0x100, + &s3str_like_cmd, + &s3str_like_cmd, + if 0 != listflags & 0x1 { 0 } else { 1 }, + ], + |row| row.get::<_, i32>(0), + |ids| { + for id in ids { + ret.add_id(id? as u32); + } + Ok(()) + }, + )?; + + let self_name = context.get_config(Config::Displayname).unwrap_or_default(); + let self_name2 = context.stock_str(StockMessage::SelfMsg); + + if let Some(query) = query { + if self_addr.contains(query.as_ref()) + || self_name.contains(query.as_ref()) + || self_name2.contains(query.as_ref()) + { + add_self = true; + } + } else { + add_self = true; + } + } else { + add_self = true; + + context.sql.query_map( + "SELECT id FROM contacts WHERE addr!=?1 AND id>?2 AND origin>=?3 AND blocked=0 ORDER BY LOWER(name||addr),id;", + params![self_addr, DC_CONTACT_ID_LAST_SPECIAL as i32, 0x100], + |row| row.get::<_, i32>(0), + |ids| { + for id in ids { + ret.add_id(id? as u32); + } + Ok(()) + } + )?; + } + + if 0 != listflags & DC_GCL_ADD_SELF as u32 && add_self { + ret.add_id(DC_CONTACT_ID_SELF as u32); + } + + Ok(ret.into_raw()) + } + + pub fn get_blocked_cnt(context: &Context) -> usize { + context + .sql + .query_row_col::<_, isize>( + context, + "SELECT COUNT(*) FROM contacts WHERE id>? AND blocked!=0", + params![DC_CONTACT_ID_LAST_SPECIAL as i32], + 0, + ) + .unwrap_or_default() as usize + } + + /// Get blocked contacts. + pub fn get_all_blocked(context: &Context) -> *mut dc_array_t { + context + .sql + .query_map( + "SELECT id FROM contacts WHERE id>? AND blocked!=0 ORDER BY LOWER(name||addr),id;", + params![DC_CONTACT_ID_LAST_SPECIAL as i32], + |row| row.get::<_, i32>(0), + |ids| { + let mut ret = dc_array_t::new(100); + + for id in ids { + ret.add_id(id? as u32); + } + + Ok(ret.into_raw()) + }, + ) + .unwrap_or_else(|_| std::ptr::null_mut()) + } + + pub fn get_encrinfo(context: &Context, contact_id: u32) -> String { + let mut ret = String::new(); + + if let Ok(contact) = Contact::load_from_db(context, contact_id) { + let peerstate = Peerstate::from_addr(context, &context.sql, &contact.addr); + let loginparam = dc_loginparam_read(context, &context.sql, "configured_"); + + let mut self_key = Key::from_self_public(context, &loginparam.addr, &context.sql); + + if peerstate.is_some() && peerstate.as_ref().and_then(|p| p.peek_key(0)).is_some() { + let peerstate = peerstate.as_ref().unwrap(); + let p = + context.stock_str(if peerstate.prefer_encrypt == EncryptPreference::Mutual { + StockMessage::E2ePreferred + } else { + StockMessage::E2eAvailable + }); + ret += &p; + if self_key.is_none() { + unsafe { dc_ensure_secret_key_exists(context) }; + self_key = Key::from_self_public(context, &loginparam.addr, &context.sql); + } + let p = context.stock_str(StockMessage::FingerPrints); + ret += &format!(" {}:", p); + + let fingerprint_self = self_key + .map(|k| k.formatted_fingerprint()) + .unwrap_or_default(); + let fingerprint_other_verified = peerstate + .peek_key(2) + .map(|k| k.formatted_fingerprint()) + .unwrap_or_default(); + let fingerprint_other_unverified = peerstate + .peek_key(0) + .map(|k| k.formatted_fingerprint()) + .unwrap_or_default(); + if peerstate.addr.is_some() && &loginparam.addr < peerstate.addr.as_ref().unwrap() { + cat_fingerprint(&mut ret, &loginparam.addr, &fingerprint_self, ""); + cat_fingerprint( + &mut ret, + peerstate.addr.as_ref().unwrap(), + &fingerprint_other_verified, + &fingerprint_other_unverified, + ); + } else { + cat_fingerprint( + &mut ret, + peerstate.addr.as_ref().unwrap(), + &fingerprint_other_verified, + &fingerprint_other_unverified, + ); + cat_fingerprint(&mut ret, &loginparam.addr, &fingerprint_self, ""); + } + } else if 0 == loginparam.server_flags & DC_LP_IMAP_SOCKET_PLAIN as i32 + && 0 == loginparam.server_flags & DC_LP_SMTP_SOCKET_PLAIN as i32 + { + ret += &context.stock_str(StockMessage::EncrTransp); + } else { + ret += &context.stock_str(StockMessage::EncrNone); + } + } + + ret + } + + /// Delete a contact. The contact is deleted from the local device. It may happen that this is not + /// possible as the contact is in use. In this case, the contact can be blocked. + /// + /// May result in a `#DC_EVENT_CONTACTS_CHANGED` event. + pub fn delete(context: &Context, contact_id: u32) -> Result<()> { + ensure!( + contact_id > DC_CONTACT_ID_LAST_SPECIAL as u32, + "Can not delete special contact" + ); + + let count_contacts: i32 = context + .sql + .query_row_col( + context, + "SELECT COUNT(*) FROM chats_contacts WHERE contact_id=?;", + params![contact_id as i32], + 0, + ) + .unwrap_or_default(); + + let count_msgs: i32 = if count_contacts > 0 { + context + .sql + .query_row_col( + context, + "SELECT COUNT(*) FROM msgs WHERE from_id=? OR to_id=?;", + params![contact_id as i32, contact_id as i32], + 0, + ) + .unwrap_or_default() + } else { + 0 + }; + + if count_msgs == 0 { + match sql::execute( + context, + &context.sql, + "DELETE FROM contacts WHERE id=?;", + params![contact_id as i32], + ) { + Ok(_) => { + context.call_cb(Event::CONTACTS_CHANGED, 0, 0); + return Ok(()); + } + Err(err) => { + error!(context, 0, "delete_contact {} failed ({})", contact_id, err); + return Err(err); + } + } + } + + info!( + context, + 0, "could not delete contact {}, there are {} messages with it", contact_id, count_msgs + ); + bail!("Could not delete contact with messages in it"); + } + + /// Get a single contact object. For a list, see eg. dc_get_contacts(). + /// + /// For contact DC_CONTACT_ID_SELF (1), the function returns sth. + /// like "Me" in the selected language and the email address + /// defined by dc_set_config(). + pub fn get_by_id(context: &Context, contact_id: u32) -> Result { + Contact::load_from_db(context, contact_id) + } + + /// Get the ID of the contact. + pub fn get_id(&self) -> u32 { + self.id + } + + /// Get email address. The email address is always set for a contact. + pub fn get_addr(&self) -> &str { + &self.addr + } + + pub fn get_authname(&self) -> &str { + &self.authname + } + + /// Get the contact name. This is the name as defined by the contact himself or + /// modified by the user. May be an empty string. + /// + /// This name is typically used in a form where the user can edit the name of a contact. + /// To get a fine name to display in lists etc., use `Contact::get_display_name` or `Contact::get_name_n_addr`. + pub fn get_name(&self) -> &str { + &self.name + } + + /// Get display name. This is the name as defined by the contact himself, + /// modified by the user or, if both are unset, the email address. + /// + /// This name is typically used in lists. + /// To get the name editable in a formular, use `Contact::get_name`. + pub fn get_display_name(&self) -> &str { + if !self.name.is_empty() { + return &self.name; + } + &self.addr + } + + /// Get a summary of name and address. + /// + /// The returned string is either "Name (email@domain.com)" or just + /// "email@domain.com" if the name is unset. + /// + /// The summary is typically used when asking the user something about the contact. + /// The attached email address makes the question unique, eg. "Chat with Alan Miller (am@uniquedomain.com)?" + pub fn get_name_n_addr(&self) -> String { + if !self.name.is_empty() { + return format!("{} ({})", self.name, self.addr); + } + (&self.addr).into() + } + + /// Get the part of the name before the first space. In most languages, this seems to be + /// the prename. If there is no space, the full display name is returned. + /// If the display name is not set, the e-mail address is returned. + pub fn get_first_name(&self) -> &str { + if !self.name.is_empty() { + return get_first_name(&self.name); + } + &self.addr + } + + /// 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 { + if self.id == DC_CONTACT_ID_SELF as u32 { + return self.context.get_config(Config::Selfavatar); + } + // TODO: else get image_abs from contact param + None + } + + /// Get a color for the contact. + /// The color is calculated from the contact's email address + /// and can be used for an fallback avatar with white initials + /// as well as for headlines in bubbles of group chats. + pub fn get_color(&self) -> u32 { + dc_str_to_color_safe(&self.addr) + } + + /// Check if a contact was verified. E.g. by a secure-join QR code scan + /// and if the key has not changed since this verification. + /// + /// The UI may draw a checkbox or something like that beside verified contacts. + /// + pub fn is_verified(&self) -> VerifiedStatus { + self.is_verified_ex(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 { + // 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 as u32 { + return VerifiedStatus::BidirectVerified; + } + + if let Some(peerstate) = peerstate { + if peerstate.verified_key().is_some() { + return VerifiedStatus::BidirectVerified; + } + } + + let peerstate = Peerstate::from_addr(self.context, &self.context.sql, &self.addr); + if let Some(ps) = peerstate { + if ps.verified_key().is_some() { + return VerifiedStatus::BidirectVerified; + } + } + + VerifiedStatus::Unverified + } + + pub fn addr_equals_contact(context: &Context, addr: impl AsRef, contact_id: u32) -> bool { + if addr.as_ref().is_empty() { + return false; + } + + if let Ok(contact) = Contact::load_from_db(context, contact_id) { + if !contact.addr.is_empty() { + let normalized_addr = addr_normalize(addr.as_ref()); + if &contact.addr == &normalized_addr { + return true; + } + } + } + + false + } + + pub fn get_real_cnt(context: &Context) -> usize { + if !context.sql.is_open() { + return 0; + } + + context + .sql + .query_row_col::<_, isize>( + context, + "SELECT COUNT(*) FROM contacts WHERE id>?;", + params![DC_CONTACT_ID_LAST_SPECIAL as i32], + 0, + ) + .unwrap_or_default() as usize + } + + pub fn get_origin_by_id(context: &Context, contact_id: u32, ret_blocked: &mut i32) -> Origin { + let mut ret = Origin::Unknown; + *ret_blocked = 0; + + if let Ok(contact) = Contact::load_from_db(context, contact_id) { + /* we could optimize this by loading only the needed fields */ + if contact.blocked { + *ret_blocked = 1; + } else { + ret = contact.origin; + } + } + + ret + } + + pub fn real_exists_by_id(context: &Context, contact_id: u32) -> bool { + if !context.sql.is_open() || contact_id <= 9 { + return false; + } + + context + .sql + .exists( + "SELECT id FROM contacts WHERE id=?;", + params![contact_id as i32], + ) + .unwrap_or_default() + } + + pub fn scaleup_origin_by_id(context: &Context, contact_id: u32, origin: Origin) -> bool { + context + .sql + .execute( + "UPDATE contacts SET origin=? WHERE id=? AND origin(full_name: &'a str) -> &'a str { + full_name.splitn(2, ' ').next().unwrap_or_default() +} + +/// Returns false if addr is an invalid address, otherwise true. +pub fn may_be_valid_addr(addr: &str) -> bool { + if addr.is_empty() { + return false; + } + + let at = addr.find('@').unwrap_or_default(); + if at < 1 { + return false; + } + let dot = addr.find('.').unwrap_or_default(); + if dot < 1 || dot > addr.len() - 3 || dot < at + 2 { + return false; + } + + true +} + +pub fn addr_normalize(addr: &str) -> &str { + let norm = addr.trim(); + + if norm.starts_with("mailto:") { + return &norm[7..]; + } + + norm +} + +fn set_block_contact(context: &Context, contact_id: u32, new_blocking: bool) { + if contact_id <= 9 { + return; + } + + if let Ok(contact) = Contact::load_from_db(context, contact_id) { + if contact.blocked != new_blocking { + if sql::execute( + context, + &context.sql, + "UPDATE contacts SET blocked=? WHERE id=?;", + params![new_blocking as i32, contact_id as i32], + ) + .is_ok() + { + // also (un)block all chats with _only_ this contact - we do not delete them to allow a + // non-destructive blocking->unblocking. + // (Maybe, beside normal chats (type=100) we should also block group chats with only this user. + // However, I'm not sure about this point; it may be confusing if the user wants to add other people; + // this would result in recreating the same group...) + if sql::execute( + context, + &context.sql, + "UPDATE chats SET blocked=? WHERE type=? AND id IN (SELECT chat_id FROM chats_contacts WHERE contact_id=?);", + params![new_blocking, 100, contact_id as i32], + ).is_ok() { + Contact::mark_noticed(context, contact_id); + context.call_cb( + Event::CONTACTS_CHANGED, + 0, + 0, + ); + } + } + } + } +} + +/// Normalize a name. +/// +/// - Remove quotes (come from some bad MUA implementations) +/// - Convert names as "Petersen, Björn" to "Björn Petersen" +/// - Trims the resulting string +/// +/// Typically, this function is not needed as it is called implicitly by `Contact::add_address_book`. +pub fn normalize_name(full_name: impl AsRef) -> String { + let mut full_name = full_name.as_ref().trim(); + if full_name.is_empty() { + return full_name.into(); + } + + let len = full_name.len(); + if len > 0 { + let firstchar = full_name.as_bytes()[0]; + let lastchar = full_name.as_bytes()[len - 1]; + if firstchar == '\'' as u8 && lastchar == '\'' as u8 + || firstchar == '\"' as u8 && lastchar == '\"' as u8 + || firstchar == '<' as u8 && lastchar == '>' as u8 + { + full_name = &full_name[1..len - 1]; + } + } + + if let Some(p1) = full_name.find(',') { + let (last_name, first_name) = full_name.split_at(p1); + + let last_name = last_name.trim(); + let first_name = (&first_name[1..]).trim(); + + return format!("{} {}", first_name, last_name); + } + + full_name.trim().into() +} + +fn cat_fingerprint( + ret: &mut String, + addr: impl AsRef, + fingerprint_verified: impl AsRef, + fingerprint_unverified: impl AsRef, +) { + *ret += &format!( + "\n\n{}:\n{}", + addr.as_ref(), + if !fingerprint_verified.as_ref().is_empty() { + fingerprint_verified.as_ref() + } else { + fingerprint_unverified.as_ref() + }, + ); + if !fingerprint_verified.as_ref().is_empty() + && !fingerprint_unverified.as_ref().is_empty() + && fingerprint_verified.as_ref() != fingerprint_unverified.as_ref() + { + *ret += &format!( + "\n\n{} (alternative):\n{}", + addr.as_ref(), + fingerprint_unverified.as_ref() + ); + } +} + +pub fn addr_cmp(addr1: impl AsRef, addr2: impl AsRef) -> bool { + let norm1 = addr_normalize(addr1.as_ref()); + let norm2 = addr_normalize(addr2.as_ref()); + + norm1 == norm2 +} + +pub fn addr_equals_self(context: &Context, addr: impl AsRef) -> 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) { + return normalized_addr == self_addr; + } + } + false +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_may_be_valid_addr() { + assert_eq!(may_be_valid_addr(""), false); + assert_eq!(may_be_valid_addr("user@domain.tld"), true); + assert_eq!(may_be_valid_addr("uuu"), false); + assert_eq!(may_be_valid_addr("dd.tt"), false); + assert_eq!(may_be_valid_addr("tt.dd@uu"), false); + assert_eq!(may_be_valid_addr("u@d"), false); + assert_eq!(may_be_valid_addr("u@d."), false); + assert_eq!(may_be_valid_addr("u@d.t"), false); + assert_eq!(may_be_valid_addr("u@d.tt"), true); + assert_eq!(may_be_valid_addr("u@.tt"), false); + assert_eq!(may_be_valid_addr("@d.tt"), false); + } + + #[test] + fn test_normalize_name() { + assert_eq!(&normalize_name("Doe, John"), "John Doe"); + assert_eq!(&normalize_name(" hello world "), "hello world"); + } + + #[test] + fn test_normalize_addr() { + assert_eq!(addr_normalize("mailto:john@doe.com"), "john@doe.com"); + assert_eq!(addr_normalize(" hello@world.com "), "hello@world.com"); + } + + #[test] + fn test_get_first_name() { + assert_eq!(get_first_name("John Doe"), "John"); + } +} diff --git a/src/context.rs b/src/context.rs index 1480c8181..013f13f5d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,9 +1,9 @@ use std::sync::{Arc, Condvar, Mutex, RwLock}; use crate::constants::*; +use crate::contact::*; use crate::dc_array::*; use crate::dc_chat::*; -use crate::dc_contact::*; use crate::dc_job::*; use crate::dc_jobthread::*; use crate::dc_loginparam::*; @@ -346,7 +346,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char { let chats = dc_get_chat_cnt(context) as usize; let real_msgs = dc_get_real_msg_cnt(context) as usize; let deaddrop_msgs = dc_get_deaddrop_msg_cnt(context) as usize; - let contacts = dc_get_real_contact_cnt(context) as usize; + let contacts = Contact::get_real_cnt(context) as usize; let is_configured = context .sql .get_config_int(context, "configured") diff --git a/src/dc_chat.rs b/src/dc_chat.rs index ec38aeb80..5497ad927 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -2,9 +2,9 @@ use std::ffi::CString; use crate::chatlist::*; use crate::constants::*; +use crate::contact::*; use crate::context::Context; use crate::dc_array::*; -use crate::dc_contact::*; use crate::dc_job::*; use crate::dc_msg::*; use crate::dc_tools::*; @@ -52,7 +52,7 @@ pub unsafe fn dc_create_chat_by_msg_id(context: &Context, msg_id: uint32_t) -> u dc_unblock_chat(context, (*chat).id); send_event = 1i32 } - dc_scaleup_contact_origin(context, (*msg).from_id, 0x800i32); + Contact::scaleup_origin_by_id(context, (*msg).from_id, Origin::CreateChat); } dc_msg_unref(msg); @@ -206,7 +206,9 @@ pub unsafe fn dc_create_chat_by_contact_id(context: &Context, contact_id: uint32 dc_unblock_chat(context, chat_id); send_event = 1i32 } - } else if !dc_real_contact_exists(context, contact_id) && contact_id != 1i32 as libc::c_uint { + } else if !Contact::real_exists_by_id(context, contact_id) + && contact_id != DC_CONTACT_ID_SELF as u32 + { warn!( context, 0, "Cannot create chat, contact {} does not exist.", contact_id as libc::c_int, @@ -222,7 +224,7 @@ pub unsafe fn dc_create_chat_by_contact_id(context: &Context, contact_id: uint32 if 0 != chat_id { send_event = 1; } - dc_scaleup_contact_origin(context, contact_id, 0x800i32); + Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat); } if 0 != send_event { context.call_cb(Event::MSGS_CHANGED, 0i32 as uintptr_t, 0i32 as uintptr_t); @@ -239,8 +241,6 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id( ) { let mut chat_id = 0; let mut chat_blocked = 0; - let contact: *mut dc_contact_t; - let chat_name: *mut libc::c_char; if !ret_chat_id.is_null() { *ret_chat_id = 0; @@ -264,14 +264,8 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id( } return; } - contact = dc_contact_new(context); - if dc_contact_load_from_db(contact, &context.sql, contact_id) { - chat_name = - if !(*contact).name.is_null() && 0 != *(*contact).name.offset(0isize) as libc::c_int { - (*contact).name - } else { - (*contact).addr - }; + if let Ok(contact) = Contact::load_from_db(context, contact_id) { + let chat_name = contact.get_display_name(); if sql::execute( context, @@ -279,10 +273,10 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id( format!( "INSERT INTO chats (type, name, param, blocked, grpid) VALUES({}, '{}', '{}', {}, '{}')", 100, - as_str(chat_name), - if contact_id == 1 { "K=1" } else { "" }, + chat_name, + if contact_id == DC_CONTACT_ID_SELF as u32 { "K=1" } else { "" }, create_blocked, - as_str((*contact).addr), + contact.get_addr(), ), params![], ).is_ok() { @@ -291,7 +285,7 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id( &context.sql, "chats", "grpid", - as_str((*contact).addr), + contact.get_addr(), ); sql::execute( @@ -303,7 +297,6 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id( } } - dc_contact_unref(contact); if !ret_chat_id.is_null() { *ret_chat_id = chat_id } @@ -1542,15 +1535,18 @@ pub unsafe fn dc_add_contact_to_chat_ex( ) -> libc::c_int { let mut OK_TO_CONTINUE = true; let mut success: libc::c_int = 0; - let contact: *mut dc_contact_t = dc_get_contact(context, contact_id); + let contact = Contact::get_by_id(context, contact_id); let chat: *mut Chat = dc_chat_new(context); let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context); - if !(contact.is_null() || chat_id <= 9 as libc::c_uint) { + if !(contact.is_err() || chat_id <= 9 as libc::c_uint) { dc_reset_gossiped_timestamp(context, chat_id); + let contact = contact.unwrap(); + /*this also makes sure, not contacts are added to special or normal chats*/ if !(0 == real_group_exists(context, chat_id) - || !dc_real_contact_exists(context, contact_id) && contact_id != 1 as libc::c_uint + || !Contact::real_exists_by_id(context, contact_id) + && contact_id != DC_CONTACT_ID_SELF as u32 || !dc_chat_load_from_db(chat, chat_id)) { if !(dc_is_contact_in_chat(context, chat_id, 1 as uint32_t) == 1) { @@ -1572,7 +1568,7 @@ pub unsafe fn dc_add_contact_to_chat_ex( .sql .get_config(context, "configured_addr") .unwrap_or_default(); - if as_str((*contact).addr) != &self_addr { + if contact.get_addr() != &self_addr { // ourself is added using DC_CONTACT_ID_SELF, do not add it explicitly. // if SELF is not in the group, members cannot be added at all. @@ -1584,7 +1580,7 @@ pub unsafe fn dc_add_contact_to_chat_ex( } else { // else continue and send status mail if (*chat).type_0 == 130 { - if dc_contact_is_verified(contact) != 2 { + if contact.is_verified() != VerifiedStatus::BidirectVerified { error!( context, 0, "Only bidirectional verified contacts can be added to verified groups." @@ -1603,14 +1599,12 @@ pub unsafe fn dc_add_contact_to_chat_ex( (*msg).type_0 = Viewtype::Text; (*msg).text = Some(context.stock_system_msg( StockMessage::MsgAddMember, - as_str((*contact).addr), + contact.get_addr(), "", DC_CONTACT_ID_SELF as uint32_t, )); (*msg).param.set_int(Param::Cmd, 4); - if !(*contact).addr.is_null() { - (*msg).param.set(Param::Arg, as_str((*contact).addr)); - } + (*msg).param.set(Param::Arg, contact.get_addr()); (*msg).param.set_int(Param::Arg2, flags); (*msg).id = dc_send_msg(context, chat_id, msg); context.call_cb( @@ -1627,7 +1621,6 @@ pub unsafe fn dc_add_contact_to_chat_ex( } } dc_chat_unref(chat); - dc_contact_unref(contact); dc_msg_unref(msg); success @@ -1689,13 +1682,12 @@ pub unsafe fn dc_remove_contact_from_chat( chat_id: u32, contact_id: u32, ) -> libc::c_int { - let mut success: libc::c_int = 0; - let contact: *mut dc_contact_t = dc_get_contact(context, contact_id); + let mut success = 0; let chat: *mut Chat = dc_chat_new(context); let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context); if !(chat_id <= 9 as libc::c_uint - || contact_id <= 9 as libc::c_uint && contact_id != 1 as libc::c_uint) + || contact_id <= 9 as libc::c_uint && contact_id != DC_CONTACT_ID_SELF as u32) { /* we do not check if "contact_id" exists but just delete all records with the id from chats_contacts */ /* this allows to delete pending references to deleted contacts. Of course, this should _not_ happen. */ @@ -1709,10 +1701,10 @@ pub unsafe fn dc_remove_contact_from_chat( ); } else { /* we should respect this - whatever we send to the group, it gets discarded anyway! */ - if !contact.is_null() { + if let Ok(contact) = Contact::get_by_id(context, contact_id) { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { (*msg).type_0 = Viewtype::Text; - if (*contact).id == 1 as libc::c_uint { + if contact.id == DC_CONTACT_ID_SELF as u32 { dc_set_group_explicitly_left(context, (*chat).grpid); (*msg).text = Some(context.stock_system_msg( StockMessage::MsgGroupLeft, @@ -1723,15 +1715,13 @@ pub unsafe fn dc_remove_contact_from_chat( } else { (*msg).text = Some(context.stock_system_msg( StockMessage::MsgDelMember, - as_str((*contact).addr), + contact.get_addr(), "", DC_CONTACT_ID_SELF as u32, )); } (*msg).param.set_int(Param::Cmd, 5); - if !(*contact).addr.is_null() { - (*msg).param.set(Param::Arg, as_str((*contact).addr)); - } + (*msg).param.set(Param::Arg, contact.get_addr()); (*msg).id = dc_send_msg(context, chat_id, msg); context.call_cb( Event::MSGS_CHANGED, @@ -1756,7 +1746,6 @@ pub unsafe fn dc_remove_contact_from_chat( } dc_chat_unref(chat); - dc_contact_unref(contact); dc_msg_unref(msg); success @@ -1947,7 +1936,6 @@ pub unsafe fn dc_forward_msgs( let msg = dc_msg_new_untyped(context); let chat = dc_chat_new(context); - let contact = dc_contact_new(context); let mut created_db_entries = Vec::new(); let mut curr_timestamp: i64; @@ -1981,7 +1969,7 @@ pub unsafe fn dc_forward_msgs( break; } let original_param = (*msg).param.clone(); - if (*msg).from_id != 1 { + if (*msg).from_id != DC_CONTACT_ID_SELF as u32 { (*msg).param.set_int(Param::Forwarded, 1); } (*msg).param.remove(Param::GuranteeE2ee); @@ -2027,7 +2015,6 @@ pub unsafe fn dc_forward_msgs( created_db_entries[i + 1] as uintptr_t, ); } - dc_contact_unref(contact); dc_msg_unref(msg); dc_chat_unref(chat); } @@ -2113,7 +2100,7 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char let mut image_rel: *mut libc::c_char = 0 as *mut libc::c_char; let mut image_abs: *mut libc::c_char = 0 as *mut libc::c_char; let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t; - let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t; + if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) { image_rel = (*chat) .param @@ -2125,15 +2112,17 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char } else if (*chat).type_0 == 100i32 { contacts = dc_get_chat_contacts((*chat).context, (*chat).id); if !(*contacts).is_empty() { - contact = dc_get_contact((*chat).context, (*contacts).get_id(0)); - image_abs = dc_contact_get_profile_image(contact) + if let Ok(contact) = Contact::get_by_id((*chat).context, (*contacts).get_id(0)) { + if let Some(img) = contact.get_profile_image() { + image_abs = img.strdup(); + } + } } } } free(image_rel as *mut libc::c_void); dc_array_unref(contacts); - dc_contact_unref(contact); image_abs } @@ -2141,13 +2130,14 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t { let mut color: uint32_t = 0i32 as uint32_t; let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t; - let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t; + if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) { if (*chat).type_0 == 100i32 { contacts = dc_get_chat_contacts((*chat).context, (*chat).id); if !(*contacts).is_empty() { - contact = dc_get_contact((*chat).context, (*contacts).get_id(0)); - color = dc_str_to_color((*contact).addr) as uint32_t + if let Ok(contact) = Contact::get_by_id((*chat).context, (*contacts).get_id(0)) { + color = contact.get_color(); + } } } else { color = dc_str_to_color((*chat).name) as uint32_t @@ -2155,7 +2145,6 @@ pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t { } dc_array_unref(contacts); - dc_contact_unref(contact); color } diff --git a/src/dc_contact.rs b/src/dc_contact.rs deleted file mode 100644 index 8e58af568..000000000 --- a/src/dc_contact.rs +++ /dev/null @@ -1,1137 +0,0 @@ -use std::ffi::CString; - -use crate::aheader::EncryptPreference; -use crate::config; -use crate::constants::*; -use crate::context::Context; -use crate::dc_array::*; -use crate::dc_e2ee::*; -use crate::dc_loginparam::*; -use crate::dc_tools::*; -use crate::key::*; -use crate::peerstate::*; -use crate::sql::{self, Sql}; -use crate::stock::StockMessage; -use crate::types::*; -use crate::x::*; - -const DC_GCL_VERIFIED_ONLY: u32 = 0x01; - -#[derive(Copy, Clone)] -#[repr(C)] -pub struct dc_contact_t<'a> { - pub magic: uint32_t, - pub context: &'a Context, - pub id: uint32_t, - pub name: *mut libc::c_char, - pub authname: *mut libc::c_char, - pub addr: *mut libc::c_char, - pub blocked: libc::c_int, - pub origin: libc::c_int, -} - -pub fn dc_marknoticed_contact(context: &Context, contact_id: u32) { - if sql::execute( - context, - &context.sql, - "UPDATE msgs SET state=? WHERE from_id=? AND state=?;", - params![DC_STATE_IN_NOTICED, contact_id as i32, DC_STATE_IN_FRESH], - ) - .is_ok() - { - context.call_cb(Event::MSGS_CHANGED, 0, 0); - } -} - -/// Returns false if addr is an invalid address, otherwise true. -pub unsafe fn dc_may_be_valid_addr(addr: *const libc::c_char) -> bool { - if addr.is_null() { - return false; - } - let at: *const libc::c_char = strchr(addr, '@' as i32); - if at.is_null() || at.wrapping_offset_from(addr) < 1 { - return false; - } - let dot: *const libc::c_char = strchr(at, '.' as i32); - if dot.is_null() - || dot.wrapping_offset_from(at) < 2 - || *dot.offset(1isize) as libc::c_int == 0i32 - || *dot.offset(2isize) as libc::c_int == 0i32 - { - return false; - } - - true -} - -pub unsafe fn dc_lookup_contact_id_by_addr( - context: &Context, - addr: *const libc::c_char, -) -> uint32_t { - if addr.is_null() || *addr.offset(0) as libc::c_int == 0 { - return 0; - } - - let addr_normalized_c = dc_addr_normalize(addr); - let addr_normalized = as_str(addr_normalized_c); - let addr_self = context - .sql - .get_config(context, "configured_addr") - .unwrap_or_default(); - - let contact_id = if addr_normalized == addr_self { - 1 - } else { - context.sql.query_row_col( - context, - "SELECT id FROM contacts WHERE addr=?1 COLLATE NOCASE AND id>?2 AND origin>=?3 AND blocked=0;", - params![addr_normalized, 9, 0x100], - 0 - ).unwrap_or_default() - }; - free(addr_normalized_c as *mut libc::c_void); - - contact_id -} - -pub unsafe fn dc_addr_normalize(addr: *const libc::c_char) -> *mut libc::c_char { - let mut addr_normalized: *mut libc::c_char = dc_strdup(addr); - dc_trim(addr_normalized); - if strncmp( - addr_normalized, - b"mailto:\x00" as *const u8 as *const libc::c_char, - 7, - ) == 0i32 - { - let old: *mut libc::c_char = addr_normalized; - addr_normalized = dc_strdup(&mut *old.offset(7isize)); - free(old as *mut libc::c_void); - dc_trim(addr_normalized); - } - - addr_normalized -} - -pub fn dc_addr_normalize_safe(addr: &str) -> &str { - let norm = addr.trim(); - - if norm.starts_with("mailto:") { - return &norm[7..]; - } - - norm -} - -pub unsafe fn dc_create_contact( - context: &Context, - name: *const libc::c_char, - addr: *const libc::c_char, -) -> uint32_t { - let mut contact_id: uint32_t = 0i32 as uint32_t; - let mut sth_modified: libc::c_int = 0i32; - let blocked: bool; - if !(addr.is_null() || *addr.offset(0isize) as libc::c_int == 0i32) { - contact_id = dc_add_or_lookup_contact(context, name, addr, 0x4000000i32, &mut sth_modified); - blocked = dc_is_contact_blocked(context, contact_id); - context.call_cb( - Event::CONTACTS_CHANGED, - (if sth_modified == 2i32 { - contact_id - } else { - 0i32 as libc::c_uint - }) as uintptr_t, - 0i32 as uintptr_t, - ); - if blocked { - dc_block_contact(context, contact_id, 0i32); - } - } - - contact_id -} - -pub unsafe fn dc_block_contact(context: &Context, contact_id: uint32_t, new_blocking: libc::c_int) { - if contact_id <= 9 { - return; - } - - let contact = dc_contact_new(context); - - if dc_contact_load_from_db(contact, &context.sql, contact_id) - && (*contact).blocked != new_blocking - { - if sql::execute( - context, - &context.sql, - "UPDATE contacts SET blocked=? WHERE id=?;", - params![new_blocking, contact_id as i32], - ) - .is_ok() - { - // also (un)block all chats with _only_ this contact - we do not delete them to allow a - // non-destructive blocking->unblocking. - // (Maybe, beside normal chats (type=100) we should also block group chats with only this user. - // However, I'm not sure about this point; it may be confusing if the user wants to add other people; - // this would result in recreating the same group...) - if sql::execute( - context, - &context.sql, - "UPDATE chats SET blocked=? WHERE type=? AND id IN (SELECT chat_id FROM chats_contacts WHERE contact_id=?);", - params![new_blocking, 100, contact_id as i32], - ).is_ok() { - dc_marknoticed_contact(context, contact_id); - context.call_cb( - Event::CONTACTS_CHANGED, - 0, - 0, - ); - } - } - } - - dc_contact_unref(contact); -} - -/** - * @class dc_contact_t - * - * An object representing a single contact in memory. - * The contact object is not updated. - * If you want an update, you have to recreate the object. - * - * The library makes sure - * only to use names _authorized_ by the contact in `To:` or `Cc:`. - * _Given-names _as "Daddy" or "Honey" are not used there. - * 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 - * (eg. dc_contact_get_name(), dc_contact_get_display_name(), - * dc_contact_get_name_n_addr(), dc_contact_get_first_name(), - * dc_create_contact() or dc_add_address_book()) - * only affect the given-name. - */ -pub unsafe fn dc_contact_new<'a>(context: &'a Context) -> *mut dc_contact_t<'a> { - let mut contact: *mut dc_contact_t; - contact = calloc(1, ::std::mem::size_of::()) as *mut dc_contact_t; - assert!(!contact.is_null()); - - (*contact).magic = 0xc047ac7i32 as uint32_t; - (*contact).context = context; - - contact -} - -pub unsafe fn dc_contact_unref(contact: *mut dc_contact_t) { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return; - } - dc_contact_empty(contact); - (*contact).magic = 0i32 as uint32_t; - free(contact as *mut libc::c_void); -} - -pub unsafe fn dc_contact_empty(mut contact: *mut dc_contact_t) { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return; - } - (*contact).id = 0i32 as uint32_t; - free((*contact).name as *mut libc::c_void); - (*contact).name = 0 as *mut libc::c_char; - free((*contact).authname as *mut libc::c_void); - (*contact).authname = 0 as *mut libc::c_char; - free((*contact).addr as *mut libc::c_void); - (*contact).addr = 0 as *mut libc::c_char; - (*contact).origin = 0i32; - (*contact).blocked = 0i32; -} - -/* From: of incoming messages of unknown sender */ -/* Cc: of incoming messages of unknown sender */ -/* To: of incoming messages of unknown sender */ -/* address scanned but not verified */ -/* Reply-To: of incoming message of known sender */ -/* Cc: of incoming message of known sender */ -/* additional To:'s of incoming message of known sender */ -/* a chat was manually created for this user, but no message yet sent */ -/* message sent by us */ -/* message sent by us */ -/* message sent by us */ -/* internal use */ -/* address is in our address book */ -/* set on Alice's side for contacts like Bob that have scanned the QR code offered by her. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling dc_contact_is_verified() ! */ -/* set on Bob's side for contacts scanned and verified from a QR code. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling dc_contact_is_verified() ! */ -/* contact added manually by dc_create_contact(), this should be the largets origin as otherwise the user cannot modify the names */ -/* contacts with at least this origin value are shown in the contact list */ -/* contacts with at least this origin value are verified and known not to be spam */ -/* contacts with at least this origin value start a new "normal" chat, defaults to off */ -pub unsafe fn dc_contact_load_from_db( - contact: *mut dc_contact_t, - sql: &Sql, - contact_id: u32, -) -> bool { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return false; - } - - dc_contact_empty(contact); - - if contact_id == 1 as libc::c_uint { - (*contact).id = contact_id; - (*contact).name = (*contact).context.stock_str(StockMessage::SelfMsg).strdup(); - (*contact).addr = (*contact) - .context - .sql - .get_config((*contact).context, "configured_addr") - .unwrap_or_default() - .strdup(); - true - } else { - sql.query_row( - "SELECT c.name, c.addr, c.origin, c.blocked, c.authname FROM contacts c WHERE c.id=?;", - params![contact_id as i32], - |row| { - (*contact).id = contact_id; - (*contact).name = row.get::<_, String>(0)?.strdup(); - (*contact).addr = row.get::<_, String>(1)?.strdup(); - (*contact).origin = row.get(2)?; - (*contact).blocked = row.get::<_, Option>(3)?.unwrap_or_default(); - (*contact).authname = row.get::<_, String>(4)?.strdup(); - Ok(()) - } - ).is_ok() - } -} - -pub unsafe fn dc_is_contact_blocked(context: &Context, contact_id: uint32_t) -> bool { - let mut is_blocked = false; - let contact: *mut dc_contact_t = dc_contact_new(context); - if dc_contact_load_from_db(contact, &context.sql, contact_id) { - if 0 != (*contact).blocked { - is_blocked = true - } - } - dc_contact_unref(contact); - - is_blocked -} - -/*can be NULL*/ -pub fn dc_add_or_lookup_contact( - context: &Context, - name: *const libc::c_char, - addr__: *const libc::c_char, - origin: libc::c_int, - mut sth_modified: *mut libc::c_int, -) -> uint32_t { - let mut dummy = 0; - - if sth_modified.is_null() { - sth_modified = &mut dummy; - } - unsafe { *sth_modified = 0 }; - - if addr__.is_null() || origin <= 0 { - return 0; - } - - let addr_c = unsafe { dc_addr_normalize(addr__) }; - let addr = as_str(addr_c); - let addr_self = context - .sql - .get_config(context, "configured_addr") - .unwrap_or_default(); - - if addr == addr_self { - return 1; - } - - if !unsafe { dc_may_be_valid_addr(addr_c) } { - warn!( - context, - 0, - "Bad address \"{}\" for contact \"{}\".", - addr, - if !name.is_null() { - as_str(name) - } else { - "" - }, - ); - return 0; - } - - let mut update_addr = false; - let mut update_name = false; - let mut update_authname = false; - let mut row_id = 0; - - if let Ok((id, row_name, row_addr, row_origin, row_authname)) = context.sql.query_row( - "SELECT id, name, addr, origin, authname FROM contacts WHERE addr=? COLLATE NOCASE;", - params![addr], - |row| { - let row_id = row.get(0)?; - let row_name: String = row.get(1)?; - let row_addr: String = row.get(2)?; - let row_origin = row.get(3)?; - let row_authname: String = row.get(4)?; - - if !name.is_null() && 0 != unsafe { *name.offset(0) as libc::c_int } { - if !row_name.is_empty() { - if origin >= row_origin && as_str(name) != row_name { - update_name = true; - } - } - } else { - update_name = true; - } - if origin == 0x10 && !name.is_null() && as_str(name) != row_authname { - update_authname = true; - } - Ok((row_id, row_name, row_addr, row_origin, row_authname)) - }, - ) { - row_id = id; - if origin >= row_origin && addr != row_addr { - update_addr = true; - } - if update_name || update_authname || update_addr || origin > row_origin { - sql::execute( - context, - &context.sql, - "UPDATE contacts SET name=?, addr=?, origin=?, authname=? WHERE id=?;", - params![ - if update_name { - to_string(name) - } else { - row_name - }, - if update_addr { addr } else { &row_addr }, - if origin > row_origin { - origin - } else { - row_origin - }, - if update_authname { - to_string(name) - } else { - row_authname - }, - row_id - ], - ) - .ok(); - - if update_name { - sql::execute( - context, - &context.sql, - "UPDATE chats SET name=? WHERE type=? AND id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?);", - params![to_string(name), 100, row_id] - ).ok(); - } - unsafe { *sth_modified = 1 }; - } - } else { - if sql::execute( - context, - &context.sql, - "INSERT INTO contacts (name, addr, origin) VALUES(?, ?, ?);", - params![to_string(name), addr, origin,], - ) - .is_ok() - { - row_id = sql::get_rowid(context, &context.sql, "contacts", "addr", addr); - unsafe { *sth_modified = 2 }; - } else { - error!(context, 0, "Cannot add contact."); - } - } - - unsafe { free(addr_c as *mut libc::c_void) }; - - row_id -} - -#[allow(non_snake_case)] -pub unsafe fn dc_add_address_book(context: &Context, adr_book: *const libc::c_char) -> libc::c_int { - let mut sth_modified: libc::c_int = 0i32; - let mut modify_cnt: libc::c_int = 0i32; - if !(adr_book.is_null()) { - let lines = dc_split_into_lines(adr_book); - - for chunk in lines.chunks(2) { - let name: *mut libc::c_char = chunk[0]; - let addr: *mut libc::c_char = chunk[1]; - dc_normalize_name(name); - dc_add_or_lookup_contact(context, name, addr, 0x80000i32, &mut sth_modified); - if 0 != sth_modified { - modify_cnt += 1 - } - } - if 0 != modify_cnt { - context.call_cb( - Event::CONTACTS_CHANGED, - 0i32 as uintptr_t, - 0i32 as uintptr_t, - ); - } - dc_free_splitted_lines(lines); - } - - modify_cnt -} - -// Working with names -pub unsafe fn dc_normalize_name(full_name: *mut libc::c_char) { - if full_name.is_null() { - return; - } - dc_trim(full_name); - let len: libc::c_int = strlen(full_name) as libc::c_int; - if len > 0i32 { - let firstchar: libc::c_char = *full_name.offset(0isize); - let lastchar: libc::c_char = *full_name.offset((len - 1i32) as isize); - if firstchar as libc::c_int == '\'' as i32 && lastchar as libc::c_int == '\'' as i32 - || firstchar as libc::c_int == '\"' as i32 && lastchar as libc::c_int == '\"' as i32 - || firstchar as libc::c_int == '<' as i32 && lastchar as libc::c_int == '>' as i32 - { - *full_name.offset(0isize) = ' ' as i32 as libc::c_char; - *full_name.offset((len - 1i32) as isize) = ' ' as i32 as libc::c_char - } - } - let p1: *mut libc::c_char = strchr(full_name, ',' as i32); - if !p1.is_null() { - *p1 = 0i32 as libc::c_char; - let last_name: *mut libc::c_char = dc_strdup(full_name); - let first_name: *mut libc::c_char = dc_strdup(p1.offset(1isize)); - dc_trim(last_name); - dc_trim(first_name); - strcpy(full_name, first_name); - strcat(full_name, b" \x00" as *const u8 as *const libc::c_char); - strcat(full_name, last_name); - free(last_name as *mut libc::c_void); - free(first_name as *mut libc::c_void); - } else { - dc_trim(full_name); - }; -} - -#[allow(non_snake_case)] -pub fn dc_get_contacts( - context: &Context, - listflags: u32, - query: *const libc::c_char, -) -> *mut dc_array_t { - let self_addr = context - .sql - .get_config(context, "configured_addr") - .unwrap_or_default(); - - let mut add_self = false; - let mut ret = dc_array_t::new(100); - - if (listflags & DC_GCL_VERIFIED_ONLY) > 0 || !query.is_null() { - let s3strLikeCmd = format!("%{}%", if !query.is_null() { as_str(query) } else { "" }); - eprintln!("query '{}'", &s3strLikeCmd); - context - .sql - .query_map( - "SELECT c.id FROM contacts c \ - LEFT JOIN acpeerstates ps ON c.addr=ps.addr \ - WHERE c.addr!=?1 \ - AND c.id>?2 \ - AND c.origin>=?3 \ - AND c.blocked=0 \ - AND (c.name LIKE ?4 OR c.addr LIKE ?5) \ - AND (1=?6 OR LENGTH(ps.verified_key_fingerprint)!=0) \ - ORDER BY LOWER(c.name||c.addr),c.id;", - params![ - self_addr, - 9, - 0x100, - &s3strLikeCmd, - &s3strLikeCmd, - if 0 != listflags & 0x1 { 0 } else { 1 }, - ], - |row| row.get::<_, i32>(0), - |ids| { - for id in ids { - ret.add_id(id? as u32); - } - Ok(()) - }, - ) - .unwrap(); // TODO: Better error handling - - let self_name = context - .sql - .get_config(context, "displayname") - .unwrap_or_default(); - - let self_name2 = CString::new(context.stock_str(StockMessage::SelfMsg).as_ref()).unwrap(); - - if query.is_null() - || self_addr.contains(as_str(query)) - || self_name.contains(as_str(query)) - || 0 != unsafe { dc_str_contains(self_name2.as_ptr(), query) } - { - add_self = true; - } - } else { - add_self = true; - - context.sql.query_map( - "SELECT id FROM contacts WHERE addr!=?1 AND id>?2 AND origin>=?3 AND blocked=0 ORDER BY LOWER(name||addr),id;", - params![self_addr, 9, 0x100], - |row| row.get::<_, i32>(0), - |ids| { - for id in ids { - ret.add_id(id? as u32); - } - Ok(()) - } - ).unwrap(); // TODO: better error handling - } - - if 0 != listflags & 0x2 && add_self { - ret.add_id(1); - } - - ret.into_raw() -} - -pub fn dc_get_blocked_cnt(context: &Context) -> libc::c_int { - context - .sql - .query_row_col( - context, - "SELECT COUNT(*) FROM contacts WHERE id>? AND blocked!=0", - params![9], - 0, - ) - .unwrap_or_default() -} - -pub fn dc_get_blocked_contacts(context: &Context) -> *mut dc_array_t { - context - .sql - .query_map( - "SELECT id FROM contacts WHERE id>? AND blocked!=0 ORDER BY LOWER(name||addr),id;", - params![9], - |row| row.get::<_, i32>(0), - |ids| { - let mut ret = dc_array_t::new(100); - - for id in ids { - ret.add_id(id? as u32); - } - - Ok(ret.into_raw()) - }, - ) - .unwrap_or_else(|_| std::ptr::null_mut()) -} - -pub unsafe fn dc_get_contact_encrinfo( - context: &Context, - contact_id: uint32_t, -) -> *mut libc::c_char { - let mut ret = String::new(); - let contact = dc_contact_new(context); - - let mut fingerprint_self = 0 as *mut libc::c_char; - let mut fingerprint_other_verified = 0 as *mut libc::c_char; - let mut fingerprint_other_unverified = 0 as *mut libc::c_char; - - if !(!dc_contact_load_from_db(contact, &context.sql, contact_id)) { - let peerstate = Peerstate::from_addr(context, &context.sql, as_str((*contact).addr)); - let loginparam = dc_loginparam_read(context, &context.sql, "configured_"); - - let mut self_key = Key::from_self_public(context, &loginparam.addr, &context.sql); - - if peerstate.is_some() && peerstate.as_ref().and_then(|p| p.peek_key(0)).is_some() { - let peerstate = peerstate.as_ref().unwrap(); - let p = context.stock_str(if peerstate.prefer_encrypt == EncryptPreference::Mutual { - StockMessage::E2ePreferred - } else { - StockMessage::E2eAvailable - }); - ret += &p; - if self_key.is_none() { - dc_ensure_secret_key_exists(context); - self_key = Key::from_self_public(context, &loginparam.addr, &context.sql); - } - let p = context.stock_str(StockMessage::FingerPrints); - ret += &format!(" {}:", p); - - fingerprint_self = self_key - .map(|k| k.formatted_fingerprint_c()) - .unwrap_or(std::ptr::null_mut()); - fingerprint_other_verified = peerstate - .peek_key(2) - .map(|k| k.formatted_fingerprint_c()) - .unwrap_or(std::ptr::null_mut()); - fingerprint_other_unverified = peerstate - .peek_key(0) - .map(|k| k.formatted_fingerprint_c()) - .unwrap_or(std::ptr::null_mut()); - if peerstate.addr.is_some() && &loginparam.addr < peerstate.addr.as_ref().unwrap() { - cat_fingerprint( - &mut ret, - &loginparam.addr, - fingerprint_self, - 0 as *const libc::c_char, - ); - cat_fingerprint( - &mut ret, - peerstate.addr.as_ref().unwrap(), - fingerprint_other_verified, - fingerprint_other_unverified, - ); - } else { - cat_fingerprint( - &mut ret, - peerstate.addr.as_ref().unwrap(), - fingerprint_other_verified, - fingerprint_other_unverified, - ); - cat_fingerprint( - &mut ret, - &loginparam.addr, - fingerprint_self, - 0 as *const libc::c_char, - ); - } - } else if 0 == loginparam.server_flags & 0x400 && 0 == loginparam.server_flags & 0x40000 { - ret += &context.stock_str(StockMessage::EncrTransp); - } else { - ret += &context.stock_str(StockMessage::EncrNone); - } - } - - dc_contact_unref(contact); - - free(fingerprint_self as *mut libc::c_void); - free(fingerprint_other_verified as *mut libc::c_void); - free(fingerprint_other_unverified as *mut libc::c_void); - - ret.strdup() -} - -unsafe fn cat_fingerprint( - ret: &mut String, - addr: impl AsRef, - fingerprint_verified: *const libc::c_char, - fingerprint_unverified: *const libc::c_char, -) { - *ret += &format!( - "\n\n{}:\n{}", - addr.as_ref(), - if !fingerprint_verified.is_null() - && 0 != *fingerprint_verified.offset(0isize) as libc::c_int - { - as_str(fingerprint_verified) - } else { - as_str(fingerprint_unverified) - }, - ); - if !fingerprint_verified.is_null() - && 0 != *fingerprint_verified.offset(0isize) as libc::c_int - && !fingerprint_unverified.is_null() - && 0 != *fingerprint_unverified.offset(0isize) as libc::c_int - && strcmp(fingerprint_verified, fingerprint_unverified) != 0 - { - *ret += &format!( - "\n\n{} (alternative):\n{}", - addr.as_ref(), - as_str(fingerprint_unverified) - ); - } -} - -pub fn dc_delete_contact(context: &Context, contact_id: u32) -> bool { - if contact_id <= 9 { - return false; - } - - let count_contacts: i32 = context - .sql - .query_row_col( - context, - "SELECT COUNT(*) FROM chats_contacts WHERE contact_id=?;", - params![contact_id as i32], - 0, - ) - .unwrap_or_default(); - - let count_msgs: i32 = if count_contacts > 0 { - context - .sql - .query_row_col( - context, - "SELECT COUNT(*) FROM msgs WHERE from_id=? OR to_id=?;", - params![contact_id as i32, contact_id as i32], - 0, - ) - .unwrap_or_default() - } else { - 0 - }; - - if count_msgs == 0 { - if sql::execute( - context, - &context.sql, - "DELETE FROM contacts WHERE id=?;", - params![contact_id as i32], - ) - .is_ok() - { - context.call_cb(Event::CONTACTS_CHANGED, 0, 0); - true - } else { - error!(context, 0, "delete_contact {} failed", contact_id); - false - } - } else { - info!( - context, - 0, "could not delete contact {}, there are {} messages with it", contact_id, count_msgs - ); - false - } -} - -pub unsafe fn dc_get_contact(context: &Context, contact_id: uint32_t) -> *mut dc_contact_t { - let mut ret: *mut dc_contact_t = dc_contact_new(context); - if !dc_contact_load_from_db(ret, &context.sql, contact_id) { - dc_contact_unref(ret); - ret = 0 as *mut dc_contact_t - } - ret -} - -pub unsafe fn dc_contact_get_id(contact: *const dc_contact_t) -> uint32_t { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return 0i32 as uint32_t; - } - (*contact).id -} - -pub unsafe fn dc_contact_get_addr(contact: *const dc_contact_t) -> *mut libc::c_char { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return dc_strdup(0 as *const libc::c_char); - } - dc_strdup((*contact).addr) -} - -pub unsafe fn dc_contact_get_name(contact: *const dc_contact_t) -> *mut libc::c_char { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return dc_strdup(0 as *const libc::c_char); - } - dc_strdup((*contact).name) -} - -pub unsafe fn dc_contact_get_display_name(contact: *const dc_contact_t) -> *mut libc::c_char { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return dc_strdup(0 as *const libc::c_char); - } - if !(*contact).name.is_null() && 0 != *(*contact).name.offset(0isize) as libc::c_int { - return dc_strdup((*contact).name); - } - dc_strdup((*contact).addr) -} - -pub unsafe fn dc_contact_get_name_n_addr(contact: *const dc_contact_t) -> *mut libc::c_char { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return dc_strdup(0 as *const libc::c_char); - } - if !(*contact).name.is_null() && 0 != *(*contact).name.offset(0isize) as libc::c_int { - return dc_mprintf( - b"%s (%s)\x00" as *const u8 as *const libc::c_char, - (*contact).name, - (*contact).addr, - ); - } - dc_strdup((*contact).addr) -} - -pub unsafe fn dc_contact_get_first_name(contact: *const dc_contact_t) -> *mut libc::c_char { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return dc_strdup(0 as *const libc::c_char); - } - if !(*contact).name.is_null() && 0 != *(*contact).name.offset(0isize) as libc::c_int { - return dc_get_first_name((*contact).name); - } - dc_strdup((*contact).addr) -} - -pub unsafe fn dc_get_first_name(full_name: *const libc::c_char) -> *mut libc::c_char { - let mut first_name: *mut libc::c_char = dc_strdup(full_name); - let p1: *mut libc::c_char = strchr(first_name, ' ' as i32); - if !p1.is_null() { - *p1 = 0i32 as libc::c_char; - dc_rtrim(first_name); - if *first_name.offset(0isize) as libc::c_int == 0i32 { - free(first_name as *mut libc::c_void); - first_name = dc_strdup(full_name) - } - } - first_name -} - -pub fn dc_contact_get_profile_image(contact: *const dc_contact_t) -> *mut libc::c_char { - let mut image_abs = 0 as *mut libc::c_char; - - if contact.is_null() || unsafe { (*contact).magic != 0xc047ac7 } { - return image_abs; - } - - if unsafe { (*contact).id } == 1 { - let context = unsafe { (*contact) }.context; - if let Some(avatar) = context.get_config(config::Config::Selfavatar) { - image_abs = unsafe { avatar.strdup() }; - } - } - // TODO: else get image_abs from contact param - image_abs -} - -pub unsafe fn dc_contact_get_color(contact: *const dc_contact_t) -> uint32_t { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return 0i32 as uint32_t; - } - dc_str_to_color((*contact).addr) as uint32_t -} - -pub unsafe fn dc_contact_is_blocked(contact: *const dc_contact_t) -> libc::c_int { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return 0i32; - } - (*contact).blocked -} - -/// Check if a contact was verified. E.g. by a secure-join QR code scan -/// and if the key has not changed since this verification. -/// -/// The UI may draw a checkbox or something like that beside verified contacts. -/// -/// Returns -/// - 0: contact is not verified. -/// - 2: SELF and contact have verified their fingerprints in both directions; in the UI typically checkmarks are shown. -pub unsafe fn dc_contact_is_verified(contact: *mut dc_contact_t) -> libc::c_int { - dc_contact_is_verified_ex(contact, None) -} - -/// Same as dc_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 unsafe fn dc_contact_is_verified_ex<'a>( - contact: *mut dc_contact_t<'a>, - peerstate: Option<&Peerstate<'a>>, -) -> libc::c_int { - if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { - return 0; - } - - // 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 (*contact).id == 1 as libc::c_uint { - return 2; - } - - if let Some(peerstate) = peerstate { - if peerstate.verified_key().is_some() { - 2 - } else { - 0 - } - } else { - let peerstate = Peerstate::from_addr( - (*contact).context, - &(*contact).context.sql, - as_str((*contact).addr), - ); - - let res = if let Some(ps) = peerstate { - if ps.verified_key().is_some() { - 2 - } else { - 0 - } - } else { - 0 - }; - - res - } -} - -// Working with e-mail-addresses -pub fn dc_addr_cmp(addr1: impl AsRef, addr2: impl AsRef) -> bool { - let norm1 = dc_addr_normalize_safe(addr1.as_ref()); - let norm2 = dc_addr_normalize_safe(addr2.as_ref()); - - norm1 == norm2 -} - -pub fn dc_addr_equals_self(context: &Context, addr: *const libc::c_char) -> libc::c_int { - let mut ret = 0; - - if !addr.is_null() { - let normalized_addr = unsafe { dc_addr_normalize(addr) }; - if let Some(self_addr) = context.sql.get_config(context, "configured_addr") { - ret = (as_str(normalized_addr) == self_addr) as libc::c_int; - } - unsafe { free(normalized_addr as *mut libc::c_void) }; - } - - ret -} - -pub unsafe fn dc_addr_equals_contact( - context: &Context, - addr: impl AsRef, - contact_id: u32, -) -> bool { - if addr.as_ref().is_empty() { - return false; - } - - let contact = dc_contact_new(context); - let mut addr_are_equal = false; - - if dc_contact_load_from_db(contact, &context.sql, contact_id) { - if !(*contact).addr.is_null() { - let normalized_addr = dc_addr_normalize_safe(addr.as_ref()); - if as_str((*contact).addr) == normalized_addr { - addr_are_equal = true; - } - } - dc_contact_unref(contact); - } - - addr_are_equal -} - -// Context functions to work with contacts -pub fn dc_get_real_contact_cnt(context: &Context) -> usize { - if !context.sql.is_open() { - return 0; - } - - context - .sql - .query_row_col::<_, isize>( - context, - "SELECT COUNT(*) FROM contacts WHERE id>?;", - params![9], - 0, - ) - .unwrap_or_default() as usize -} - -pub unsafe fn dc_get_contact_origin( - context: &Context, - contact_id: uint32_t, - mut ret_blocked: *mut libc::c_int, -) -> libc::c_int { - let mut ret: libc::c_int = 0i32; - let mut dummy: libc::c_int = 0i32; - if ret_blocked.is_null() { - ret_blocked = &mut dummy - } - let contact: *mut dc_contact_t = dc_contact_new(context); - *ret_blocked = 0i32; - if dc_contact_load_from_db(contact, &context.sql, contact_id) { - /* we could optimize this by loading only the needed fields */ - if 0 != (*contact).blocked { - *ret_blocked = 1i32 - } else { - ret = (*contact).origin - } - } - dc_contact_unref(contact); - ret -} - -pub fn dc_real_contact_exists(context: &Context, contact_id: u32) -> bool { - if !context.sql.is_open() || contact_id <= 9 { - return false; - } - - context - .sql - .exists( - "SELECT id FROM contacts WHERE id=?;", - params![contact_id as i32], - ) - .unwrap_or_default() -} - -pub fn dc_scaleup_contact_origin(context: &Context, contact_id: u32, origin: libc::c_int) -> bool { - context - .sql - .execute( - "UPDATE contacts SET origin=? WHERE id=? AND origin, context: &Context, ) { if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint || msg.is_null() { @@ -150,16 +150,24 @@ pub unsafe fn dc_lot_fill( (*lot).text1 = 0 as *mut libc::c_char; (*lot).text1_meaning = 0i32 } else if (*chat).type_0 == 120i32 || (*chat).type_0 == 130i32 { - if 0 != dc_msg_is_info(msg) || contact.is_null() { + if 0 != dc_msg_is_info(msg) || contact.is_none() { (*lot).text1 = 0 as *mut libc::c_char; (*lot).text1_meaning = 0i32 } else { if !chat.is_null() && (*chat).id == 1i32 as libc::c_uint { - (*lot).text1 = dc_contact_get_display_name(contact) + if let Some(contact) = contact { + (*lot).text1 = contact.get_display_name().strdup(); + } else { + (*lot).text1 = std::ptr::null_mut(); + } } else { - (*lot).text1 = dc_contact_get_first_name(contact) + if let Some(contact) = contact { + (*lot).text1 = contact.get_first_name().strdup(); + } else { + (*lot).text1 = std::ptr::null_mut(); + } } - (*lot).text1_meaning = 2i32 + (*lot).text1_meaning = 2i32; } } diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 5d0d9d3ad..a42d7ae70 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -12,9 +12,9 @@ use mmime::other::*; use std::ptr; use crate::constants::*; +use crate::contact::*; use crate::context::Context; use crate::dc_chat::*; -use crate::dc_contact::*; use crate::dc_e2ee::*; use crate::dc_location::*; use crate::dc_msg::*; @@ -294,7 +294,6 @@ pub unsafe fn dc_mimefactory_load_mdn( } let mut success = 0; - let mut contact = 0 as *mut dc_contact_t; (*factory).recipients_names = clist_new(); (*factory).recipients_addr = clist_new(); @@ -306,24 +305,19 @@ pub unsafe fn dc_mimefactory_load_mdn( .unwrap_or_else(|| 1) { // MDNs not enabled - check this is late, in the job. the use may have changed its choice while offline ... - contact = dc_contact_new((*factory).context); - if !(!dc_msg_load_from_db((*factory).msg, (*factory).context, msg_id) - || !dc_contact_load_from_db( - contact, - &(*factory).context.sql, - (*(*factory).msg).from_id, - )) - { - if !(0 != (*contact).blocked || (*(*factory).msg).chat_id <= 9 as libc::c_uint) { + if !dc_msg_load_from_db((*factory).msg, (*factory).context, msg_id) { + return success; + } + + if let Ok(contact) = Contact::load_from_db((*factory).context, (*(*factory).msg).from_id) { + if !(contact.is_blocked() || (*(*factory).msg).chat_id <= 9 as libc::c_uint) { // Do not send MDNs trash etc.; chats.blocked is already checked by the caller in dc_markseen_msgs() if !((*(*factory).msg).from_id <= 9 as libc::c_uint) { clist_insert_after( (*factory).recipients_names, (*(*factory).recipients_names).last, - (if !(*contact).authname.is_null() - && 0 != *(*contact).authname.offset(0isize) as libc::c_int - { - dc_strdup((*contact).authname) + (if !contact.get_authname().is_empty() { + contact.get_authname().strdup() } else { 0 as *mut libc::c_char }) as *mut libc::c_void, @@ -331,7 +325,7 @@ pub unsafe fn dc_mimefactory_load_mdn( clist_insert_after( (*factory).recipients_addr, (*(*factory).recipients_addr).last, - dc_strdup((*contact).addr) as *mut libc::c_void, + contact.get_addr().strdup() as *mut libc::c_void, ); load_from(factory); (*factory).timestamp = dc_create_smeared_timestamp((*factory).context); @@ -346,8 +340,6 @@ pub unsafe fn dc_mimefactory_load_mdn( } } - dc_contact_unref(contact); - success } diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index 89522d047..a9c9476c1 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -11,8 +11,8 @@ use mmime::mailmime_types::*; use mmime::mmapstring::*; use mmime::other::*; +use crate::contact::*; use crate::context::Context; -use crate::dc_contact::*; use crate::dc_e2ee::*; use crate::dc_location::*; use crate::dc_simplify::*; @@ -422,7 +422,7 @@ pub unsafe fn mailimf_find_first_addr(mb_list: *const mailimf_mailbox_list) -> * 0 as *mut libc::c_void }) as *mut mailimf_mailbox; if !mb.is_null() && !(*mb).mb_addr_spec.is_null() { - return dc_addr_normalize((*mb).mb_addr_spec); + return addr_normalize(as_str((*mb).mb_addr_spec)).strdup(); } cur = if !cur.is_null() { (*cur).next @@ -1565,7 +1565,7 @@ pub unsafe fn dc_mimeparser_sender_equals_recipient(mimeparser: &dc_mimeparser_t let fld: *const mailimf_field; let mut fld_from: *const mailimf_from = 0 as *const mailimf_from; let mb: *mut mailimf_mailbox; - let mut from_addr_norm: *mut libc::c_char = 0 as *mut libc::c_char; + if !(*mimeparser).header_root.is_null() { /* get From: and check there is exactly one sender */ fld = mailimf_find_field(mimeparser.header_root, MAILIMF_FIELD_FROM as libc::c_int); @@ -1584,17 +1584,16 @@ pub unsafe fn dc_mimeparser_sender_equals_recipient(mimeparser: &dc_mimeparser_t 0 as *mut libc::c_void }) as *mut mailimf_mailbox; if !mb.is_null() { - from_addr_norm = dc_addr_normalize((*mb).mb_addr_spec); + let from_addr_norm = addr_normalize(as_str((*mb).mb_addr_spec)); let recipients = mailimf_get_recipients(mimeparser.header_root); if recipients.len() == 1 { - if recipients.contains(as_str(from_addr_norm)) { + if recipients.contains(from_addr_norm) { sender_equals_recipient = 1i32; } } } } } - free(from_addr_norm as *mut libc::c_void); sender_equals_recipient } @@ -1691,15 +1690,15 @@ pub unsafe fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet< /* ****************************************************************************** * low-level-tools for getting a list of all recipients ******************************************************************************/ + #[allow(non_snake_case)] unsafe fn mailimf_get_recipients__add_addr( recipients: &mut HashSet, mb: *mut mailimf_mailbox, ) { if !mb.is_null() { - let addr_norm: *mut libc::c_char = dc_addr_normalize((*mb).mb_addr_spec); - recipients.insert(to_string(addr_norm)); - free(addr_norm as *mut libc::c_void); + let addr_norm = addr_normalize(as_str((*mb).mb_addr_spec)); + recipients.insert(addr_norm.into()); }; } diff --git a/src/dc_msg.rs b/src/dc_msg.rs index 109d5ebae..963cb6ed4 100644 --- a/src/dc_msg.rs +++ b/src/dc_msg.rs @@ -1,9 +1,9 @@ use std::ffi::CString; use crate::constants::*; +use crate::contact::*; use crate::context::*; use crate::dc_chat::*; -use crate::dc_contact::*; use crate::dc_job::*; use crate::dc_lot::dc_lot_t; use crate::dc_lot::*; @@ -48,12 +48,10 @@ pub struct dc_msg_t<'a> { // handle messages pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_char { let msg = dc_msg_new_untyped(context); - let contact_from = dc_contact_new(context); let mut p: *mut libc::c_char; let mut ret = String::new(); dc_msg_load_from_db(msg, context, msg_id); - dc_contact_load_from_db(contact_from, &context.sql, (*msg).from_id); let rawtxt: Option = context.sql.query_row_col( context, @@ -65,7 +63,6 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch if rawtxt.is_none() { ret += &format!("Cannot load message #{}.", msg_id as usize); dc_msg_unref(msg); - dc_contact_unref(contact_from); return ret.strdup(); } let rawtxt = rawtxt.unwrap(); @@ -74,12 +71,14 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch let fts = dc_timestamp_to_str(dc_msg_get_timestamp(msg)); ret += &format!("Sent: {}", fts); - p = dc_contact_get_name_n_addr(contact_from); - ret += &format!(" by {}", to_string(p)); - free(p as *mut libc::c_void); + let name = Contact::load_from_db(context, (*msg).from_id) + .map(|contact| contact.get_name_n_addr()) + .unwrap_or_default(); + + ret += &format!(" by {}", name); ret += "\n"; - if (*msg).from_id != 1 as libc::c_uint { + if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint { let s = dc_timestamp_to_str(if 0 != (*msg).timestamp_rcvd { (*msg).timestamp_rcvd } else { @@ -92,7 +91,6 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch if (*msg).from_id == 2 || (*msg).to_id == 2 { // device-internal message, no further details needed dc_msg_unref(msg); - dc_contact_unref(contact_from); return ret.strdup(); } @@ -112,14 +110,11 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch let fts = dc_timestamp_to_str(ts); ret += &format!("Read: {}", fts); - let contact = dc_contact_new(context); - dc_contact_load_from_db(contact, &context.sql, contact_id as u32); - - p = dc_contact_get_name_n_addr(contact); - ret += &format!(" by {}", as_str(p)); - free(p as *mut libc::c_void); - dc_contact_unref(contact); + let name = Contact::load_from_db(context, contact_id as u32) + .map(|contact| contact.get_name_n_addr()) + .unwrap_or_default(); + ret += &format!(" by {}", name); ret += "\n"; } Ok(()) @@ -210,7 +205,6 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch } dc_msg_unref(msg); - dc_contact_unref(contact_from); ret.strdup() } @@ -794,8 +788,8 @@ pub unsafe fn dc_msg_get_summary<'a>( ) -> *mut dc_lot_t { let current_block: u64; let ret: *mut dc_lot_t = dc_lot_new(); - let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t; let mut chat_to_delete: *mut Chat = 0 as *mut Chat; + if !(msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint) { if chat.is_null() { chat_to_delete = dc_get_chat((*msg).context, (*msg).chat_id); @@ -811,16 +805,19 @@ pub unsafe fn dc_msg_get_summary<'a>( match current_block { 15204159476013091401 => {} _ => { - if (*msg).from_id != 1 as libc::c_uint + let contact = if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint && ((*chat).type_0 == 120 || (*chat).type_0 == 130) { - contact = dc_get_contact((*chat).context, (*msg).from_id) - } - dc_lot_fill(ret, msg, chat, contact, (*msg).context); + Contact::get_by_id((*chat).context, (*msg).from_id).ok() + } else { + None + }; + + dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context); } } } - dc_contact_unref(contact); + dc_chat_unref(chat_to_delete); ret @@ -1572,12 +1569,8 @@ mod tests { let d = test::dummy_context(); let ctx = &d.ctx; - let contact = dc_create_contact( - ctx, - b"\x00".as_ptr().cast(), - b"dest@example.com\x00".as_ptr().cast(), - ); - assert!(contact != 0); + let contact = + Contact::create(ctx, "", "dest@example.com").expect("failed to create contact"); let res = ctx.set_config(Config::ConfiguredAddr, Some("self@example.com")); assert!(res.is_ok()); diff --git a/src/dc_qr.rs b/src/dc_qr.rs index b216822a4..251b3bd2a 100644 --- a/src/dc_qr.rs +++ b/src/dc_qr.rs @@ -1,8 +1,8 @@ use percent_encoding::percent_decode_str; +use crate::contact::*; use crate::context::Context; use crate::dc_chat::*; -use crate::dc_contact::*; use crate::dc_lot::*; use crate::dc_strencode::*; use crate::dc_tools::*; @@ -66,8 +66,7 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc let name_r = percent_decode_str(name_enc) .decode_utf8() .expect("invalid name"); - name = name_r.strdup(); - dc_normalize_name(name); + name = normalize_name(name_r).strdup(); } invitenumber = param .get(Param::ProfileImage) @@ -186,7 +185,7 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc b";\x00" as *const u8 as *const libc::c_char, b",\x00" as *const u8 as *const libc::c_char, ); - dc_normalize_name(name); + name = normalize_name(as_str(name)).strdup(); } } } @@ -204,10 +203,10 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc let mut temp: *mut libc::c_char = dc_urldecode(addr); free(addr as *mut libc::c_void); addr = temp; - temp = dc_addr_normalize(addr); + temp = addr_normalize(as_str(addr)).strdup(); free(addr as *mut libc::c_void); addr = temp; - if !dc_may_be_valid_addr(addr) { + if !may_be_valid_addr(as_str(addr)) { (*qr_parsed).state = 400i32; (*qr_parsed).text1 = dc_strdup( b"Bad e-mail address.\x00" as *const u8 as *const libc::c_char, @@ -248,19 +247,19 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc if addr.is_null() || invitenumber.is_null() || auth.is_null() { if let Some(peerstate) = peerstate { (*qr_parsed).state = 210i32; - let addr_ptr = if let Some(ref addr) = peerstate.addr { - addr.strdup() - } else { - std::ptr::null() - }; - (*qr_parsed).id = dc_add_or_lookup_contact( + let addr = peerstate + .addr + .as_ref() + .map(|s| s.as_str()) + .unwrap_or_else(|| ""); + (*qr_parsed).id = Contact::add_or_lookup( context, - 0 as *const libc::c_char, - addr_ptr, - 0x80i32, - 0 as *mut libc::c_int, - ); - free(addr_ptr as *mut _); + "", + addr, + Origin::UnhandledQrScan, + ) + .map(|(id, _)| id) + .unwrap_or_default(); dc_create_or_lookup_nchat_by_contact_id( context, (*qr_parsed).id, @@ -286,26 +285,28 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc } else { (*qr_parsed).state = 200i32 } - (*qr_parsed).id = dc_add_or_lookup_contact( + (*qr_parsed).id = Contact::add_or_lookup( context, - name, - addr, - 0x80i32, - 0 as *mut libc::c_int, - ); + as_str(name), + as_str(addr), + Origin::UnhandledQrScan, + ) + .map(|(id, _)| id) + .unwrap_or_default(); (*qr_parsed).fingerprint = dc_strdup(fingerprint); (*qr_parsed).invitenumber = dc_strdup(invitenumber); (*qr_parsed).auth = dc_strdup(auth) } } else if !addr.is_null() { (*qr_parsed).state = 320i32; - (*qr_parsed).id = dc_add_or_lookup_contact( + (*qr_parsed).id = Contact::add_or_lookup( context, - name, - addr, - 0x80i32, - 0 as *mut libc::c_int, + as_str(name), + as_str(addr), + Origin::UnhandledQrScan, ) + .map(|(id, _)| id) + .unwrap_or_default(); } else if strstr( qr, b"http://\x00" as *const u8 as *const libc::c_char, diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 21010d955..77e6b452c 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -8,10 +8,10 @@ use mmime::other::*; use sha2::{Digest, Sha256}; use crate::constants::*; +use crate::contact::*; use crate::context::Context; use crate::dc_array::*; use crate::dc_chat::*; -use crate::dc_contact::*; use crate::dc_job::*; use crate::dc_location::*; use crate::dc_mimeparser::*; @@ -38,7 +38,7 @@ pub unsafe fn dc_receive_imf( let mut current_block: u64; /* the function returns the number of created messages in the database */ let mut incoming: libc::c_int = 1; - let mut incoming_origin: libc::c_int = 0; + let mut incoming_origin = Origin::Unknown; let mut to_self: libc::c_int = 0; let mut from_id: uint32_t = 0 as uint32_t; let mut from_id_blocked: libc::c_int = 0; @@ -103,7 +103,7 @@ pub unsafe fn dc_receive_imf( dc_add_or_lookup_contacts_by_mailbox_list( context, (*fld_from).frm_mb_list, - 0x10, + Origin::IncomingUnknownFrom, from_list, &mut check_self, ); @@ -114,7 +114,8 @@ pub unsafe fn dc_receive_imf( } } else if dc_array_get_cnt(from_list) >= 1 { from_id = dc_array_get_id(from_list, 0 as size_t); - incoming_origin = dc_get_contact_origin(context, from_id, &mut from_id_blocked) + incoming_origin = + Contact::get_origin_by_id(context, from_id, &mut from_id_blocked) } dc_array_unref(from_list); } @@ -127,11 +128,11 @@ pub unsafe fn dc_receive_imf( context, (*fld_to).to_addr_list, if 0 == incoming { - 0x4000 - } else if incoming_origin >= 0x100 { - 0x400 + Origin::OutgoingTo + } else if incoming_origin.is_verified() { + Origin::IncomingTo } else { - 0x40 + Origin::IncomingUnknownTo }, to_ids, &mut to_self, @@ -147,11 +148,11 @@ pub unsafe fn dc_receive_imf( context, (*fld_cc).cc_addr_list, if 0 == incoming { - 0x2000 - } else if incoming_origin >= 0x100 { - 0x200 + Origin::OutgoingCc + } else if incoming_origin.is_verified() { + Origin::IncomingCc } else { - 0x20 + Origin::IncomingUnknownCc }, to_ids, 0 as *mut libc::c_int, @@ -253,7 +254,7 @@ pub unsafe fn dc_receive_imf( if chat_id == 0 as libc::c_uint { let create_blocked: libc::c_int = if 0 != test_normal_chat_id && test_normal_chat_id_blocked == 0 - || incoming_origin >= 0x7fffffff + || incoming_origin.is_start_new_chat() { 0 } else { @@ -285,7 +286,7 @@ pub unsafe fn dc_receive_imf( } if chat_id == 0 as libc::c_uint { let create_blocked_0: libc::c_int = - if incoming_origin >= 0x7fffffff || from_id == to_id { + if incoming_origin.is_start_new_chat() || from_id == to_id { 0 } else { 2 @@ -309,16 +310,20 @@ pub unsafe fn dc_receive_imf( } else if 0 != dc_is_reply_to_known_message(context, &mime_parser) { - dc_scaleup_contact_origin(context, from_id, 0x100); + 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.", ); - incoming_origin = if incoming_origin > 0x100 { + incoming_origin = if incoming_origin.is_verified() { incoming_origin } else { - 0x100 + Origin::IncomingReplyTo } } } @@ -327,8 +332,8 @@ pub unsafe fn dc_receive_imf( chat_id = 3 as uint32_t } if 0 != chat_id_blocked && state == 10 { - if incoming_origin < 0x100 && msgrmsg == 0 { - state = 13 + if !incoming_origin.is_verified() && msgrmsg == 0 { + state = 13; } } } else { @@ -353,12 +358,13 @@ pub unsafe fn dc_receive_imf( } } if chat_id == 0 as libc::c_uint && 0 != allow_creation { - let create_blocked_1: libc::c_int = - if 0 != msgrmsg && !dc_is_contact_blocked(context, to_id) { - 0 - } else { - 2 - }; + let create_blocked_1: libc::c_int = if 0 != msgrmsg + && !Contact::is_blocked_load(context, to_id) + { + 0 + } else { + 2 + }; dc_create_or_lookup_nchat_by_contact_id( context, to_id, @@ -777,28 +783,34 @@ pub unsafe fn dc_receive_imf( if !mime_parser.location_kml.is_none() && chat_id > DC_CHAT_ID_LAST_SPECIAL as libc::c_uint { - let contact = dc_get_contact(context, from_id); - if !mime_parser.location_kml.as_ref().unwrap().addr.is_null() - && !contact.is_null() - && !(*contact).addr.is_null() - && strcasecmp( - (*contact).addr, - mime_parser.location_kml.as_ref().unwrap().addr, - ) == 0 - { - let newest_location_id = dc_save_locations( - context, - chat_id, - from_id, - &mime_parser.location_kml.as_ref().unwrap().locations, - 0, - ); - if newest_location_id != 0 && hidden == 0 && !location_id_written { - dc_set_msg_location_id(context, insert_msg_id, newest_location_id); + if !mime_parser.location_kml.as_ref().unwrap().addr.is_null() { + if let Ok(contact) = Contact::get_by_id(context, from_id) { + if !contact.get_addr().is_empty() + && contact.get_addr().to_lowercase() + == as_str(mime_parser.location_kml.as_ref().unwrap().addr) + .to_lowercase() + { + let newest_location_id = dc_save_locations( + context, + chat_id, + from_id, + &mime_parser.location_kml.as_ref().unwrap().locations, + 0, + ); + if newest_location_id != 0 + && hidden == 0 + && !location_id_written + { + dc_set_msg_location_id( + context, + insert_msg_id, + newest_location_id, + ); + } + send_event = true; + } } - send_event = true; } - dc_contact_unref(contact); } if send_event { context.call_cb( @@ -1014,9 +1026,8 @@ unsafe fn create_or_lookup_group( if !optional_field.is_null() { X_MrRemoveFromGrp = (*optional_field).fld_value; mime_parser.is_system_message = 5; - let left_group: libc::c_int = - (dc_lookup_contact_id_by_addr(context, X_MrRemoveFromGrp) - == from_id as libc::c_uint) as libc::c_int; + let left_group = (Contact::lookup_id_by_addr(context, as_str(X_MrRemoveFromGrp)) + == from_id as u32) as libc::c_int; better_msg = context.stock_system_msg( if 0 != left_group { StockMessage::MsgGroupLeft @@ -1125,7 +1136,7 @@ unsafe fn create_or_lookup_group( && !grpname.is_null() && X_MrRemoveFromGrp.is_null() && (0 == group_explicitly_left - || !X_MrAddToGrp.is_null() && dc_addr_cmp(&self_addr, as_str(X_MrAddToGrp))) + || !X_MrAddToGrp.is_null() && addr_cmp(&self_addr, as_str(X_MrAddToGrp))) { /*otherwise, a pending "quit" message may pop up*/ /*re-create explicitly left groups only if ourself is re-added*/ @@ -1255,17 +1266,20 @@ unsafe fn create_or_lookup_group( params![chat_id as i32], ) .ok(); - if skip.is_null() || !dc_addr_cmp(&self_addr, as_str(skip)) { + if skip.is_null() || !addr_cmp(&self_addr, as_str(skip)) { dc_add_to_chat_contacts_table(context, chat_id, 1); } if from_id > 9 { - if !dc_addr_equals_contact(context, &self_addr, from_id as u32) - && (skip.is_null() - || !dc_addr_equals_contact( - context, - to_string(skip), - from_id as u32, - )) + if !Contact::addr_equals_contact( + context, + &self_addr, + from_id as u32, + ) && (skip.is_null() + || !Contact::addr_equals_contact( + context, + to_string(skip), + from_id as u32, + )) { dc_add_to_chat_contacts_table( context, @@ -1277,9 +1291,13 @@ unsafe fn create_or_lookup_group( i = 0; while i < to_ids_cnt { let to_id = dc_array_get_id(to_ids, i as size_t); - if !dc_addr_equals_contact(context, &self_addr, to_id) + if !Contact::addr_equals_contact(context, &self_addr, to_id) && (skip.is_null() - || !dc_addr_equals_contact(context, to_string(skip), to_id)) + || !Contact::addr_equals_contact( + context, + to_string(skip), + to_id, + )) { dc_add_to_chat_contacts_table(context, chat_id, to_id); } @@ -1604,26 +1622,21 @@ unsafe fn check_verified_properties( to_ids: *const dc_array_t, failure_reason: *mut *mut libc::c_char, ) -> libc::c_int { - let contact = dc_contact_new(context); - let verify_fail = |reason: String| { *failure_reason = format!("{}. See \"Info\" for details.", reason).strdup(); warn!(context, 0, "{}", reason); }; - let cleanup = || { - dc_contact_unref(contact); + let contact = match Contact::load_from_db(context, from_id) { + Ok(contact) => contact, + Err(_err) => { + verify_fail("Internal Error; cannot load contact".into()); + return 0; + } }; - if !dc_contact_load_from_db(contact, &context.sql, from_id) { - verify_fail("Internal Error; cannot load contact".into()); - cleanup(); - return 0; - } - if 0 == mimeparser.e2ee_helper.encrypted { verify_fail("This message is not encrypted".into()); - cleanup(); return 0; } @@ -1632,18 +1645,18 @@ unsafe fn check_verified_properties( // this check is skipped for SELF as there is no proper SELF-peerstate // and results in group-splits otherwise. if from_id != 1 { - let peerstate = Peerstate::from_addr(context, &context.sql, as_str((*contact).addr)); + let peerstate = Peerstate::from_addr(context, &context.sql, contact.get_addr()); - if peerstate.is_none() || dc_contact_is_verified_ex(contact, peerstate.as_ref()) != 2 { + if peerstate.is_none() + || contact.is_verified_ex(peerstate.as_ref()) != VerifiedStatus::BidirectVerified + { verify_fail("The sender of this message is not verified.".into()); - cleanup(); return 0; } if let Some(peerstate) = peerstate { if !peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures) { verify_fail("The message was sent with non-verified encryption.".into()); - cleanup(); return 0; } } @@ -1665,7 +1678,6 @@ unsafe fn check_verified_properties( ); if rows.is_err() { - cleanup(); return 0; } for (to_addr, mut is_verified) in rows.unwrap().into_iter() { @@ -1686,7 +1698,7 @@ unsafe fn check_verified_properties( context, 0, "{} has verfied {}.", - as_str((*contact).addr), + contact.get_addr(), to_addr, ); let fp = peerstate.gossip_key_fingerprint.clone(); @@ -1702,7 +1714,6 @@ unsafe fn check_verified_properties( "{} is not a member of this verified group", to_addr )); - cleanup(); return 0; } } @@ -1883,7 +1894,7 @@ fn is_msgrmsg_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) -> unsafe fn dc_add_or_lookup_contacts_by_address_list( context: &Context, adr_list: *const mailimf_address_list, - origin: libc::c_int, + origin: Origin, ids: *mut dc_array_t, check_self: *mut libc::c_int, ) { @@ -1933,7 +1944,7 @@ unsafe fn dc_add_or_lookup_contacts_by_address_list( unsafe fn dc_add_or_lookup_contacts_by_mailbox_list( context: &Context, mb_list: *const mailimf_mailbox_list, - origin: libc::c_int, + origin: Origin, ids: *mut dc_array_t, check_self: *mut libc::c_int, ) { @@ -1971,7 +1982,7 @@ unsafe fn add_or_lookup_contact_by_addr( context: &Context, display_name_enc: *const libc::c_char, addr_spec: *const libc::c_char, - origin: libc::c_int, + origin: Origin, ids: *mut dc_array_t, mut check_self: *mut libc::c_int, ) { @@ -1989,7 +2000,7 @@ unsafe fn add_or_lookup_contact_by_addr( .get_config(context, "configured_addr") .unwrap_or_default(); - if dc_addr_cmp(self_addr, as_str(addr_spec)) { + if addr_cmp(self_addr, as_str(addr_spec)) { *check_self = 1; } @@ -1997,20 +2008,15 @@ unsafe fn add_or_lookup_contact_by_addr( return; } /* add addr_spec if missing, update otherwise */ - let mut display_name_dec = 0 as *mut libc::c_char; + let mut display_name_dec = "".to_string(); if !display_name_enc.is_null() { - display_name_dec = dc_decode_header_words(display_name_enc); - dc_normalize_name(display_name_dec); + let tmp = as_str(dc_decode_header_words(display_name_enc)); + display_name_dec = normalize_name(&tmp); } /*can be NULL*/ - let row_id = dc_add_or_lookup_contact( - context, - display_name_dec, - addr_spec, - origin, - 0 as *mut libc::c_int, - ); - free(display_name_dec as *mut libc::c_void); + let row_id = Contact::add_or_lookup(context, display_name_dec, as_str(addr_spec), origin) + .map(|(id, _)| id) + .unwrap_or_default(); if 0 != row_id { if !dc_array_search_id(ids, row_id, 0 as *mut size_t) { dc_array_add_id(ids, row_id); diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index edcdacffa..45d970d96 100644 --- a/src/dc_securejoin.rs +++ b/src/dc_securejoin.rs @@ -5,11 +5,11 @@ use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; use crate::aheader::EncryptPreference; use crate::constants::*; +use crate::contact::*; use crate::context::Context; use crate::dc_array::*; use crate::dc_chat::*; use crate::dc_configure::*; -use crate::dc_contact::*; use crate::dc_e2ee::*; use crate::dc_lot::*; use crate::dc_mimeparser::*; @@ -315,30 +315,23 @@ unsafe fn fingerprint_equals_sender( return 0; } let mut fingerprint_equal: libc::c_int = 0i32; - let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id); - let contact: *mut dc_contact_t = dc_contact_new(context); + let contacts = dc_get_chat_contacts(context, contact_chat_id); if !(dc_array_get_cnt(contacts) != 1) { - if !dc_contact_load_from_db( - contact, - &context.sql, - dc_array_get_id(contacts, 0i32 as size_t), - ) { + if let Ok(contact) = Contact::load_from_db(context, dc_array_get_id(contacts, 0)) { + if let Some(peerstate) = Peerstate::from_addr(context, &context.sql, contact.get_addr()) + { + let fingerprint_normalized = dc_normalize_fingerprint(as_str(fingerprint)); + if peerstate.public_key_fingerprint.is_some() + && &fingerprint_normalized == peerstate.public_key_fingerprint.as_ref().unwrap() + { + fingerprint_equal = 1; + } + } + } else { return 0; } - - if let Some(peerstate) = - Peerstate::from_addr(context, &context.sql, as_str((*contact).addr)) - { - let fingerprint_normalized = dc_normalize_fingerprint(as_str(fingerprint)); - if peerstate.public_key_fingerprint.is_some() - && &fingerprint_normalized == peerstate.public_key_fingerprint.as_ref().unwrap() - { - fingerprint_equal = 1; - } - } } - dc_contact_unref(contact); dc_array_unref(contacts); fingerprint_equal @@ -360,7 +353,7 @@ pub unsafe fn dc_handle_securejoin_handshake( let mut contact_chat_id_blocked: libc::c_int = 0i32; let mut grpid: *mut libc::c_char = 0 as *mut libc::c_char; let mut ret: libc::c_int = 0i32; - let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t; + if !(contact_id <= 9i32 as libc::c_uint) { step = lookup_field(mimeparser, "Secure-Join"); if !step.is_null() { @@ -572,7 +565,11 @@ pub unsafe fn dc_handle_securejoin_handshake( ); current_block = 4378276786830486580; } else { - dc_scaleup_contact_origin(context, contact_id, 0x1000000i32); + Contact::scaleup_origin_by_id( + context, + contact_id, + Origin::SecurejoinInvited, + ); info!(context, 0, "Auth verified.",); secure_connection_established(context, contact_chat_id); context.call_cb( @@ -699,16 +696,23 @@ pub unsafe fn dc_handle_securejoin_handshake( ); current_block = 4378276786830486580; } else { - dc_scaleup_contact_origin(context, contact_id, 0x2000000i32); + Contact::scaleup_origin_by_id( + context, + contact_id, + Origin::SecurejoinJoined, + ); context.call_cb( Event::CONTACTS_CHANGED, 0i32 as uintptr_t, 0i32 as uintptr_t, ); if 0 != join_vg { - if 0 == dc_addr_equals_self( + if !addr_equals_self( context, - lookup_field(mimeparser, "Chat-Group-Member-Added"), + as_str(lookup_field( + mimeparser, + "Chat-Group-Member-Added", + )), ) { info!( context, @@ -756,22 +760,26 @@ pub unsafe fn dc_handle_securejoin_handshake( ==== Alice - the inviter side ==== ==== Step 8 in "Out-of-band verified groups" protocol ==== ============================================================ */ - contact = dc_get_contact(context, contact_id); - if contact.is_null() || 0 == dc_contact_is_verified(contact) { + 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.",); + current_block = 4378276786830486580; + } else { + context.call_cb( + Event::SECUREJOIN_INVITER_PROGRESS, + contact_id as uintptr_t, + 800i32 as uintptr_t, + ); + context.call_cb( + Event::SECUREJOIN_INVITER_PROGRESS, + contact_id as uintptr_t, + 1000i32 as uintptr_t, + ); + current_block = 10256747982273457880; + } + } else { warn!(context, 0, "vg-member-added-received invalid.",); current_block = 4378276786830486580; - } else { - context.call_cb( - Event::SECUREJOIN_INVITER_PROGRESS, - contact_id as uintptr_t, - 800i32 as uintptr_t, - ); - context.call_cb( - Event::SECUREJOIN_INVITER_PROGRESS, - contact_id as uintptr_t, - 1000i32 as uintptr_t, - ); - current_block = 10256747982273457880; } } else { current_block = 10256747982273457880; @@ -786,7 +794,7 @@ pub unsafe fn dc_handle_securejoin_handshake( } } } - dc_contact_unref(contact); + free(scanned_fingerprint_of_alice as *mut libc::c_void); free(auth as *mut libc::c_void); free(own_fingerprint as *mut libc::c_void); @@ -802,23 +810,20 @@ unsafe fn end_bobs_joining(context: &Context, status: libc::c_int) { unsafe fn secure_connection_established(context: &Context, contact_chat_id: uint32_t) { let contact_id: uint32_t = chat_id_2_contact_id(context, contact_chat_id); - let contact: *mut dc_contact_t = dc_get_contact(context, contact_id); - let msg = CString::new(context.stock_string_repl_str( - StockMessage::ContactVerified, - if !contact.is_null() { - as_str((*contact).addr) - } else { - "?" - }, - )) - .unwrap(); + let contact = Contact::get_by_id(context, contact_id); + let addr = if let Ok(ref contact) = contact { + contact.get_addr() + } else { + "?" + }; + let msg = + CString::new(context.stock_string_repl_str(StockMessage::ContactVerified, addr)).unwrap(); dc_add_device_msg(context, contact_chat_id, msg.as_ptr()); context.call_cb( Event::CHAT_MODIFIED, contact_chat_id as uintptr_t, 0i32 as uintptr_t, ); - dc_contact_unref(contact); } unsafe fn lookup_field(mimeparser: &dc_mimeparser_t, key: &str) -> *const libc::c_char { @@ -844,11 +849,11 @@ unsafe fn could_not_establish_secure_connection( details: *const libc::c_char, ) { let contact_id: uint32_t = chat_id_2_contact_id(context, contact_chat_id); - let contact = dc_get_contact(context, contact_id); + let contact = Contact::get_by_id(context, contact_id); let msg = context.stock_string_repl_str( StockMessage::ContactNotVerified, - if !contact.is_null() { - as_str((*contact).addr) + if let Ok(ref contact) = contact { + contact.get_addr() } else { "?" }, @@ -856,7 +861,6 @@ unsafe fn could_not_establish_secure_connection( let msg_c = CString::new(msg.as_str()).unwrap(); dc_add_device_msg(context, contact_chat_id, msg_c.as_ptr()); error!(context, 0, "{} ({})", msg, as_str(details)); - dc_contact_unref(contact); } unsafe fn mark_peer_as_verified( diff --git a/src/dc_tools.rs b/src/dc_tools.rs index ae63098df..814ddd1ab 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -539,32 +539,32 @@ pub unsafe fn dc_str_to_clist( list } +/* the colors must fulfill some criterions as: +- contrast to black and to white +- work as a text-color +- being noticeable on a typical map +- harmonize together while being different enough +(therefore, we cannot just use random rgb colors :) */ +const COLORS: [u32; 16] = [ + 0xe56555, 0xf28c48, 0x8e85ee, 0x76c84d, 0x5bb6cc, 0x549cdd, 0xd25c99, 0xb37800, 0xf23030, + 0x39b249, 0xbb243b, 0x964078, 0x66874f, 0x308ab9, 0x127ed0, 0xbe450c, +]; + +pub fn dc_str_to_color_safe(s: impl AsRef) -> u32 { + let str_lower = s.as_ref().to_lowercase(); + let mut checksum = 0; + let bytes = str_lower.as_bytes(); + for i in 0..str_lower.len() { + checksum += (i + 1) * bytes[i] as usize; + checksum %= 0xffffff; + } + let color_index = checksum % COLORS.len(); + + COLORS[color_index] +} + pub unsafe fn dc_str_to_color(str: *const libc::c_char) -> libc::c_int { let str_lower: *mut libc::c_char = dc_strlower(str); - /* the colors must fulfill some criterions as: - - contrast to black and to white - - work as a text-color - - being noticeable on a typical map - - harmonize together while being different enough - (therefore, we cannot just use random rgb colors :) */ - static mut COLORS: [uint32_t; 16] = [ - 0xe56555i32 as uint32_t, - 0xf28c48i32 as uint32_t, - 0x8e85eei32 as uint32_t, - 0x76c84di32 as uint32_t, - 0x5bb6cci32 as uint32_t, - 0x549cddi32 as uint32_t, - 0xd25c99i32 as uint32_t, - 0xb37800i32 as uint32_t, - 0xf23030i32 as uint32_t, - 0x39b249i32 as uint32_t, - 0xbb243bi32 as uint32_t, - 0x964078i32 as uint32_t, - 0x66874fi32 as uint32_t, - 0x308ab9i32 as uint32_t, - 0x127ed0i32 as uint32_t, - 0xbe450ci32 as uint32_t, - ]; let mut checksum: libc::c_int = 0i32; let str_len: libc::c_int = strlen(str_lower) as libc::c_int; let mut i: libc::c_int = 0i32; diff --git a/src/lib.rs b/src/lib.rs index f735de035..395d2068f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ pub mod aheader; pub mod chatlist; pub mod config; pub mod constants; +pub mod contact; pub mod context; pub mod imap; pub mod key; @@ -39,7 +40,6 @@ pub mod x; pub mod dc_array; pub mod dc_chat; pub mod dc_configure; -pub mod dc_contact; pub mod dc_dehtml; pub mod dc_e2ee; pub mod dc_imex; diff --git a/src/stock.rs b/src/stock.rs index 3416c31ea..20231712b 100644 --- a/src/stock.rs +++ b/src/stock.rs @@ -1,12 +1,11 @@ use std::borrow::Cow; -use std::ffi::CString; use strum::EnumProperty; use strum_macros::EnumProperty; use crate::constants::Event; +use crate::contact::*; use crate::context::Context; -use crate::dc_contact::*; use crate::dc_tools::*; use libc::free; @@ -200,40 +199,30 @@ impl Context { from_id: u32, ) -> String { let insert1 = if id == StockMessage::MsgAddMember || id == StockMessage::MsgDelMember { - unsafe { - let param1_c = CString::new(param1.as_ref()).unwrap(); - let contact_id = dc_lookup_contact_id_by_addr(self, param1_c.as_ptr()); - if contact_id != 0 { - let contact = dc_get_contact(self, contact_id); - let displayname = dc_contact_get_name_n_addr(contact); - let ret = to_string(displayname); - free(contact as *mut libc::c_void); - free(displayname as *mut libc::c_void); - ret - } else { - param1.as_ref().to_string() - } + let contact_id = Contact::lookup_id_by_addr(self, param1.as_ref()); + if contact_id != 0 { + Contact::get_by_id(self, contact_id) + .map(|contact| contact.get_name_n_addr()) + .unwrap_or_default() + } else { + param1.as_ref().to_string() } } else { param1.as_ref().to_string() }; + let action = self.stock_string_repl_str2(id, insert1, param2.as_ref().to_string()); let action1 = action.trim_end_matches('.'); match from_id { 0 => action, 1 => self.stock_string_repl_str(StockMessage::MsgActionByMe, action1), // DC_CONTACT_ID_SELF - _ => unsafe { - let contact = dc_get_contact(self, from_id); - let displayname = dc_contact_get_display_name(contact); - let ret = self.stock_string_repl_str2( - StockMessage::MsgActionByUser, - action1, - as_str(displayname), - ); - free(contact as *mut libc::c_void); - free(displayname as *mut libc::c_void); - ret - }, + _ => { + let displayname = Contact::get_by_id(self, from_id) + .map(|contact| contact.get_name_n_addr()) + .unwrap_or_default(); + + self.stock_string_repl_str2(StockMessage::MsgActionByUser, action1, &displayname) + } } } } @@ -343,11 +332,7 @@ mod tests { #[test] fn test_stock_system_msg_add_member_by_me_with_displayname() { let t = dummy_context(); - unsafe { - let name = CString::new("Alice").unwrap(); - let addr = CString::new("alice@example.com").unwrap(); - assert!(dc_create_contact(&t.ctx, name.as_ptr(), addr.as_ptr()) > 0); - } + Contact::create(&t.ctx, "Alice", "alice@example.com").expect("failed to create contact"); assert_eq!( t.ctx.stock_system_msg( StockMessage::MsgAddMember, @@ -356,23 +341,17 @@ mod tests { DC_CONTACT_ID_SELF as u32 ), "Member Alice (alice@example.com) added by me." - ) + ); } #[test] fn test_stock_system_msg_add_member_by_other_with_displayname() { let t = dummy_context(); - let contact_id = unsafe { - let name = CString::new("Alice").unwrap(); - let addr = CString::new("alice@example.com").unwrap(); - assert!( - dc_create_contact(&t.ctx, name.as_ptr(), addr.as_ptr()) > 0, - "Failed to create contact Alice" - ); - let name = CString::new("Bob").unwrap(); - let addr = CString::new("bob@example.com").unwrap(); - let id = dc_create_contact(&t.ctx, name.as_ptr(), addr.as_ptr()); - assert!(id > 0, "Failed to create contact Bob"); + let contact_id = { + Contact::create(&t.ctx, "Alice", "alice@example.com") + .expect("Failed to create contact Alice"); + let id = + Contact::create(&t.ctx, "Bob", "bob@example.com").expect("failed to create bob"); id }; assert_eq!( @@ -382,8 +361,8 @@ mod tests { "", contact_id, ), - "Member Alice (alice@example.com) added by Bob." - ) + "Member Alice (alice@example.com) added by Bob (bob@example.com)." + ); } #[test] @@ -403,21 +382,13 @@ mod tests { #[test] fn test_stock_system_msg_grp_name_other() { let t = dummy_context(); - let contact_id = unsafe { - let name = CString::new("Alice").unwrap(); - let addr = CString::new("alice@example.com").unwrap(); - let id = dc_create_contact(&t.ctx, name.as_ptr(), addr.as_ptr()); - assert!(id > 0, "Failed to create contact Alice"); - id - }; + let id = Contact::create(&t.ctx, "Alice", "alice@example.com") + .expect("failed to create contact"); + assert_eq!( - t.ctx.stock_system_msg( - StockMessage::MsgGrpName, - "Some chat", - "Other chat", - contact_id - ), - "Group name changed from \"Some chat\" to \"Other chat\" by Alice." + t.ctx + .stock_system_msg(StockMessage::MsgGrpName, "Some chat", "Other chat", id,), + "Group name changed from \"Some chat\" to \"Other chat\" by Alice (alice@example.com)." ) } } diff --git a/tests/stress.rs b/tests/stress.rs index 1230dda85..46176a418 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -8,11 +8,11 @@ use tempfile::{tempdir, TempDir}; use deltachat::config; use deltachat::constants::*; +use deltachat::contact::*; use deltachat::context::*; use deltachat::dc_array::*; use deltachat::dc_chat::*; use deltachat::dc_configure::*; -use deltachat::dc_contact::*; use deltachat::dc_imex::*; use deltachat::dc_location::*; use deltachat::dc_lot::*; @@ -890,22 +890,18 @@ fn test_stress_tests() { fn test_get_contacts() { unsafe { let context = create_test_context(); - let name = CString::yolo("some2"); - let contacts = dc_get_contacts(&context.ctx, 0, name.as_ptr()); + let contacts = Contact::get_all(&context.ctx, 0, Some("some2")).unwrap(); assert_eq!(dc_array_get_cnt(contacts), 0); dc_array_unref(contacts); - let name = CString::yolo("bob"); - let email = CString::yolo("bob@mail.de"); - let id = dc_create_contact(&context.ctx, name.as_ptr(), email.as_ptr()); + let id = Contact::create(&context.ctx, "bob", "bob@mail.de").unwrap(); assert_ne!(id, 0); - let contacts = dc_get_contacts(&context.ctx, 0, name.as_ptr()); + let contacts = Contact::get_all(&context.ctx, 0, Some("bob")).unwrap(); assert_eq!(dc_array_get_cnt(contacts), 1); dc_array_unref(contacts); - let name2 = CString::yolo("alice"); - let contacts = dc_get_contacts(&context.ctx, 0, name2.as_ptr()); + let contacts = Contact::get_all(&context.ctx, 0, Some("alice")).unwrap(); assert_eq!(dc_array_get_cnt(contacts), 0); dc_array_unref(contacts); } @@ -915,10 +911,7 @@ fn test_get_contacts() { fn test_chat() { unsafe { let context = create_test_context(); - let name = CString::yolo("bob"); - let email = CString::yolo("bob@mail.de"); - - let contact1 = dc_create_contact(&context.ctx, name.as_ptr(), email.as_ptr()); + let contact1 = Contact::create(&context.ctx, "bob", "bob@mail.de").unwrap(); assert_ne!(contact1, 0); let chat_id = dc_create_chat_by_contact_id(&context.ctx, contact1); From a993c256e23dce48505fed010f53f67745694d5e Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 23:15:55 +0200 Subject: [PATCH 84/95] Remove comment --- src/dc_e2ee.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index 954f4904b..bd8686323 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -343,7 +343,6 @@ pub unsafe fn dc_e2ee_encrypt( } } } - // ok_to_continue = false = 14181132614457621749 if ok_to_continue { let aheader = Aheader::new(addr, public_key, prefer_encrypt); mailimf_fields_add( From cb138fdcb76f69840affaeac5da6a261f17ecb23 Mon Sep 17 00:00:00 2001 From: jikstra Date: Wed, 7 Aug 2019 23:17:11 +0200 Subject: [PATCH 85/95] Remove comment --- src/dc_mimefactory.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 47920343c..0713f5c35 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -863,7 +863,6 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: } } } - // ok_to_continue = false = 11328123142868406523 if ok_to_continue { if parts == 0 { set_error( From 76dbb37609411f3a61f08b77ad6568f30addce3d Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 5 Aug 2019 19:21:31 +0300 Subject: [PATCH 86/95] Implement dc_get_abs_path_safe --- src/config.rs | 13 +-- src/dc_tools.rs | 223 ++++++++++++++++++------------------------------ src/sql.rs | 6 +- 3 files changed, 84 insertions(+), 158 deletions(-) diff --git a/src/config.rs b/src/config.rs index f4be262b3..459d0f949 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,3 @@ -use std::ffi::CString; - use strum::{EnumProperty, IntoEnumIterator}; use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString}; @@ -9,7 +7,6 @@ use crate::dc_job::*; use crate::dc_tools::*; use crate::error::Error; use crate::stock::StockMessage; -use crate::x::*; /// The available configuration keys. #[derive( @@ -72,15 +69,7 @@ impl Context { let value = match key { Config::Selfavatar => { let rel_path = self.sql.get_config(self, key); - rel_path.map(|p| { - let v = unsafe { - let n = CString::yolo(p); - dc_get_abs_path(self, n.as_ptr()) - }; - let r = to_string(v); - unsafe { free(v as *mut _) }; - r - }) + rel_path.map(|p| dc_get_abs_path_safe(self, &p).to_str().unwrap().to_string()) } Config::SysVersion => Some(std::str::from_utf8(DC_VERSION_STR).unwrap().into()), Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)), diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 814ddd1ab..32f56d807 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -1036,6 +1036,26 @@ pub unsafe fn dc_get_filemeta( 0 } +/// Expand paths relative to $BLOBDIR into absolute paths. +/// +/// If `path` starts with "$BLOBDIR", replaces it with the blobdir path. +/// Otherwise, returns path as is. +pub fn dc_get_abs_path_safe>( + context: &Context, + path: P, +) -> std::path::PathBuf { + let p: &std::path::Path = path.as_ref(); + if let Ok(p) = p.strip_prefix("$BLOBDIR") { + assert!( + context.has_blobdir(), + "Expected context to have blobdir to substitute $BLOBDIR", + ); + std::path::PathBuf::from(as_str(context.get_blobdir())).join(p) + } else { + p.into() + } +} + #[allow(non_snake_case)] pub unsafe fn dc_get_abs_path( context: &Context, @@ -1066,137 +1086,79 @@ pub unsafe fn dc_get_abs_path( pathNfilename_abs } -#[allow(non_snake_case)] -pub unsafe fn dc_file_exist(context: &Context, pathNfilename: *const libc::c_char) -> libc::c_int { - let pathNfilename_abs = dc_get_abs_path(context, pathNfilename); - if pathNfilename_abs.is_null() { - return 0; - } - - let exist = { - let p = std::path::Path::new(as_str(pathNfilename_abs)); - p.exists() - }; - - free(pathNfilename_abs as *mut libc::c_void); - exist as libc::c_int +pub fn dc_file_exist(context: &Context, path: *const libc::c_char) -> libc::c_int { + dc_get_abs_path_safe(context, as_path(path)).exists() as libc::c_int } -#[allow(non_snake_case)] -pub unsafe fn dc_get_filebytes(context: &Context, pathNfilename: *const libc::c_char) -> uint64_t { - let pathNfilename_abs = dc_get_abs_path(context, pathNfilename); - if pathNfilename_abs.is_null() { - return 0; +pub fn dc_get_filebytes(context: &Context, path: *const libc::c_char) -> uint64_t { + let path_abs = dc_get_abs_path_safe(context, as_path(path)); + match fs::metadata(&path_abs) { + Ok(meta) => meta.len() as uint64_t, + Err(_err) => 0, } - - let p = std::ffi::CStr::from_ptr(pathNfilename_abs) - .to_str() - .unwrap(); - let filebytes = match fs::metadata(p) { - Ok(meta) => meta.len(), - Err(_err) => { - return 0; - } - }; - - free(pathNfilename_abs as *mut libc::c_void); - filebytes as uint64_t } -#[allow(non_snake_case)] -pub unsafe fn dc_delete_file(context: &Context, pathNfilename: *const libc::c_char) -> libc::c_int { - let mut success: libc::c_int = 0i32; - let pathNfilename_abs = dc_get_abs_path(context, pathNfilename); - if pathNfilename_abs.is_null() { - return 0; - } - let p = std::path::Path::new( - std::ffi::CStr::from_ptr(pathNfilename_abs) - .to_str() - .unwrap(), - ); - - let res = if p.is_file() { - fs::remove_file(p) +pub fn dc_delete_file(context: &Context, path: *const libc::c_char) -> libc::c_int { + let path = as_path(path); + 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(p) + fs::remove_dir_all(path_abs) }; match res { - Ok(_) => { - success = 1; - } + Ok(_) => 1, Err(_err) => { - warn!(context, 0, "Cannot delete \"{}\".", as_str(pathNfilename),); + warn!(context, 0, "Cannot delete \"{}\".", path.display()); + 0 } } - - free(pathNfilename_abs as *mut libc::c_void); - success } -#[allow(non_snake_case)] -pub unsafe fn dc_copy_file( +pub fn dc_copy_file( context: &Context, src: *const libc::c_char, dest: *const libc::c_char, ) -> libc::c_int { - let mut success = 0; - - let src_abs = dc_get_abs_path(context, src); - let dest_abs = dc_get_abs_path(context, dest); - - if src_abs.is_null() || dest_abs.is_null() { - return 0; - } - - let src_p = std::ffi::CStr::from_ptr(src_abs).to_str().unwrap(); - let dest_p = std::ffi::CStr::from_ptr(dest_abs).to_str().unwrap(); - - match fs::copy(src_p, dest_p) { - Ok(_) => { - success = 1; - } + let src = as_path(src); + let dest = as_path(dest); + let src_abs = dc_get_abs_path_safe(context, src); + let dest_abs = dc_get_abs_path_safe(context, dest); + match fs::copy(&src_abs, &dest_abs) { + Ok(_) => 1, Err(_) => { - error!(context, 0, "Cannot copy \"{}\" to \"{}\".", src_p, dest_p,); + error!( + context, + 0, + "Cannot copy \"{}\" to \"{}\".", + src.display(), + dest.display(), + ); + 0 } } - - free(src_abs as *mut libc::c_void); - free(dest_abs as *mut libc::c_void); - success } -#[allow(non_snake_case)] -pub unsafe fn dc_create_folder( - context: &Context, - pathNfilename: *const libc::c_char, -) -> libc::c_int { - let mut success = 0; - let pathNfilename_abs = dc_get_abs_path(context, pathNfilename); - { - let p = std::path::Path::new(as_str(pathNfilename_abs)); - if !p.exists() { - match fs::create_dir_all(p) { - Ok(_) => { - success = 1; - } - Err(_err) => { - warn!( - context, - 0, - "Cannot create directory \"{}\".", - as_str(pathNfilename), - ); - } +pub fn dc_create_folder(context: &Context, path: *const libc::c_char) -> libc::c_int { + let path = as_path(path); + let path_abs = dc_get_abs_path_safe(context, path); + if !path_abs.exists() { + match fs::create_dir_all(path_abs) { + Ok(_) => 1, + Err(_err) => { + warn!( + context, + 0, + "Cannot create directory \"{}\".", + path.display(), + ); + 0 } - } else { - success = 1; } + } else { + 1 } - - free(pathNfilename_abs as *mut libc::c_void); - success } #[allow(non_snake_case)] @@ -1211,33 +1173,24 @@ pub unsafe fn dc_write_file( dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int } -#[allow(non_snake_case)] -pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef, buf: &[u8]) -> bool { - let pathNfilename_abs = unsafe { - let n = CString::yolo(pathNfilename.as_ref()); - dc_get_abs_path(context, n.as_ptr()) - }; - if pathNfilename_abs.is_null() { - return false; - } - - let p = as_str(pathNfilename_abs); - - let success = if let Err(_err) = fs::write(p, buf) { +pub fn dc_write_file_safe>( + context: &Context, + path: P, + buf: &[u8], +) -> bool { + let path_abs = dc_get_abs_path_safe(context, &path); + if let Err(_err) = fs::write(&path_abs, buf) { warn!( context, 0, "Cannot write {} bytes to \"{}\".", buf.len(), - pathNfilename.as_ref(), + path.as_ref().display(), ); false } else { true - }; - - unsafe { free(pathNfilename_abs as *mut libc::c_void) }; - success + } } #[allow(non_snake_case)] @@ -1260,34 +1213,20 @@ pub unsafe fn dc_read_file( } } -#[allow(non_snake_case)] -pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef) -> Option> { - let pathNfilename_abs = unsafe { - let n = CString::yolo(pathNfilename.as_ref()); - dc_get_abs_path(context, n.as_ptr()) - }; - - if pathNfilename_abs.is_null() { - return None; - } - - let p = as_str(pathNfilename_abs); - let res = match fs::read(p) { +pub fn dc_read_file_safe>(context: &Context, path: P) -> Option> { + let path_abs = dc_get_abs_path_safe(context, &path); + match fs::read(&path_abs) { Ok(bytes) => Some(bytes), Err(_err) => { warn!( context, 0, "Cannot read \"{}\" or file is empty.", - pathNfilename.as_ref(), + path.as_ref().display() ); None } - }; - - unsafe { free(pathNfilename_abs as *mut libc::c_void) }; - - res + } } #[allow(non_snake_case)] diff --git a/src/sql.rs b/src/sql.rs index 2264e3c0e..079130648 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -1047,10 +1047,8 @@ pub fn housekeeping(context: &Context) { unreferenced_count, entry.file_name() ); - unsafe { - let path = entry.path().to_c_string().unwrap(); - dc_delete_file(context, path.as_ptr()); - } + let path = entry.path().to_c_string().unwrap(); + dc_delete_file(context, path.as_ptr()); } } Err(err) => { From 3d834093755d62c721eea82122c1ba2d326acad4 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Thu, 8 Aug 2019 08:48:58 +0200 Subject: [PATCH 87/95] fix own messages displayed as noMsgs in summary --- src/chatlist.rs | 2 +- src/constants.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chatlist.rs b/src/chatlist.rs index 901e0b35b..018aff4ab 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -291,7 +291,7 @@ impl<'a> Chatlist<'a> { if (*chat).id == DC_CHAT_ID_ARCHIVED_LINK as u32 { (*ret).text2 = dc_strdup(0 as *const libc::c_char) - } else if lastmsg.is_null() || (*lastmsg).from_id == DC_CONTACT_ID_SELF as u32 { + } else if lastmsg.is_null() || (*lastmsg).from_id == DC_CONTACT_ID_UNDEFINED as u32 { (*ret).text2 = self.context.stock_str(StockMessage::NoMessages).strdup(); } else { dc_lot_fill(ret, lastmsg, chat, lastcontact.as_ref(), self.context); diff --git a/src/constants.rs b/src/constants.rs index e055dc73d..a5180de98 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -89,6 +89,7 @@ pub const DC_MAX_GET_TEXT_LEN: usize = 30000; /// approx. max. length returned by dc_get_msg_info() pub const DC_MAX_GET_INFO_LEN: usize = 100000; +pub const DC_CONTACT_ID_UNDEFINED: usize = 0; pub const DC_CONTACT_ID_SELF: usize = 1; pub const DC_CONTACT_ID_DEVICE: usize = 2; pub const DC_CONTACT_ID_LAST_SPECIAL: usize = 9; From 8c933f8fa8371b8806f19d915a6e29b0a81cc122 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Thu, 8 Aug 2019 12:26:41 +0300 Subject: [PATCH 88/95] Return bool from set_self_key() --- src/dc_imex.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/dc_imex.rs b/src/dc_imex.rs index 11d06b9b4..259c7237d 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -326,7 +326,7 @@ pub unsafe fn dc_continue_key_transfer( 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 !(0 == set_self_key(context, armored_key, 1i32)) { + } else if set_self_key(context, armored_key, 1) { /*set default*/ /* error already logged */ success = 1i32 @@ -343,12 +343,11 @@ pub unsafe fn dc_continue_key_transfer( success } -// TODO should return bool /rtn fn set_self_key( context: &Context, armored_c: *const libc::c_char, set_default: libc::c_int, -) -> libc::c_int { +) -> bool { assert!(!armored_c.is_null(), "invalid buffer"); let armored = as_str(armored_c); @@ -358,7 +357,7 @@ fn set_self_key( if keys.is_none() { error!(context, 0, "File does not contain a valid private key.",); - return 0; + return false; } let (private_key, public_key, header) = keys.unwrap(); @@ -372,7 +371,7 @@ fn set_self_key( ) .is_err() { - return 0; + return false; } if 0 != set_default { @@ -384,7 +383,7 @@ fn set_self_key( ) .is_err() { - return 0; + return false; } } else { error!(context, 0, "File does not contain a private key.",); @@ -394,7 +393,7 @@ fn set_self_key( if self_addr.is_none() { error!(context, 0, "Missing self addr"); - return 0; + return false; } if !dc_key_save_self_keypair( @@ -406,20 +405,20 @@ fn set_self_key( &context.sql, ) { error!(context, 0, "Cannot save keypair."); - return 0; + return false; } match preferencrypt.map(|s| s.as_str()) { - Some("") => 0, + Some("") => false, Some("nopreference") => context .sql .set_config_int(context, "e2ee_enabled", 0) - .is_ok() as libc::c_int, + .is_ok(), Some("mutual") => context .sql .set_config_int(context, "e2ee_enabled", 1) - .is_ok() as libc::c_int, - _ => 1, + .is_ok(), + _ => true, } } @@ -1155,7 +1154,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) -> ); set_default = 0i32 } - if 0 == set_self_key(context, private_key, set_default) { + if !set_self_key(context, private_key, set_default) { continue; } imported_cnt += 1 From 7c34806125f0d31a7bda3723be8324ffb3f8b6ad Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Thu, 8 Aug 2019 13:32:45 +0300 Subject: [PATCH 89/95] Remove empty keyhistory module --- src/dc_job.rs | 8 -------- src/keyhistory.rs | 13 ------------- src/lib.rs | 1 - 3 files changed, 22 deletions(-) delete mode 100644 src/keyhistory.rs diff --git a/src/dc_job.rs b/src/dc_job.rs index 5efa05f53..1445eeb7d 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -17,7 +17,6 @@ use crate::dc_mimefactory::*; use crate::dc_msg::*; use crate::dc_tools::*; use crate::imap::*; -use crate::keyhistory::*; use crate::param::*; use crate::sql; use crate::types::*; @@ -1277,13 +1276,6 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in (*mimefactory.msg).param.set_int(Param::GuranteeE2ee, 1); dc_msg_save_param_to_disk(mimefactory.msg); } - dc_add_to_keyhistory( - context, - 0 as *const libc::c_char, - 0, - 0 as *const libc::c_char, - 0 as *const libc::c_char, - ); success = dc_add_smtp_job(context, 5901i32, &mut mimefactory); } } diff --git a/src/keyhistory.rs b/src/keyhistory.rs deleted file mode 100644 index ca4bc9507..000000000 --- a/src/keyhistory.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::context::Context; - -/* yes: uppercase */ -/* library private: key-history */ -pub fn dc_add_to_keyhistory( - _context: &Context, - _rfc724_mid: *const libc::c_char, - _sending_time: u64, - _addr: *const libc::c_char, - _fingerprint: *const libc::c_char, -) { - -} diff --git a/src/lib.rs b/src/lib.rs index 395d2068f..da16c8c4a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,6 @@ pub mod contact; pub mod context; pub mod imap; pub mod key; -pub mod keyhistory; pub mod keyring; pub mod oauth2; pub mod param; From 89531dfb62c104774e1377e7583480c8d78efc88 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Fri, 9 Aug 2019 11:31:11 +0200 Subject: [PATCH 90/95] fix(dc_lot): correct test2 --- src/dc_lot.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/dc_lot.rs b/src/dc_lot.rs index 8ca1e05ec..87ef926a1 100644 --- a/src/dc_lot.rs +++ b/src/dc_lot.rs @@ -6,8 +6,6 @@ use crate::dc_tools::*; use crate::stock::StockMessage; use crate::types::*; use crate::x::*; -use std::ffi::CString; -use std::ptr; /* * Structure behind dc_lot_t */ #[derive(Copy, Clone)] @@ -171,14 +169,15 @@ pub unsafe fn dc_lot_fill( } } - let msgtext_c = (*msg) - .text - .as_ref() - .map(|s| CString::yolo(String::as_str(s))); - let msgtext_ptr = msgtext_c.map_or(ptr::null(), |s| s.as_ptr()); + let message_text = (*msg).text.as_ref().unwrap(); - (*lot).text2 = - dc_msg_get_summarytext_by_raw((*msg).type_0, msgtext_ptr, &mut (*msg).param, 160, context); + (*lot).text2 = dc_msg_get_summarytext_by_raw( + (*msg).type_0, + message_text.strdup(), + &mut (*msg).param, + 160, + context, + ); (*lot).timestamp = dc_msg_get_timestamp(msg); (*lot).state = (*msg).state; From 6772d6f66cbb1339bbb2fd845dc3c27ed9ea2ad9 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 7 Aug 2019 22:20:00 +0200 Subject: [PATCH 91/95] fix: improve some string handling in the message recieve path --- src/dc_dehtml.rs | 26 +++--- src/dc_e2ee.rs | 71 +++++++++++++++- src/dc_mimeparser.rs | 187 +++++++++++++++++++++++-------------------- src/dc_simplify.rs | 4 + 4 files changed, 186 insertions(+), 102 deletions(-) diff --git a/src/dc_dehtml.rs b/src/dc_dehtml.rs index bc9747556..de8fa5767 100644 --- a/src/dc_dehtml.rs +++ b/src/dc_dehtml.rs @@ -11,7 +11,7 @@ lazy_static! { struct Dehtml { strbuilder: String, add_text: AddText, - last_href: *mut libc::c_char, + last_href: Option, } #[derive(Debug, PartialEq)] @@ -32,7 +32,7 @@ pub unsafe fn dc_dehtml(buf_terminated: *mut libc::c_char) -> *mut libc::c_char let mut dehtml = Dehtml { strbuilder: String::with_capacity(strlen(buf_terminated)), add_text: AddText::YesRemoveLineEnds, - last_href: 0 as *mut libc::c_char, + last_href: None, }; let mut saxparser = dc_saxparser_t { starttag_cb: None, @@ -51,7 +51,6 @@ pub unsafe fn dc_dehtml(buf_terminated: *mut libc::c_char) -> *mut libc::c_char ); dc_saxparser_set_text_handler(&mut saxparser, Some(dehtml_text_cb)); dc_saxparser_parse(&mut saxparser, buf_terminated); - free(dehtml.last_href as *mut libc::c_void); dehtml.strbuilder.strdup() } @@ -66,7 +65,11 @@ unsafe fn dehtml_text_cb( if dehtml.add_text == AddText::YesPreserveLineEnds || dehtml.add_text == AddText::YesRemoveLineEnds { - let last_added = std::ffi::CStr::from_ptr(text).to_string_lossy(); + let last_added = std::ffi::CStr::from_ptr(text) + .to_str() + .expect("invalid utf8"); + // TODO: why does len does not match? + // assert_eq!(last_added.len(), len as usize); if dehtml.add_text == AddText::YesRemoveLineEnds { dehtml.strbuilder += LINE_RE.replace_all(last_added.as_ref(), "\r").as_ref(); @@ -86,14 +89,10 @@ unsafe fn dehtml_endtag_cb(userdata: *mut libc::c_void, tag: *const libc::c_char dehtml.add_text = AddText::YesRemoveLineEnds; } "a" => { - if !dehtml.last_href.is_null() { + if let Some(ref last_href) = dehtml.last_href.take() { dehtml.strbuilder += "]("; - dehtml.strbuilder += std::ffi::CStr::from_ptr((*dehtml).last_href) - .to_string_lossy() - .as_ref(); + dehtml.strbuilder += last_href; dehtml.strbuilder += ")"; - free(dehtml.last_href as *mut libc::c_void); - dehtml.last_href = 0 as *mut libc::c_char; } } "b" | "strong" => { @@ -131,12 +130,13 @@ unsafe fn dehtml_starttag_cb( dehtml.add_text = AddText::YesPreserveLineEnds; } "a" => { - free(dehtml.last_href as *mut libc::c_void); - dehtml.last_href = dc_strdup_keep_null(dc_attr_find( + let text_c = std::ffi::CStr::from_ptr(dc_attr_find( attr, b"href\x00" as *const u8 as *const libc::c_char, )); - if !dehtml.last_href.is_null() { + let text_r = text_c.to_str().expect("invalid utf8"); + if !text_r.is_empty() { + dehtml.last_href = Some(text_r.to_string()); dehtml.strbuilder += "["; } } diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index bd8686323..41946412b 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -293,7 +293,7 @@ pub unsafe fn dc_e2ee_encrypt( ) { let ctext_bytes = ctext_v.len(); let ctext = ctext_v.strdup(); - (*helper).cdata_to_free = ctext as *mut _; + helper.cdata_to_free = ctext as *mut _; /* create MIME-structure that will contain the encrypted text */ let mut encrypted_part: *mut mailmime = new_data_part( @@ -339,7 +339,7 @@ pub unsafe fn dc_e2ee_encrypt( (*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part; (*encrypted_part).mm_parent = in_out_message; mailmime_free(message_to_encrypt); - (*helper).encryption_successfull = 1i32; + helper.encryption_successfull = 1i32; } } } @@ -926,6 +926,7 @@ unsafe fn decrypt_part( *ret_decrypted_mime = decrypted_mime; sth_decrypted = 1i32 } + std::mem::forget(plain); } } } @@ -1055,3 +1056,69 @@ pub unsafe fn dc_ensure_secret_key_exists(context: &Context) -> libc::c_int { success } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mailmime_parse() { + let plain = b"Chat-Disposition-Notification-To: holger@deltachat.de +Chat-Group-ID: CovhGgau8M- +Chat-Group-Name: Delta Chat Dev +Subject: =?utf-8?Q?Chat=3A?= Delta Chat =?utf-8?Q?Dev=3A?= sidenote for + =?utf-8?Q?all=3A?= rust core master ... +Content-Type: text/plain; charset=\"utf-8\"; protected-headers=\"v1\" +Content-Transfer-Encoding: quoted-printable + +sidenote for all: rust core master is broken currently ... so dont recomm= +end to try to run with desktop or ios unless you are ready to hunt bugs + +-- =20 +Sent with my Delta Chat Messenger: https://delta.chat"; + let plain_bytes = plain.len(); + let plain_buf = plain.as_ptr() as *const libc::c_char; + + let mut index = 0; + let mut decrypted_mime = std::ptr::null_mut(); + + let res = unsafe { + mailmime_parse( + plain_buf as *const _, + plain_bytes, + &mut index, + &mut decrypted_mime, + ) + }; + unsafe { + let msg1 = (*decrypted_mime).mm_data.mm_message.mm_msg_mime; + let mut decoded_data = 0 as *const libc::c_char; + let mut decoded_data_bytes = 0; + let mut transfer_decoding_buffer: *mut libc::c_char = 0 as *mut libc::c_char; + + assert_eq!( + mailmime_transfer_decode( + msg1, + &mut decoded_data, + &mut decoded_data_bytes, + &mut transfer_decoding_buffer, + ), + 1 + ); + println!( + "{:?}", + String::from_utf8_lossy(std::slice::from_raw_parts( + decoded_data as *const u8, + decoded_data_bytes as usize, + )) + ); + + free(decoded_data as *mut _); + } + + assert_eq!(res, 0); + assert!(!decrypted_mime.is_null()); + + unsafe { free(decrypted_mime as *mut _) }; + } +} diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index a9c9476c1..0b40b1747 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -98,34 +98,34 @@ pub unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) { dc_mimepart_unref(part); } assert!(mimeparser.parts.is_empty()); - (*mimeparser).header_root = 0 as *mut mailimf_fields; - (*mimeparser).header.clear(); - if !(*mimeparser).header_protected.is_null() { - mailimf_fields_free((*mimeparser).header_protected); - (*mimeparser).header_protected = 0 as *mut mailimf_fields + mimeparser.header_root = 0 as *mut mailimf_fields; + mimeparser.header.clear(); + if !mimeparser.header_protected.is_null() { + mailimf_fields_free(mimeparser.header_protected); + mimeparser.header_protected = 0 as *mut mailimf_fields } - (*mimeparser).is_send_by_messenger = 0i32; - (*mimeparser).is_system_message = 0i32; - free((*mimeparser).subject as *mut libc::c_void); - (*mimeparser).subject = 0 as *mut libc::c_char; - if !(*mimeparser).mimeroot.is_null() { - mailmime_free((*mimeparser).mimeroot); - (*mimeparser).mimeroot = 0 as *mut mailmime + mimeparser.is_send_by_messenger = 0i32; + mimeparser.is_system_message = 0i32; + free(mimeparser.subject as *mut libc::c_void); + mimeparser.subject = 0 as *mut libc::c_char; + if !mimeparser.mimeroot.is_null() { + mailmime_free(mimeparser.mimeroot); + mimeparser.mimeroot = 0 as *mut mailmime } - (*mimeparser).is_forwarded = 0i32; - (*mimeparser).reports.clear(); - (*mimeparser).decrypting_failed = 0i32; - dc_e2ee_thanks(&mut (*mimeparser).e2ee_helper); + mimeparser.is_forwarded = 0i32; + mimeparser.reports.clear(); + mimeparser.decrypting_failed = 0i32; + dc_e2ee_thanks(&mut mimeparser.e2ee_helper); - if let Some(location_kml) = (*mimeparser).location_kml.as_mut() { + if let Some(location_kml) = mimeparser.location_kml.as_mut() { dc_kml_unref(location_kml); } - (*mimeparser).location_kml = None; + mimeparser.location_kml = None; - if let Some(message_kml) = (*mimeparser).message_kml.as_mut() { + if let Some(message_kml) = mimeparser.message_kml.as_mut() { dc_kml_unref(message_kml); } - (*mimeparser).message_kml = None; + mimeparser.message_kml = None; } unsafe fn dc_mimepart_unref(mut mimepart: dc_mimepart_t) { @@ -148,19 +148,18 @@ pub unsafe fn dc_mimeparser_parse( body_not_terminated, body_bytes, &mut index, - &mut (*mimeparser).mimeroot, + &mut mimeparser.mimeroot, ); - if !(r != MAILIMF_NO_ERROR as libc::c_int || (*mimeparser).mimeroot.is_null()) { + if !(r != MAILIMF_NO_ERROR as libc::c_int || mimeparser.mimeroot.is_null()) { dc_e2ee_decrypt( - (*mimeparser).context, - (*mimeparser).mimeroot, - &mut (*mimeparser).e2ee_helper, + mimeparser.context, + mimeparser.mimeroot, + &mut mimeparser.e2ee_helper, ); - dc_mimeparser_parse_mime_recursive(mimeparser, (*mimeparser).mimeroot); + dc_mimeparser_parse_mime_recursive(mimeparser, mimeparser.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 { - (*mimeparser).subject = - dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value) + mimeparser.subject = dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value) } if !dc_mimeparser_lookup_optional_field( mimeparser, @@ -168,7 +167,7 @@ pub unsafe fn dc_mimeparser_parse( ) .is_null() { - (*mimeparser).is_send_by_messenger = 1i32 + mimeparser.is_send_by_messenger = 1i32 } if !dc_mimeparser_lookup_field(mimeparser, "Autocrypt-Setup-Message").is_null() { let mut has_setup_file: libc::c_int = 0i32; @@ -212,7 +211,7 @@ pub unsafe fn dc_mimeparser_parse( b"location-streaming-enabled\x00" as *const u8 as *const libc::c_char, ) == 0i32 { - (*mimeparser).is_system_message = 8i32 + mimeparser.is_system_message = 8i32 } } } @@ -229,7 +228,7 @@ pub unsafe fn dc_mimeparser_parse( } } } - if 0 != (*mimeparser).is_send_by_messenger + if 0 != mimeparser.is_send_by_messenger && 0 != S_GENERATE_COMPOUND_MSGS && mimeparser.parts.len() == 2 { @@ -248,22 +247,33 @@ pub unsafe fn dc_mimeparser_parse( } if need_drop { - free(mimeparser.parts[1].msg as *mut libc::c_void); - let mut textpart = mimeparser.parts.swap_remove(0); - mimeparser.parts[1].msg = textpart.msg; - textpart.msg = 0 as *mut libc::c_char; - dc_mimepart_unref(textpart); + let mut filepart = mimeparser.parts.swap_remove(1); + + // clear old one + free(filepart.msg as *mut libc::c_void); + + // insert new one + filepart.msg = mimeparser.parts[0].msg; + + // forget the one we use now + mimeparser.parts[0].msg = std::ptr::null_mut(); + + // swap new with old + let old = std::mem::replace(&mut mimeparser.parts[0], filepart); + + // unref old one + dc_mimepart_unref(old); } } - if !(*mimeparser).subject.is_null() { + if !mimeparser.subject.is_null() { let mut prepend_subject: libc::c_int = 1i32; - if 0 == (*mimeparser).decrypting_failed { - let p: *mut libc::c_char = strchr((*mimeparser).subject, ':' as i32); - if p.wrapping_offset_from((*mimeparser).subject) == 2 - || p.wrapping_offset_from((*mimeparser).subject) == 3 - || 0 != (*mimeparser).is_send_by_messenger + if 0 == mimeparser.decrypting_failed { + let p: *mut libc::c_char = strchr(mimeparser.subject, ':' as i32); + if p.wrapping_offset_from(mimeparser.subject) == 2 + || p.wrapping_offset_from(mimeparser.subject) == 3 + || 0 != mimeparser.is_send_by_messenger || !strstr( - (*mimeparser).subject, + mimeparser.subject, b"Chat:\x00" as *const u8 as *const libc::c_char, ) .is_null() @@ -272,7 +282,7 @@ pub unsafe fn dc_mimeparser_parse( } } if 0 != prepend_subject { - let subj: *mut libc::c_char = dc_strdup((*mimeparser).subject); + let subj: *mut libc::c_char = dc_strdup(mimeparser.subject); let p_0: *mut libc::c_char = strchr(subj, '[' as i32); if !p_0.is_null() { *p_0 = 0i32 as libc::c_char @@ -295,7 +305,7 @@ pub unsafe fn dc_mimeparser_parse( free(subj as *mut libc::c_void); } } - if 0 != (*mimeparser).is_forwarded { + if 0 != mimeparser.is_forwarded { for part in mimeparser.parts.iter_mut() { part.param.set_int(Param::Forwarded, 1); } @@ -327,7 +337,7 @@ pub unsafe fn dc_mimeparser_parse( } } } - if 0 == (*mimeparser).decrypting_failed { + if 0 == mimeparser.decrypting_failed { let dn_field: *const mailimf_optional_field = dc_mimeparser_lookup_optional_field( mimeparser, b"Chat-Disposition-Notification-To\x00" as *const u8 as *const libc::c_char, @@ -372,11 +382,11 @@ pub unsafe fn dc_mimeparser_parse( } } /* Cleanup - and try to create at least an empty part if there are no parts yet */ - if dc_mimeparser_get_last_nonmeta(mimeparser).is_none() && (*mimeparser).reports.is_empty() { + if dc_mimeparser_get_last_nonmeta(mimeparser).is_none() && mimeparser.reports.is_empty() { let mut part_5 = dc_mimepart_new(); part_5.type_0 = 10i32; - if !(*mimeparser).subject.is_null() && 0 == (*mimeparser).is_send_by_messenger { - part_5.msg = dc_strdup((*mimeparser).subject) + if !mimeparser.subject.is_null() && 0 == mimeparser.is_send_by_messenger { + part_5.msg = dc_strdup(mimeparser.subject) } else { part_5.msg = dc_strdup(b"\x00" as *const u8 as *const libc::c_char) } @@ -493,32 +503,32 @@ unsafe fn dc_mimeparser_parse_mime_recursive( ) == 0i32 { info!( - (*mimeparser).context, + mimeparser.context, 0, "Protected headers found in text/rfc822-headers attachment: Will be ignored.", ); return 0i32; } - if (*mimeparser).header_protected.is_null() { + if mimeparser.header_protected.is_null() { let mut dummy: size_t = 0i32 as size_t; if mailimf_envelope_and_optional_fields_parse( (*mime).mm_mime_start, (*mime).mm_length, &mut dummy, - &mut (*mimeparser).header_protected, + &mut mimeparser.header_protected, ) != MAILIMF_NO_ERROR as libc::c_int - || (*mimeparser).header_protected.is_null() + || mimeparser.header_protected.is_null() { - warn!((*mimeparser).context, 0, "Protected headers parsing error.",); + warn!(mimeparser.context, 0, "Protected headers parsing error.",); } else { hash_header( - &mut (*mimeparser).header, - (*mimeparser).header_protected, - (*mimeparser).context, + &mut mimeparser.header, + mimeparser.header_protected, + mimeparser.context, ); } } else { info!( - (*mimeparser).context, + mimeparser.context, 0, "Protected headers found in MIME header: Will be ignored as we already found an outer one." ); @@ -622,7 +632,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive( let mut part = dc_mimepart_new(); part.type_0 = 10i32; let msg_body = CString::new( - (*mimeparser) + mimeparser .context .stock_str(StockMessage::CantDecryptMsgBody) .as_ref(), @@ -635,7 +645,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive( part.msg_raw = dc_strdup(part.msg); mimeparser.parts.push(part); any_part_added = 1i32; - (*mimeparser).decrypting_failed = 1i32 + mimeparser.decrypting_failed = 1i32 } 46 => { cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; @@ -663,7 +673,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive( b"disposition-notification\x00" as *const u8 as *const libc::c_char, ) == 0i32 { - (*mimeparser).reports.push(mime); + mimeparser.reports.push(mime); } else { any_part_added = dc_mimeparser_parse_mime_recursive( mimeparser, @@ -713,7 +723,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive( } if plain_cnt == 1i32 && html_cnt == 1i32 { warn!( - (*mimeparser).context, + mimeparser.context, 0i32, "HACK: multipart/mixed message found with PLAIN and HTML, we\'ll skip the HTML part as this seems to be unwanted." ); @@ -742,12 +752,12 @@ unsafe fn dc_mimeparser_parse_mime_recursive( } } 3 => { - if (*mimeparser).header_root.is_null() { - (*mimeparser).header_root = (*mime).mm_data.mm_message.mm_fields; + if mimeparser.header_root.is_null() { + mimeparser.header_root = (*mime).mm_data.mm_message.mm_fields; hash_header( - &mut (*mimeparser).header, - (*mimeparser).header_root, - (*mimeparser).context, + &mut mimeparser.header, + mimeparser.header_root, + mimeparser.context, ); } if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() { @@ -1127,8 +1137,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known( simplifier = Some(dc_simplify_t::new()); } /* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */ - let charset: *const libc::c_char = - mailmime_content_charset_get((*mime).mm_content_type); + let charset = mailmime_content_charset_get((*mime).mm_content_type); if !charset.is_null() && strcmp(charset, b"utf-8\x00" as *const u8 as *const libc::c_char) != 0i32 @@ -1144,12 +1153,16 @@ unsafe fn dc_mimeparser_add_single_part_if_known( ); let (res, _, _) = encoding.decode(data); + info!(mimeparser.context, 0, "decoded message: '{}'", res); if res.is_empty() { /* no error - but nothing to add */ current_block = 8795901732489102124; } else { - decoded_data_bytes = res.len(); - decoded_data = res.as_ptr() as *const libc::c_char; + let b = res.as_bytes(); + decoded_data = b.as_ptr() as *const libc::c_char; + decoded_data_bytes = b.len(); + std::mem::forget(res); + current_block = 17788412896529399552; } } else { @@ -1169,19 +1182,19 @@ unsafe fn dc_mimeparser_add_single_part_if_known( 8795901732489102124 => {} _ => { /* check header directly as is_send_by_messenger is not yet set up */ - let is_msgrmsg: libc::c_int = (dc_mimeparser_lookup_optional_field( + let is_msgrmsg = (!dc_mimeparser_lookup_optional_field( &mimeparser, b"Chat-Version\x00" as *const u8 as *const libc::c_char, - ) != 0 as *mut libc::c_void - as *mut mailimf_optional_field) + ) + .is_null()) as libc::c_int; - let simplified_txt: *mut libc::c_char = - simplifier.unwrap().simplify( - decoded_data, - decoded_data_bytes as libc::c_int, - if mime_type == 70i32 { 1i32 } else { 0i32 }, - is_msgrmsg, - ); + + let simplified_txt = simplifier.unwrap().simplify( + decoded_data, + decoded_data_bytes as libc::c_int, + if mime_type == 70i32 { 1i32 } else { 0i32 }, + is_msgrmsg, + ); if !simplified_txt.is_null() && 0 != *simplified_txt.offset(0isize) as libc::c_int { @@ -1196,7 +1209,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known( free(simplified_txt as *mut libc::c_void); } if 0 != simplifier.unwrap().is_forwarded { - (*mimeparser).is_forwarded = 1i32 + mimeparser.is_forwarded = 1i32 } current_block = 10261677128829721533; } @@ -1324,8 +1337,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known( 4, ) == 0i32 { - (*mimeparser).location_kml = Some(dc_kml_parse( - (*mimeparser).context, + mimeparser.location_kml = Some(dc_kml_parse( + mimeparser.context, decoded_data, decoded_data_bytes, )); @@ -1343,8 +1356,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known( 4, ) == 0i32 { - (*mimeparser).message_kml = Some(dc_kml_parse( - (*mimeparser).context, + mimeparser.message_kml = Some(dc_kml_parse( + mimeparser.context, decoded_data, decoded_data_bytes, )); @@ -1566,7 +1579,7 @@ pub unsafe fn dc_mimeparser_sender_equals_recipient(mimeparser: &dc_mimeparser_t let mut fld_from: *const mailimf_from = 0 as *const mailimf_from; let mb: *mut mailimf_mailbox; - if !(*mimeparser).header_root.is_null() { + if !mimeparser.header_root.is_null() { /* get From: and check there is exactly one sender */ fld = mailimf_find_field(mimeparser.header_root, MAILIMF_FIELD_FROM as libc::c_int); if !(fld.is_null() diff --git a/src/dc_simplify.rs b/src/dc_simplify.rs index bca7a7fe5..6cfb25fd0 100644 --- a/src/dc_simplify.rs +++ b/src/dc_simplify.rs @@ -29,6 +29,10 @@ impl dc_simplify_t { is_html: libc::c_int, is_msgrmsg: libc::c_int, ) -> *mut libc::c_char { + if in_bytes <= 0 { + return "".strdup(); + } + /* create a copy of the given buffer */ let mut out: *mut libc::c_char; let mut temp: *mut libc::c_char; From 1cd2a62caf57aa39fa671ce4309f72af037bebee Mon Sep 17 00:00:00 2001 From: holger krekel Date: Thu, 8 Aug 2019 18:16:27 +0200 Subject: [PATCH 92/95] fix a failure which blocked correctly sending out messages (dc_job_add_smtp mis-set filename) --- src/dc_job.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dc_job.rs b/src/dc_job.rs index 1445eeb7d..e253fabad 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -786,7 +786,7 @@ unsafe fn dc_add_smtp_job( b"\x1e\x00" as *const u8 as *const libc::c_char, ); param.set(Param::File, as_str(pathNfilename)); - param.set(Param::File, as_str(recipients)); + param.set(Param::Recipients, as_str(recipients)); dc_job_add( context, action, From a67892d414a1a9aa36ab7382b97ab111688511bb Mon Sep 17 00:00:00 2001 From: holger krekel Date: Thu, 8 Aug 2019 19:21:52 +0200 Subject: [PATCH 93/95] (jikstra, hpk) fix a logic bug introduced with the stock-string merge which set the better message only if it was empty --- src/dc_receive_imf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 77e6b452c..8be5287f3 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -1723,7 +1723,7 @@ unsafe fn check_verified_properties( unsafe fn set_better_msg>(mime_parser: &mut dc_mimeparser_t, better_msg: T) { let msg = better_msg.as_ref(); - if !(msg.len() > 0) && !mime_parser.parts.is_empty() { + if msg.len() > 0 && !mime_parser.parts.is_empty() { let part = &mut mime_parser.parts[0]; if (*part).type_0 == 10 { free(part.msg as *mut libc::c_void); From 750d6e99a89a618b9deb9347c7f23f52185e3ee4 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Thu, 8 Aug 2019 19:57:51 +0200 Subject: [PATCH 94/95] fix some longer standing nonsense code that sent to misleading MSG_READ events instead of one correct one --- python/tests/test_account.py | 4 +++- src/dc_receive_imf.rs | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/python/tests/test_account.py b/python/tests/test_account.py index 6e6c1e2c2..c9fa5db94 100644 --- a/python/tests/test_account.py +++ b/python/tests/test_account.py @@ -421,7 +421,9 @@ class TestOnlineAccount: lp.sec("mark message as seen on ac2, wait for changes on ac1") ac2.mark_seen_messages([msg_in]) lp.step("1") - ac1._evlogger.get_matching("DC_EVENT_MSG_READ") + ev = ac1._evlogger.get_matching("DC_EVENT_MSG_READ") + assert ev[1] >= const.DC_CHAT_ID_LAST_SPECIAL + assert ev[2] >= const.DC_MSG_ID_LAST_SPECIAL lp.step("2") assert msg_out.is_out_mdn_received() diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 8be5287f3..47c1e3004 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -723,8 +723,7 @@ pub unsafe fn dc_receive_imf( &mut msg_id, ) { rr_event_to_send - .push((chat_id_0, 0)); - rr_event_to_send.push((msg_id, 0)); + .push((chat_id_0, msg_id)); } mdn_consumed = (msg_id != 0 as libc::c_uint) From be605d8ea5059cb13a6eec32ab81c55eb899421b Mon Sep 17 00:00:00 2001 From: holger krekel Date: Fri, 9 Aug 2019 13:28:48 +0200 Subject: [PATCH 95/95] fix(peerstate): encryption-not-available Add a test for failing e2e encryption and some info statement to hunt where the e2e encryption failure comes from, as well as fix the issue. Closes #233 --- python/tests/conftest.py | 2 + python/tests/test_account.py | 31 +++++++++++++++ src/dc_e2ee.rs | 13 +++++- src/peerstate.rs | 77 ++++++++++++++++++++++++++++++++---- 4 files changed, 114 insertions(+), 9 deletions(-) diff --git a/python/tests/conftest.py b/python/tests/conftest.py index fca88e94a..2ee4ad7fd 100644 --- a/python/tests/conftest.py +++ b/python/tests/conftest.py @@ -120,6 +120,8 @@ def acfactory(pytestconfig, tmpdir, request): pytest.skip("specify a --liveconfig file to run tests with real accounts") self.live_count += 1 configdict = self.configlist.pop(0) + if "e2ee_enabled" not in configdict: + configdict["e2ee_enabled"] = "1" tmpdb = tmpdir.join("livedb%d" % self.live_count) ac = Account(tmpdb.strpath, logid="ac{}".format(self.live_count)) ac._evlogger.init_time = self.init_time diff --git a/python/tests/test_account.py b/python/tests/test_account.py index c9fa5db94..5acf972c4 100644 --- a/python/tests/test_account.py +++ b/python/tests/test_account.py @@ -427,6 +427,37 @@ class TestOnlineAccount: lp.step("2") assert msg_out.is_out_mdn_received() + def test_send_and_receive_will_encrypt_decrypt(self, acfactory, lp): + lp.sec("starting accounts, waiting for configuration") + ac1 = acfactory.get_online_configuring_account() + ac2 = acfactory.get_online_configuring_account() + c2 = ac1.create_contact(email=ac2.get_config("addr")) + chat = ac1.create_chat_by_contact(c2) + assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL + + wait_configuration_progress(ac1, 1000) + wait_configuration_progress(ac2, 1000) + + lp.sec("sending text message from ac1 to ac2") + msg_out = chat.send_text("message1") + + lp.sec("wait for ac2 to receive message") + ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED") + assert ev[2] == msg_out.id + msg_in = ac2.get_message_by_id(msg_out.id) + assert msg_in.text == "message1" + + lp.sec("create new chat with contact and send back (encrypted) message") + chat2b = ac2.create_chat_by_message(msg_in) + chat2b.send_text("message-back") + + lp.sec("wait for ac1 to receive message") + ev = ac1._evlogger.get_matching("DC_EVENT_INCOMING_MSG") + assert ev[1] == chat.id + assert ev[2] > msg_out.id + msg_back = ac1.get_message_by_id(ev[2]) + assert msg_back.text == "message-back" + def test_saved_mime_on_received_message(self, acfactory, lp): lp.sec("starting accounts, waiting for configuration") ac1 = acfactory.get_online_configuring_account() diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index 41946412b..db0c15a89 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -115,11 +115,22 @@ pub unsafe fn dc_e2ee_encrypt( || 0 != e2ee_guaranteed) { let peerstate = peerstate.unwrap(); + info!( + context, + 0, "dc_e2ee_encrypt {} has peerstate", recipient_addr + ); if let Some(key) = peerstate.peek_key(min_verified as usize) { keyring.add_owned(key.clone()); peerstates.push(peerstate); } } else { + info!( + context, + 0, + "dc_e2ee_encrypt {} HAS NO peerstate {}", + recipient_addr, + peerstate.is_some() + ); do_encrypt = 0i32; /* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */ break; @@ -574,7 +585,7 @@ pub unsafe fn dc_e2ee_decrypt( } } else if let Some(ref header) = autocryptheader { let p = Peerstate::from_header(context, header, message_time); - p.save_to_db(&context.sql, true); + assert!(p.save_to_db(&context.sql, true)); peerstate = Some(p); } } diff --git a/src/peerstate.rs b/src/peerstate.rs index d7f8009ab..de0e01abe 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -166,7 +166,6 @@ impl<'a> Peerstate<'a> { pub fn from_addr(context: &'a Context, _sql: &Sql, addr: &str) -> Option { let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;"; - Self::from_stmt(context, query, &[addr]) } @@ -191,6 +190,11 @@ impl<'a> Peerstate<'a> { context .sql .query_row(query, params, |row| { + /* all the above queries start with this: SELECT + addr, last_seen, last_seen_autocrypt, prefer_encrypted, + public_key, gossip_timestamp, gossip_key, public_key_fingerprint, + gossip_key_fingerprint, verified_key, verified_key_fingerprint + */ let mut res = Self::new(context); res.addr = Some(row.get(0)?); @@ -198,13 +202,34 @@ impl<'a> Peerstate<'a> { res.last_seen_autocrypt = row.get(2)?; res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default(); res.gossip_timestamp = row.get(5)?; - let pkf: String = row.get(7)?; - res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) }; - let gkf: String = row.get(8)?; - res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) }; - let vkf: String = row.get(10)?; - res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) }; + res.public_key_fingerprint = row.get(7)?; + if res + .public_key_fingerprint + .as_ref() + .map(|s| s.is_empty()) + .unwrap_or_default() + { + res.public_key_fingerprint = None; + } + res.gossip_key_fingerprint = row.get(8)?; + if res + .gossip_key_fingerprint + .as_ref() + .map(|s| s.is_empty()) + .unwrap_or_default() + { + res.gossip_key_fingerprint = None; + } + res.verified_key_fingerprint = row.get(10)?; + if res + .verified_key_fingerprint + .as_ref() + .map(|s| s.is_empty()) + .unwrap_or_default() + { + res.verified_key_fingerprint = None; + } res.public_key = row .get(4) .ok() @@ -217,7 +242,8 @@ impl<'a> Peerstate<'a> { .get(9) .ok() .and_then(|blob: Vec| Key::from_slice(&blob, KeyType::Public)); - res.verified_key = if vk == res.gossip_key { + + res.verified_key = if vk == res.gossip_key && res.gossip_key.is_some() { VerifiedKey::Gossip } else if vk == res.public_key { VerifiedKey::Public @@ -422,6 +448,7 @@ impl<'a> Peerstate<'a> { &self.addr, ], ).is_ok(); + assert_eq!(success, true); } else if self.to_save == Some(ToSave::Timestamps) { success = sql::execute( self.context, @@ -498,6 +525,40 @@ mod tests { assert_eq!(peerstate, peerstate_new); } + #[test] + fn test_peerstate_with_empty_gossip_key_save_to_db() { + let ctx = crate::test_utils::dummy_context(); + let addr = "hello@mail.com"; + + let pub_key = crate::key::Key::from_base64("xsBNBFztUVkBCADYaQl/UOUpRPd32nLRzx8eU0eI+jQEnG+g5anjYA+3oct1rROGl5SygjMULDKdaUy27O3o9Srsti0YjA7uxZnavIqhSopJhFidqY1M1wA9JZa/duucZdNwUGbjGIRsS/4Cjr5+3svscK24hVYub1dvDWXpwUTnj3K6xOEnJdoM+MhCqtSD5+zcJhFc9vyZm9ZTGWUxAhKh0iJTcCD8V6CQ3XZ2z9GruwzZT/FTFovWrz7m3TUI2OdSSHh0eZLRGEoxMCT/vzflAFGAr8ijCaRsEIfqP6FW8uQWnFTqkjxEUCZG6XkeFHB84aj5jqYG/1KCLjL5vEKwfl1tz/WnPhY7ABEBAAHNEDxoZWxsb0BtYWlsLmNvbT7CwIkEEAEIADMCGQEFAlztUVoCGwMECwkIBwYVCAkKCwIDFgIBFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7ijAwf+PTsuawUax9cNPn1bN90H+g9qyHZJMEwKXtUnNaXJxPW3iB7ThhpCiCzsZwP7+l7ArS8tmLeNDw2bENtcf1XCv4wovP2fdXOP3QOUUFX/GdakcTwv7DzC7CO0grB1HtaPhGw/6UX2o2cx2i9xiUf4Givq2MfCbgAW5zloH6WXGPb6yLQYJXxqDIphr4+uZDb+bMAyWHN/DUkAjHrV8nnVki7PMHqzzZpwglalxMX8RGeiGZE39ALJKL/Og87DMFah87/yoxQWGoS7Wqv0XDcCPKoTCPrpk8pOe2KEsq/lz215nefHd4aRpfUX5YCYa8HPvvfPQbGF73uvyQw5w7qjis7ATQRc7VFZAQgAt8ONdnX6KEEQ5Jw6ilJ+LBtY44SP5t0I3eK+goKepgIiKhjGDa+Mntyi4jdhH+HO6kvK5SHMh2sPp4rRO/WKHJwWFySyM1OdyiywhyH0J9R5rBY4vPHsJjf6vSKJdWLWT+ho1fNet2IIC+jVCYli91MAMbRvk6EKVj1nCc+67giOahXEkHt6xxkeCGlOvbw8hxGj1A8+AC1BLms/OR3oc4JMi9O3kq6uG0z9tlUEerac9HVwcjoO1XLe+hJhoT5H+TbnGjPuhuURP3pFiIKHpbRYgUfdSAY0dTObO7t4I5y/drPOrCTnWrBUg2wXAECUhpRKow9/ai2YemLv9KqhhwARAQABwsB2BBgBCAAgBQJc7VFaAhsMFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7jmyggAhs4QzCzIbT2OsAReBxkxtm0AI+g1HZ1KFKof5NDHfgv9C/Qu1I8mKEjlZzA4qFyPmLqntgwJ0RuFy6gLbljZBNCFO7vB478AhYtnWjuKZmA40HUPwcB1hEJ31c42akzfUbioY1TLLepngdsJg7Cm8O+rhI9+1WRA66haJDgFs793SVUDyJh8f9NX50l5zR87/bsV30CFSw0q4OSSy9VI/z+2g5khn1LnuuOrCfFnYIPYtJED1BfkXkosxGlgbzy79VvGmI9d23x4atDK7oBPCzIj+lP8sytJ0u3HOguXi9OgDitKy+Pt1r8gH8frdktMJr5Ts6DW+tIn2vR23KR8aA==", KeyType::Public).unwrap(); + + let mut peerstate = Peerstate { + context: &ctx.ctx, + addr: Some(addr.into()), + last_seen: 10, + last_seen_autocrypt: 11, + prefer_encrypt: EncryptPreference::Mutual, + public_key: Some(pub_key.clone()), + public_key_fingerprint: Some(pub_key.fingerprint()), + gossip_key: None, + gossip_timestamp: 12, + gossip_key_fingerprint: None, + verified_key: VerifiedKey::None, + verified_key_fingerprint: None, + to_save: Some(ToSave::All), + degrade_event: None, + }; + + assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save"); + + let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into()) + .expect("failed to load peerstate from db"); + + // clear to_save, as that is not persissted + peerstate.to_save = None; + assert_eq!(peerstate, peerstate_new); + } + // TODO: don't copy this from stress.rs #[allow(dead_code)] struct TestContext {