diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 920a97a389..ea5539b351 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 9c2d6f5da1..30f27e67cf 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 b023c801ef..c3a47ccecf 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 fc80fda687..1ec8da0f11 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 c8c0d8a144..9012597a30 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), @@ -950,7 +950,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!( @@ -960,18 +960,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 @@ -1001,9 +991,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 @@ -1036,11 +1024,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.as_ref().map(String::as_str).unwrap_or(""), (*msg).param.to_string(), 1, ], @@ -1616,14 +1600,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)); @@ -1731,23 +1713,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() { @@ -1848,14 +1826,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)); @@ -1922,18 +1898,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 c9e3ee66eb..5e6e599ca5 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 3d4c714de7..8741b43413 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 0cb95d7804..5d0d9d3add 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 5963476101..109d5ebae7 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( @@ -1426,6 +1442,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 +1563,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()); + } + } } diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index 90573412f0..edcdacffa7 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() {