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();