diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 426507192..94d69f779 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -1172,7 +1172,7 @@ pub unsafe extern "C" fn dc_get_msg_info( } let ffi_context = &*context; ffi_context - .with_inner(|ctx| message::dc_get_msg_info(ctx, msg_id)) + .with_inner(|ctx| message::get_msg_info(ctx, msg_id)) .unwrap_or_else(|_| ptr::null_mut()) } @@ -1187,7 +1187,7 @@ pub unsafe extern "C" fn dc_get_mime_headers( } let ffi_context = &*context; ffi_context - .with_inner(|ctx| message::dc_get_mime_headers(ctx, msg_id)) + .with_inner(|ctx| message::get_mime_headers(ctx, msg_id)) .unwrap_or_else(|_| ptr::null_mut()) } @@ -1203,7 +1203,7 @@ pub unsafe extern "C" fn dc_delete_msgs( } let ffi_context = &*context; ffi_context - .with_inner(|ctx| message::dc_delete_msgs(ctx, msg_ids, msg_cnt)) + .with_inner(|ctx| message::delete_msgs(ctx, msg_ids, msg_cnt)) .unwrap_or(()) } @@ -1252,7 +1252,7 @@ pub unsafe extern "C" fn dc_markseen_msgs( } let ffi_context = &*context; ffi_context - .with_inner(|ctx| message::dc_markseen_msgs(ctx, msg_ids, msg_cnt as usize)) + .with_inner(|ctx| message::markseen_msgs(ctx, msg_ids, msg_cnt as usize)) .ok(); } @@ -1269,7 +1269,7 @@ pub unsafe extern "C" fn dc_star_msgs( } let ffi_context = &*context; ffi_context - .with_inner(|ctx| message::dc_star_msgs(ctx, msg_ids, msg_cnt, star)) + .with_inner(|ctx| message::star_msgs(ctx, msg_ids, msg_cnt, star)) .ok(); } @@ -1282,7 +1282,7 @@ pub unsafe extern "C" fn dc_get_msg(context: *mut dc_context_t, msg_id: u32) -> let ffi_context = &*context; ffi_context .with_inner(|ctx| { - let message = match message::dc_get_msg(ctx, msg_id) { + let message = match message::Message::load_from_db(ctx, msg_id) { Ok(msg) => msg, Err(e) => { error!(ctx, "Error getting msg #{}: {}", msg_id, e); @@ -2176,7 +2176,7 @@ pub unsafe extern "C" fn dc_msg_new( let viewtype = from_prim(viewtype).expect(&format!("invalid viewtype = {}", viewtype)); let msg = MessageWrapper { context, - message: message::dc_msg_new(viewtype), + message: message::Message::new(viewtype), }; Box::into_raw(Box::new(msg)) } @@ -2198,7 +2198,7 @@ pub unsafe extern "C" fn dc_msg_get_id(msg: *mut dc_msg_t) -> u32 { return 0; } let ffi_msg = &*msg; - message::dc_msg_get_id(&ffi_msg.message) + ffi_msg.message.get_id() } #[no_mangle] @@ -2208,7 +2208,7 @@ pub unsafe extern "C" fn dc_msg_get_from_id(msg: *mut dc_msg_t) -> u32 { return 0; } let ffi_msg = &*msg; - message::dc_msg_get_from_id(&ffi_msg.message) + ffi_msg.message.get_from_id() } #[no_mangle] @@ -2218,7 +2218,7 @@ pub unsafe extern "C" fn dc_msg_get_chat_id(msg: *mut dc_msg_t) -> u32 { return 0; } let ffi_msg = &*msg; - message::dc_msg_get_chat_id(&ffi_msg.message) + ffi_msg.message.get_chat_id() } #[no_mangle] @@ -2228,7 +2228,9 @@ pub unsafe extern "C" fn dc_msg_get_viewtype(msg: *mut dc_msg_t) -> libc::c_int return 0; } let ffi_msg = &*msg; - message::dc_msg_get_viewtype(&ffi_msg.message) + ffi_msg + .message + .get_viewtype() .to_i64() .expect("impossible: Viewtype -> i64 conversion failed") as libc::c_int } @@ -2240,7 +2242,7 @@ pub unsafe extern "C" fn dc_msg_get_state(msg: *mut dc_msg_t) -> libc::c_int { return 0; } let ffi_msg = &*msg; - message::dc_msg_get_state(&ffi_msg.message) as libc::c_int + ffi_msg.message.get_state() as libc::c_int } #[no_mangle] @@ -2250,7 +2252,7 @@ pub unsafe extern "C" fn dc_msg_get_timestamp(msg: *mut dc_msg_t) -> i64 { return 0; } let ffi_msg = &*msg; - message::dc_msg_get_timestamp(&ffi_msg.message) + ffi_msg.message.get_timestamp() } #[no_mangle] @@ -2260,7 +2262,7 @@ pub unsafe extern "C" fn dc_msg_get_received_timestamp(msg: *mut dc_msg_t) -> i6 return 0; } let ffi_msg = &*msg; - message::dc_msg_get_received_timestamp(&ffi_msg.message) + ffi_msg.message.get_received_timestamp() } #[no_mangle] @@ -2270,7 +2272,7 @@ pub unsafe extern "C" fn dc_msg_get_sort_timestamp(msg: *mut dc_msg_t) -> i64 { return 0; } let ffi_msg = &*msg; - message::dc_msg_get_sort_timestamp(&ffi_msg.message) + ffi_msg.message.get_sort_timestamp() } #[no_mangle] @@ -2280,7 +2282,7 @@ pub unsafe extern "C" fn dc_msg_get_text(msg: *mut dc_msg_t) -> *mut libc::c_cha return dc_strdup(ptr::null()); } let ffi_msg = &*msg; - message::dc_msg_get_text(&ffi_msg.message) + ffi_msg.message.get_text() } #[no_mangle] @@ -2293,7 +2295,9 @@ pub unsafe extern "C" fn dc_msg_get_file(msg: *mut dc_msg_t) -> *mut libc::c_cha let ffi_context = &*ffi_msg.context; ffi_context .with_inner(|ctx| { - message::dc_msg_get_file(ctx, &ffi_msg.message) + ffi_msg + .message + .get_file(ctx) .and_then(|p| p.to_c_string().ok()) .map(|cs| dc_strdup(cs.as_ptr())) .unwrap_or_else(|| "".strdup()) @@ -2308,7 +2312,7 @@ pub unsafe extern "C" fn dc_msg_get_filename(msg: *mut dc_msg_t) -> *mut libc::c return dc_strdup(ptr::null()); } let ffi_msg = &*msg; - message::dc_msg_get_filename(&ffi_msg.message) + ffi_msg.message.get_filename() } #[no_mangle] @@ -2318,7 +2322,7 @@ pub unsafe extern "C" fn dc_msg_get_filemime(msg: *mut dc_msg_t) -> *mut libc::c return dc_strdup(ptr::null()); } let ffi_msg = &*msg; - message::dc_msg_get_filemime(&ffi_msg.message).strdup() + ffi_msg.message.get_filemime().strdup() } #[no_mangle] @@ -2330,7 +2334,7 @@ pub unsafe extern "C" fn dc_msg_get_filebytes(msg: *mut dc_msg_t) -> u64 { let ffi_msg = &*msg; let ffi_context = &*ffi_msg.context; ffi_context - .with_inner(|ctx| message::dc_msg_get_filebytes(ctx, &ffi_msg.message)) + .with_inner(|ctx| ffi_msg.message.get_filebytes(ctx)) .unwrap_or(0) } @@ -2341,7 +2345,7 @@ pub unsafe extern "C" fn dc_msg_get_width(msg: *mut dc_msg_t) -> libc::c_int { return 0; } let ffi_msg = &*msg; - message::dc_msg_get_width(&ffi_msg.message) + ffi_msg.message.get_width() } #[no_mangle] @@ -2351,7 +2355,7 @@ pub unsafe extern "C" fn dc_msg_get_height(msg: *mut dc_msg_t) -> libc::c_int { return 0; } let ffi_msg = &*msg; - message::dc_msg_get_height(&ffi_msg.message) + ffi_msg.message.get_height() } #[no_mangle] @@ -2361,7 +2365,7 @@ pub unsafe extern "C" fn dc_msg_get_duration(msg: *mut dc_msg_t) -> libc::c_int return 0; } let ffi_msg = &*msg; - message::dc_msg_get_duration(&ffi_msg.message) + ffi_msg.message.get_duration() } #[no_mangle] @@ -2371,7 +2375,7 @@ pub unsafe extern "C" fn dc_msg_get_showpadlock(msg: *mut dc_msg_t) -> libc::c_i return 0; } let ffi_msg = &*msg; - message::dc_msg_get_showpadlock(&ffi_msg.message) as libc::c_int + ffi_msg.message.get_showpadlock() as libc::c_int } #[no_mangle] @@ -2393,7 +2397,7 @@ pub unsafe extern "C" fn dc_msg_get_summary( let ffi_context = &*ffi_msg.context; ffi_context .with_inner(|ctx| { - let lot = message::dc_msg_get_summary(ctx, &mut ffi_msg.message, maybe_chat); + let lot = ffi_msg.message.get_summary(ctx, maybe_chat); Box::into_raw(Box::new(lot)) }) .unwrap_or_else(|_| ptr::null_mut()) @@ -2412,11 +2416,9 @@ pub unsafe extern "C" fn dc_msg_get_summarytext( let ffi_context = &*ffi_msg.context; ffi_context .with_inner(|ctx| { - message::dc_msg_get_summarytext( - ctx, - &mut ffi_msg.message, - approx_characters.try_into().unwrap(), - ) + ffi_msg + .message + .get_summarytext(ctx, approx_characters.try_into().unwrap()) }) .unwrap_or_else(|_| "".strdup()) } @@ -2428,7 +2430,7 @@ pub unsafe extern "C" fn dc_msg_has_deviating_timestamp(msg: *mut dc_msg_t) -> l return 0; } let ffi_msg = &*msg; - message::dc_msg_has_deviating_timestamp(&ffi_msg.message) + ffi_msg.message.has_deviating_timestamp() } #[no_mangle] @@ -2438,7 +2440,7 @@ pub unsafe extern "C" fn dc_msg_has_location(msg: *mut dc_msg_t) -> libc::c_int return 0; } let ffi_msg = &*msg; - message::dc_msg_has_location(&ffi_msg.message) as libc::c_int + ffi_msg.message.has_location() as libc::c_int } #[no_mangle] @@ -2448,7 +2450,7 @@ pub unsafe extern "C" fn dc_msg_is_sent(msg: *mut dc_msg_t) -> libc::c_int { return 0; } let ffi_msg = &*msg; - message::dc_msg_is_sent(&ffi_msg.message).into() + ffi_msg.message.is_sent().into() } #[no_mangle] @@ -2458,7 +2460,7 @@ pub unsafe extern "C" fn dc_msg_is_starred(msg: *mut dc_msg_t) -> libc::c_int { return 0; } let ffi_msg = &*msg; - message::dc_msg_is_starred(&ffi_msg.message).into() + ffi_msg.message.is_starred().into() } #[no_mangle] @@ -2468,7 +2470,7 @@ pub unsafe extern "C" fn dc_msg_is_forwarded(msg: *mut dc_msg_t) -> libc::c_int return 0; } let ffi_msg = &*msg; - message::dc_msg_is_forwarded(&ffi_msg.message).into() + ffi_msg.message.is_forwarded().into() } #[no_mangle] @@ -2478,7 +2480,7 @@ pub unsafe extern "C" fn dc_msg_is_info(msg: *mut dc_msg_t) -> libc::c_int { return 0; } let ffi_msg = &*msg; - message::dc_msg_is_info(&ffi_msg.message).into() + ffi_msg.message.is_info().into() } #[no_mangle] @@ -2488,7 +2490,7 @@ pub unsafe extern "C" fn dc_msg_is_increation(msg: *mut dc_msg_t) -> libc::c_int return 0; } let ffi_msg = &*msg; - message::dc_msg_is_increation(&ffi_msg.message).into() + ffi_msg.message.is_increation().into() } #[no_mangle] @@ -2498,7 +2500,7 @@ pub unsafe extern "C" fn dc_msg_is_setupmessage(msg: *mut dc_msg_t) -> libc::c_i return 0; } let ffi_msg = &*msg; - message::dc_msg_is_setupmessage(&ffi_msg.message).into() + ffi_msg.message.is_setupmessage().into() } #[no_mangle] @@ -2510,7 +2512,7 @@ pub unsafe extern "C" fn dc_msg_get_setupcodebegin(msg: *mut dc_msg_t) -> *mut l let ffi_msg = &*msg; let ffi_context = &*ffi_msg.context; ffi_context - .with_inner(|ctx| message::dc_msg_get_setupcodebegin(ctx, &ffi_msg.message)) + .with_inner(|ctx| ffi_msg.message.get_setupcodebegin(ctx)) .unwrap_or_else(|_| "".strdup()) } @@ -2522,7 +2524,7 @@ pub unsafe extern "C" fn dc_msg_set_text(msg: *mut dc_msg_t, text: *mut libc::c_ } let ffi_msg = &mut *msg; // TODO: {text} equal to NULL is treated as "", which is strange. Does anyone rely on it? - message::dc_msg_set_text(&mut ffi_msg.message, text) + ffi_msg.message.set_text(text) } #[no_mangle] @@ -2536,7 +2538,7 @@ pub unsafe extern "C" fn dc_msg_set_file( return; } let ffi_msg = &mut *msg; - message::dc_msg_set_file(&mut ffi_msg.message, file, filemime) + ffi_msg.message.set_file(file, filemime) } #[no_mangle] @@ -2550,7 +2552,7 @@ pub unsafe extern "C" fn dc_msg_set_dimension( return; } let ffi_msg = &mut *msg; - message::dc_msg_set_dimension(&mut ffi_msg.message, width, height) + ffi_msg.message.set_dimension(width, height) } #[no_mangle] @@ -2560,7 +2562,7 @@ pub unsafe extern "C" fn dc_msg_set_duration(msg: *mut dc_msg_t, duration: libc: return; } let ffi_msg = &mut *msg; - message::dc_msg_set_duration(&mut ffi_msg.message, duration) + ffi_msg.message.set_duration(duration) } #[no_mangle] @@ -2574,7 +2576,7 @@ pub unsafe extern "C" fn dc_msg_set_location( return; } let ffi_msg = &mut *msg; - message::dc_msg_set_location(&mut ffi_msg.message, latitude, longitude) + ffi_msg.message.set_location(latitude, longitude) } #[no_mangle] @@ -2592,7 +2594,9 @@ pub unsafe extern "C" fn dc_msg_latefiling_mediasize( let ffi_context = &*ffi_msg.context; ffi_context .with_inner(|ctx| { - message::dc_msg_latefiling_mediasize(ctx, &mut ffi_msg.message, width, height, duration) + ffi_msg + .message + .latefiling_mediasize(ctx, width, height, duration) }) .ok(); } diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index e2d6dead4..12c5d7446 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -16,7 +16,7 @@ use deltachat::error::Error; use deltachat::job::*; use deltachat::location; use deltachat::lot::LotState; -use deltachat::message::*; +use deltachat::message::{self, Message, MessageState}; use deltachat::peerstate::*; use deltachat::qr::*; use deltachat::sql; @@ -216,44 +216,40 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int } unsafe fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { - let contact = Contact::get_by_id(context, dc_msg_get_from_id(msg)).expect("invalid contact"); + let contact = Contact::get_by_id(context, msg.get_from_id()).expect("invalid contact"); let contact_name = contact.get_name(); let contact_id = contact.get_id(); - let statestr = match dc_msg_get_state(msg) { + let statestr = match msg.get_state() { MessageState::OutPending => " o", MessageState::OutDelivered => " √", MessageState::OutMdnRcvd => " √√", MessageState::OutFailed => " !!", _ => "", }; - let temp2 = dc_timestamp_to_str(dc_msg_get_timestamp(msg)); - let msgtext = dc_msg_get_text(msg); + let temp2 = dc_timestamp_to_str(msg.get_timestamp()); + let msgtext = msg.get_text(); info!( context, "{}#{}{}{}: {} (Contact#{}): {} {}{}{}{} [{}]", prefix.as_ref(), - dc_msg_get_id(msg) as libc::c_int, - if dc_msg_get_showpadlock(msg) { - "🔒" - } else { - "" - }, - if dc_msg_has_location(msg) { "📍" } else { "" }, + msg.get_id() as libc::c_int, + if msg.get_showpadlock() { "🔒" } else { "" }, + if msg.has_location() { "📍" } else { "" }, &contact_name, contact_id, as_str(msgtext), - if dc_msg_is_starred(msg) { "★" } else { "" }, - if dc_msg_get_from_id(msg) == 1 as libc::c_uint { + if msg.is_starred() { "★" } else { "" }, + if msg.get_from_id() == 1 as libc::c_uint { "" - } else if dc_msg_get_state(msg) == MessageState::InSeen { + } else if msg.get_state() == MessageState::InSeen { "[SEEN]" - } else if dc_msg_get_state(msg) == MessageState::InNoticed { + } else if msg.get_state() == MessageState::InNoticed { "[NOTICED]" } else { "[FRESH]" }, - if dc_msg_is_info(msg) { "[INFO]" } else { "" }, + if msg.is_info() { "[INFO]" } else { "" }, statestr, &temp2, ); @@ -278,7 +274,7 @@ unsafe fn log_msglist(context: &Context, msglist: &Vec) -> Result<(), Error ); lines_out += 1 } - let msg = dc_get_msg(context, msg_id)?; + let msg = Message::load_from_db(context, msg_id)?; log_msg(context, "Msg", &msg); } } @@ -467,9 +463,9 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E "get-setupcodebegin" => { ensure!(!arg1.is_empty(), "Argument missing."); let msg_id: u32 = arg1.parse()?; - let msg = dc_get_msg(context, msg_id)?; - if dc_msg_is_setupmessage(&msg) { - let setupcodebegin = dc_msg_get_setupcodebegin(context, &msg); + let msg = Message::load_from_db(context, msg_id)?; + if msg.is_setupmessage() { + let setupcodebegin = msg.get_setupcodebegin(context); println!( "The setup code for setup message Msg#{} starts with: {}", msg_id, @@ -825,14 +821,14 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E ensure!(sel_chat.is_some(), "No chat selected."); ensure!(!arg1.is_empty(), "No file given."); - let mut msg = dc_msg_new(if arg0 == "sendimage" { + let mut msg = Message::new(if arg0 == "sendimage" { Viewtype::Image } else { Viewtype::File }); - dc_msg_set_file(&mut msg, arg1_c, ptr::null()); + msg.set_file(arg1_c, ptr::null()); if !arg2.is_empty() { - dc_msg_set_text(&mut msg, arg2_c); + msg.set_text(arg2_c); } chat::send_msg(context, sel_chat.as_ref().unwrap().get_id(), &mut msg)?; } @@ -854,8 +850,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E ensure!(sel_chat.is_some(), "No chat selected."); if !arg1.is_empty() { - let mut draft = dc_msg_new(Viewtype::Text); - dc_msg_set_text(&mut draft, arg1_c); + let mut draft = Message::new(Viewtype::Text); + draft.set_text(arg1_c); chat::set_draft( context, sel_chat.as_ref().unwrap().get_id(), @@ -904,7 +900,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E "msginfo" => { ensure!(!arg1.is_empty(), "Argument missing."); let id = arg1.parse()?; - let res = dc_get_msg_info(context, id); + let res = message::get_msg_info(context, id); println!("{}", as_str(res)); } "listfresh" => { @@ -928,13 +924,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E ensure!(!arg1.is_empty(), "Argument missing."); let mut msg_ids = [0; 1]; msg_ids[0] = arg1.parse()?; - dc_markseen_msgs(context, msg_ids.as_mut_ptr(), 1); + message::markseen_msgs(context, msg_ids.as_mut_ptr(), 1); } "star" | "unstar" => { ensure!(!arg1.is_empty(), "Argument missing."); let mut msg_ids = [0; 1]; msg_ids[0] = arg1.parse()?; - dc_star_msgs( + message::star_msgs( context, msg_ids.as_mut_ptr(), 1, @@ -945,7 +941,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E ensure!(!arg1.is_empty(), "Argument missing."); let mut ids = [0; 1]; ids[0] = arg1.parse()?; - dc_delete_msgs(context, ids.as_mut_ptr(), 1); + message::delete_msgs(context, ids.as_mut_ptr(), 1); } "listcontacts" | "contacts" | "listverified" => { let contacts = Contact::get_all( diff --git a/src/chat.rs b/src/chat.rs index 546afc81f..76a90913e 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -11,7 +11,7 @@ use crate::dc_tools::*; use crate::error::Error; use crate::events::Event; use crate::job::*; -use crate::message::*; +use crate::message::{self, Message, MessageState}; use crate::param::*; use crate::sql::{self, Sql}; use crate::stock::StockMessage; @@ -484,7 +484,7 @@ pub fn create_by_msg_id(context: &Context, msg_id: u32) -> Result { let mut chat_id = 0; let mut send_event = false; - if let Ok(msg) = dc_msg_load_from_db(context, msg_id) { + if let Ok(msg) = Message::load_from_db(context, msg_id) { if let Ok(chat) = Chat::load_from_db(context, msg.chat_id) { if chat.id > DC_CHAT_ID_LAST_SPECIAL { chat_id = chat.id; @@ -691,13 +691,13 @@ fn prepare_msg_common(context: &Context, chat_id: u32, msg: &mut Message) -> Res // - from FILE to AUDIO/VIDEO/IMAGE // - from FILE/IMAGE to GIF */ if let Some((better_type, better_mime)) = - dc_msg_guess_msgtype_from_suffix(Path::new(&path_filename)) + message::guess_msgtype_from_suffix(Path::new(&path_filename)) { msg.type_0 = better_type; msg.param.set(Param::MimeType, better_mime); } } else if !msg.param.exists(Param::MimeType) { - if let Some((_, mime)) = dc_msg_guess_msgtype_from_suffix(Path::new(&path_filename)) { + if let Some((_, mime)) = message::guess_msgtype_from_suffix(Path::new(&path_filename)) { msg.param.set(Param::MimeType, mime); } } @@ -783,7 +783,7 @@ pub fn send_msg(context: &Context, chat_id: u32, msg: &mut Message) -> Result Result bool { let draft = get_draft_msg_id(context, chat_id); if draft != 0 { - dc_delete_msg_from_db(context, draft); + Message::delete_from_db(context, draft); return true; } false @@ -881,7 +881,7 @@ fn do_set_draft(context: &Context, chat_id: u32, msg: &mut Message) -> bool { _ => { if let Some(path_filename) = msg.param.get(Param::File) { let mut path_filename = path_filename.to_string(); - if dc_msg_is_increation(msg) && !dc_is_blobdir_path(context, &path_filename) { + if msg.is_increation() && !dc_is_blobdir_path(context, &path_filename) { return false; } if !dc_make_rel_and_copy(context, &mut path_filename) { @@ -938,7 +938,7 @@ pub fn get_draft(context: &Context, chat_id: u32) -> Result, Err if draft_msg_id == 0 { return Ok(None); } - Ok(Some(dc_msg_load_from_db(context, draft_msg_id)?)) + Ok(Some(Message::load_from_db(context, draft_msg_id)?)) } pub fn get_chat_msgs(context: &Context, chat_id: u32, flags: u32, marker1before: u32) -> Vec { @@ -1133,7 +1133,7 @@ pub unsafe fn get_next_media( ) -> u32 { let mut ret = 0; - if let Ok(msg) = dc_msg_load_from_db(context, curr_msg_id) { + if let Ok(msg) = Message::load_from_db(context, curr_msg_id) { let list = get_chat_media( context, msg.chat_id, @@ -1301,8 +1301,8 @@ pub unsafe fn create_group_chat( if chat_id != 0 { if add_to_chat_contacts_table(context, chat_id, 1) { - let mut draft_msg = dc_msg_new(Viewtype::Text); - dc_msg_set_text(&mut draft_msg, draft_txt.as_ptr()); + let mut draft_msg = Message::new(Viewtype::Text); + draft_msg.set_text(draft_txt.as_ptr()); set_draft_raw(context, chat_id, &mut draft_msg); } @@ -1347,7 +1347,7 @@ pub fn add_contact_to_chat_ex( if contact.is_err() || chat_id <= DC_CHAT_ID_LAST_SPECIAL { return false; } - let mut msg = dc_msg_new_untyped(); + let mut msg = Message::default(); reset_gossiped_timestamp(context, chat_id); let contact = contact.unwrap(); @@ -1495,7 +1495,7 @@ pub unsafe fn remove_contact_from_chat( "Cannot remove special contact" ); - let mut msg = dc_msg_new_untyped(); + let mut msg = Message::default(); let mut success = false; /* we do not check if "contact_id" exists but just delete all records with the id from chats_contacts */ @@ -1593,7 +1593,7 @@ pub unsafe fn set_chat_name( ensure!(chat_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat ID"); let chat = Chat::load_from_db(context, chat_id)?; - let mut msg = dc_msg_new_untyped(); + let mut msg = Message::default(); if real_group_exists(context, chat_id) { if &chat.name == new_name.as_ref() { @@ -1682,7 +1682,7 @@ pub fn set_chat_profile_image( chat.param.set(Param::ProfileImage, &new_image_rel); if chat.update_param(context).is_ok() { if chat.is_promoted() { - let mut msg = dc_msg_new_untyped(); + let mut msg = Message::default(); msg.param .set_int(Param::Cmd, SystemMessage::GroupImageChanged as i32); msg.type_0 = Viewtype::Text; @@ -1753,7 +1753,7 @@ pub unsafe fn forward_msgs( for id in ids { let src_msg_id = id; - let msg = dc_msg_load_from_db(context, src_msg_id as u32); + let msg = Message::load_from_db(context, src_msg_id as u32); if msg.is_err() { break; } @@ -1784,7 +1784,7 @@ pub unsafe fn forward_msgs( msg.param.set(Param::PrepForwards, new_msg_id.to_string()); } - dc_msg_save_param_to_disk(context, &mut msg); + msg.save_param_to_disk(context); msg.param = save_param; } else { msg.state = MessageState::OutPending; @@ -1910,12 +1910,12 @@ mod tests { unsafe { let t = dummy_context(); let chat_id = create_by_contact_id(&t.ctx, DC_CONTACT_ID_SELF).unwrap(); - let mut msg = dc_msg_new(Viewtype::Text); - dc_msg_set_text(&mut msg, b"hello\x00" as *const u8 as *const libc::c_char); + let mut msg = Message::new(Viewtype::Text); + msg.set_text(b"hello\x00" as *const u8 as *const libc::c_char); set_draft(&t.ctx, chat_id, Some(&mut msg)); let draft = get_draft(&t.ctx, chat_id).unwrap().unwrap(); - let msg_text = dc_msg_get_text(&msg); - let draft_text = dc_msg_get_text(&draft); + let msg_text = msg.get_text(); + let draft_text = draft.get_text(); assert_eq!(as_str(msg_text), as_str(draft_text)); } } diff --git a/src/chatlist.rs b/src/chatlist.rs index 06b027ea7..bf5e542f1 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -4,7 +4,7 @@ use crate::contact::*; use crate::context::*; use crate::error::Result; use crate::lot::Lot; -use crate::message::*; +use crate::message::Message; use crate::stock::StockMessage; /// An object representing a single chatlist in memory. @@ -271,7 +271,7 @@ impl Chatlist { let mut lastcontact = None; let lastmsg = if 0 != lastmsg_id { - if let Ok(lastmsg) = dc_msg_load_from_db(context, lastmsg_id) { + if let Ok(lastmsg) = Message::load_from_db(context, lastmsg_id) { if lastmsg.from_id != 1 as libc::c_uint && (chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup) { diff --git a/src/context.rs b/src/context.rs index 198b2f7b8..2b8da2174 100644 --- a/src/context.rs +++ b/src/context.rs @@ -16,7 +16,7 @@ use crate::job_thread::JobThread; use crate::key::*; use crate::login_param::LoginParam; use crate::lot::Lot; -use crate::message::*; +use crate::message::{self, Message}; use crate::param::Params; use crate::smtp::*; use crate::sql::Sql; @@ -144,8 +144,8 @@ impl Context { let l2 = LoginParam::from_database(self, "configured_"); let displayname = self.sql.get_config(self, "displayname"); let chats = get_chat_cnt(self) as usize; - let real_msgs = dc_get_real_msg_cnt(self) as usize; - let deaddrop_msgs = dc_get_deaddrop_msg_cnt(self) as usize; + let real_msgs = message::get_real_msg_cnt(self) as usize; + let deaddrop_msgs = message::get_deaddrop_msg_cnt(self) as usize; let contacts = Contact::get_real_cnt(self) as usize; let is_configured = self .sql @@ -354,15 +354,15 @@ impl Context { return; } - if let Ok(msg) = dc_msg_new_load(self, msg_id) { - if dc_msg_is_setupmessage(&msg) { + if let Ok(msg) = Message::load_from_db(self, msg_id) { + if msg.is_setupmessage() { // do not move setup messages; // there may be a non-delta device that wants to handle it return; } if self.is_mvbox(folder) { - dc_update_msg_move_state(self, &msg.rfc724_mid, MoveState::Stay); + message::update_msg_move_state(self, &msg.rfc724_mid, MoveState::Stay); } // 1 = dc message, 2 = reply to dc message @@ -374,7 +374,7 @@ impl Context { Params::new(), 0, ); - dc_update_msg_move_state(self, &msg.rfc724_mid, MoveState::Moving); + message::update_msg_move_state(self, &msg.rfc724_mid, MoveState::Moving); } } } diff --git a/src/dc_imex.rs b/src/dc_imex.rs index 752626f2d..33b196835 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -18,7 +18,7 @@ use crate::error::*; use crate::events::Event; use crate::job::*; use crate::key::*; -use crate::message::*; +use crate::message::Message; use crate::param::*; use crate::pgp::*; use crate::sql::{self, Sql}; @@ -127,7 +127,7 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { dc_get_fine_path_filename(context, "$BLOBDIR", "autocrypt-setup-message.html"); if dc_write_file(context, &setup_file_name, setup_file_content.as_bytes()) { if let Ok(chat_id) = chat::create_by_contact_id(context, 1) { - msg = dc_msg_new_untyped(); + msg = Message::default(); msg.type_0 = Viewtype::File; msg.param .set(Param::File, setup_file_name.to_string_lossy()); @@ -157,8 +157,8 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { break; } std::thread::sleep(std::time::Duration::from_secs(1)); - if let Ok(msg) = dc_get_msg(context, msg_id) { - if dc_msg_is_sent(&msg) { + if let Ok(msg) = Message::load_from_db(context, msg_id) { + if msg.is_sent() { info!(context, "... setup message sent.",); break; } @@ -264,18 +264,18 @@ pub unsafe fn dc_continue_key_transfer( return false; } - let msg = dc_get_msg(context, msg_id); + let msg = Message::load_from_db(context, msg_id); if msg.is_err() { error!(context, "Message is no Autocrypt Setup Message."); return false; } let msg = msg.unwrap(); - if !dc_msg_is_setupmessage(&msg) { + if !msg.is_setupmessage() { error!(context, "Message is no Autocrypt Setup Message."); return false; } - if let Some(filename) = dc_msg_get_file(context, &msg) { + if let Some(filename) = msg.get_file(context) { if let Some(buf) = dc_read_file_safe(context, filename) { norm_sc = dc_normalize_setup_code(context, setup_code); if norm_sc.is_null() { diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 330b6c8e5..72c906e4f 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -22,7 +22,7 @@ use crate::dc_tools::*; use crate::e2ee::*; use crate::error::Error; use crate::location; -use crate::message::*; +use crate::message::{self, Message}; use crate::param::*; use crate::stock::StockMessage; use crate::x::*; @@ -115,7 +115,7 @@ pub unsafe fn dc_mimefactory_load_msg( ) -> Result { ensure!(msg_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat id"); - let msg = dc_msg_load_from_db(context, msg_id)?; + let msg = Message::load_from_db(context, msg_id)?; let chat = Chat::load_from_db(context, msg.chat_id)?; let mut factory = MimeFactory::new(context, msg); factory.chat = Some(chat); @@ -239,7 +239,7 @@ pub unsafe fn dc_mimefactory_load_msg( factory.loaded = Loaded::Message; factory.timestamp = factory.msg.timestamp_sort; factory.rfc724_mid = factory.msg.rfc724_mid.clone(); - factory.increation = dc_msg_is_increation(&factory.msg); + factory.increation = factory.msg.is_increation(); Ok(factory) } @@ -285,7 +285,7 @@ pub unsafe fn dc_mimefactory_load_mdn<'a>( bail!("MDNs disabled ") } - let msg = dc_msg_load_from_db(context, msg_id)?; + let msg = Message::load_from_db(context, msg_id)?; let mut factory = MimeFactory::new(context, msg); let contact = Contact::load_from_db(factory.context, factory.msg.from_id)?; @@ -705,7 +705,7 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut MimeFactory if let Some(grpimage) = grpimage { info!(factory.context, "setting group image '{}'", grpimage); - let mut meta = dc_msg_new_untyped(); + let mut meta = Message::default(); meta.type_0 = Viewtype::Image; meta.param.set(Param::File, grpimage); @@ -917,7 +917,7 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut MimeFactory .stock_str(StockMessage::EncryptedMsg) .into_owned() } else { - to_string(dc_msg_get_summarytext(context, &mut factory.msg, 32)) + to_string(factory.msg.get_summarytext(context, 32)) }; let p2 = factory .context @@ -1040,7 +1040,7 @@ unsafe fn get_subject( let ret: *mut libc::c_char; let raw_subject = - dc_msg_get_summarytext_by_raw(msg.type_0, msg.text.as_ref(), &mut msg.param, 32, context); + message::get_summarytext_by_raw(msg.type_0, msg.text.as_ref(), &mut msg.param, 32, context); let fwd = if 0 != afwd_email { "Fwd: " } else { "" }; if msg.param.get_cmd() == SystemMessage::AutocryptSetupMessage { diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 39d2a4067..2689d2dcc 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -22,7 +22,7 @@ use crate::error::Result; use crate::events::Event; use crate::job::*; use crate::location; -use crate::message::*; +use crate::message::{self, MessageState}; use crate::param::*; use crate::peerstate::*; use crate::securejoin::handle_securejoin_handshake; @@ -354,14 +354,14 @@ unsafe fn add_parts( let mut old_server_folder = std::ptr::null_mut(); let mut old_server_uid = 0; - if 0 != dc_rfc724_mid_exists( + if 0 != message::rfc724_mid_exists( context, &rfc724_mid, &mut old_server_folder, &mut old_server_uid, ) { if as_str(old_server_folder) != server_folder.as_ref() || old_server_uid != server_uid { - dc_update_server_uid(context, &rfc724_mid, server_folder.as_ref(), server_uid); + message::update_server_uid(context, &rfc724_mid, server_folder.as_ref(), server_uid); } free(old_server_folder.cast()); @@ -840,7 +840,7 @@ unsafe fn handle_reports( let mut chat_id_0 = 0; let mut msg_id = 0; - if 0 != dc_mdn_from_ext( + if 0 != message::mdn_from_ext( context, from_id, as_str(rfc724_mid_0), diff --git a/src/imap.rs b/src/imap.rs index 4297489d6..dc0e2b8e5 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -13,7 +13,7 @@ use crate::dc_tools::*; use crate::events::Event; use crate::job::{job_add, Action}; use crate::login_param::LoginParam; -use crate::message::{dc_rfc724_mid_exists, dc_update_msg_move_state, dc_update_server_uid}; +use crate::message::{self, update_msg_move_state, update_server_uid}; use crate::oauth2::dc_get_oauth2_access_token; use crate::param::Params; @@ -1652,7 +1652,7 @@ unsafe fn precheck_imf( let mut old_server_folder: *mut libc::c_char = ptr::null_mut(); let mut old_server_uid: u32 = 0i32 as u32; let mut mark_seen: libc::c_int = 0i32; - msg_id = dc_rfc724_mid_exists( + msg_id = message::rfc724_mid_exists( context, &rfc724_mid, &mut old_server_folder, @@ -1667,10 +1667,10 @@ unsafe fn precheck_imf( mark_seen = 1i32 } else if as_str(old_server_folder) != server_folder { info!(context, "[move] detected moved message {}", rfc724_mid,); - dc_update_msg_move_state(context, &rfc724_mid, MoveState::Stay); + update_msg_move_state(context, &rfc724_mid, MoveState::Stay); } if as_str(old_server_folder) != server_folder || old_server_uid != server_uid { - dc_update_server_uid(context, &rfc724_mid, server_folder, server_uid); + update_server_uid(context, &rfc724_mid, server_folder, server_uid); } context.do_heuristics_moves(server_folder, msg_id); if 0 != mark_seen { diff --git a/src/job.rs b/src/job.rs index 13d0f87ea..3d21537ba 100644 --- a/src/job.rs +++ b/src/job.rs @@ -16,7 +16,7 @@ use crate::events::Event; use crate::imap::*; use crate::location; use crate::login_param::LoginParam; -use crate::message::*; +use crate::message::{self, Message, MessageState}; use crate::param::*; use crate::sql; use crate::x::*; @@ -156,7 +156,7 @@ impl Job { /* if there is a msg-id and it does not exist in the db, cancel sending. this happends if dc_delete_msgs() was called before the generated mime was sent out */ - if 0 != self.foreign_id && !dc_msg_exists(context, self.foreign_id) { + if 0 != self.foreign_id && !message::exists(context, self.foreign_id) { warn!( context, "Message {} for job {} does not exist", self.foreign_id, self.job_id, @@ -175,7 +175,7 @@ impl Job { } else { dc_delete_file(context, filename); if 0 != self.foreign_id { - dc_update_msg_state( + message::update_msg_state( context, self.foreign_id, MessageState::OutDelivered, @@ -226,7 +226,7 @@ impl Job { ok_to_continue = true; } if ok_to_continue { - if let Ok(msg) = dc_msg_load_from_db(context, self.foreign_id) { + if let Ok(msg) = Message::load_from_db(context, self.foreign_id) { if context .sql .get_config_int(context, "folders_configured") @@ -251,7 +251,12 @@ impl Job { self.try_again_later(3i32, None); } ImapResult::Success => { - dc_update_server_uid(context, &msg.rfc724_mid, &dest_folder, dest_uid); + message::update_server_uid( + context, + &msg.rfc724_mid, + &dest_folder, + dest_uid, + ); } ImapResult::Failed | ImapResult::AlreadyDone => {} } @@ -265,11 +270,11 @@ impl Job { let mut delete_from_server = 1; let inbox = context.inbox.read().unwrap(); - if let Ok(mut msg) = dc_msg_load_from_db(context, self.foreign_id) { + if let Ok(mut msg) = Message::load_from_db(context, self.foreign_id) { if !msg.rfc724_mid.is_empty() { let ok_to_continue1; /* eg. device messages have no Message-ID */ - if dc_rfc724_mid_cnt(context, &msg.rfc724_mid) != 1 { + if message::rfc724_mid_cnt(context, &msg.rfc724_mid) != 1 { info!( context, "The message is deleted from the server when all parts are deleted.", @@ -307,7 +312,7 @@ impl Job { ok_to_continue1 = true; } if ok_to_continue1 { - dc_delete_msg_from_db(context, msg.id); + Message::delete_from_db(context, msg.id); } } } @@ -330,7 +335,7 @@ impl Job { ok_to_continue = true; } if ok_to_continue { - if let Ok(msg) = dc_msg_load_from_db(context, self.foreign_id) { + if let Ok(msg) = Message::load_from_db(context, self.foreign_id) { let server_folder = msg.server_folder.as_ref().unwrap(); match inbox.set_seen(context, server_folder, msg.server_uid) { ImapResult::Failed => {} @@ -671,13 +676,13 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int { mimefactory.msg.param.set_int(Param::Height, height as i32); } } - dc_msg_save_param_to_disk(context, &mut mimefactory.msg); + mimefactory.msg.save_param_to_disk(context); } } } /* create message */ if !dc_mimefactory_render(context, &mut mimefactory) { - dc_set_msg_failed(context, msg_id, as_opt_str(mimefactory.error)); + message::set_msg_failed(context, msg_id, as_opt_str(mimefactory.error)); } else if 0 != mimefactory .msg @@ -692,7 +697,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int { msg_id, mimefactory.msg.param.get_int(Param::GuranteeE2ee), ); - dc_set_msg_failed( + message::set_msg_failed( context, msg_id, Some("End-to-end-encryption unavailable unexpectedly."), @@ -739,7 +744,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int { == 0 { mimefactory.msg.param.set_int(Param::GuranteeE2ee, 1); - dc_msg_save_param_to_disk(context, &mut mimefactory.msg); + mimefactory.msg.save_param_to_disk(context); } success = add_smtp_job(context, Action::SendMsgToSmtp, &mut mimefactory); } @@ -940,7 +945,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) { } } else { if job.action == Action::SendMsgToSmtp { - dc_set_msg_failed(context, job.foreign_id, job.pending_error.as_ref()); + message::set_msg_failed(context, job.foreign_id, job.pending_error.as_ref()); } job.delete(context); } diff --git a/src/location.rs b/src/location.rs index ef67d7c17..24fb582bc 100644 --- a/src/location.rs +++ b/src/location.rs @@ -9,7 +9,7 @@ use crate::dc_tools::*; use crate::error::Error; use crate::events::Event; use crate::job::*; -use crate::message::*; +use crate::message::Message; use crate::param::*; use crate::sql; use crate::stock::StockMessage; @@ -214,7 +214,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) { .is_ok() { if 0 != seconds && !is_sending_locations_before { - msg = dc_msg_new(Viewtype::Text); + msg = Message::new(Viewtype::Text); msg.text = Some(context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0)); msg.param.set_int(Param::Cmd, 8); @@ -601,7 +601,7 @@ pub fn job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: &Job) { // the easiest way to determine this, is to check for an empty message queue. // (might not be 100%, however, as positions are sent combined later // and dc_set_location() is typically called periodically, this is ok) - let mut msg = dc_msg_new(Viewtype::Text); + let mut msg = Message::new(Viewtype::Text); msg.hidden = true; msg.param.set_int(Param::Cmd, 9); Some((chat_id, msg)) diff --git a/src/message.rs b/src/message.rs index 74bfb2479..81ae17efb 100644 --- a/src/message.rs +++ b/src/message.rs @@ -24,8 +24,433 @@ use crate::x::*; /// In practice, the user additionally cuts the string himself pixel-accurate. const SUMMARY_CHARACTERS: usize = 160; -#[repr(i32)] +/// An object representing a single message in memory. +/// The message object is not updated. +/// If you want an update, you have to recreate the object. +/// +/// to check if a mail was sent, use dc_msg_is_sent() +/// approx. max. length returned by dc_msg_get_text() +/// approx. max. length returned by dc_get_msg_info() +#[derive(Debug, Clone, Default)] +pub struct Message { + pub(crate) id: u32, + pub(crate) from_id: u32, + pub(crate) to_id: u32, + pub(crate) chat_id: u32, + pub(crate) move_state: MoveState, + pub(crate) type_0: Viewtype, + pub(crate) state: MessageState, + pub(crate) hidden: bool, + pub(crate) timestamp_sort: i64, + pub(crate) timestamp_sent: i64, + pub(crate) timestamp_rcvd: i64, + pub(crate) text: Option, + pub(crate) rfc724_mid: String, + pub(crate) in_reply_to: Option, + pub(crate) server_folder: Option, + pub(crate) server_uid: u32, + // TODO: enum + pub(crate) is_dc_message: u32, + pub(crate) starred: bool, + pub(crate) chat_blocked: Blocked, + pub(crate) location_id: u32, + pub(crate) param: Params, +} + +impl Message { + pub fn new(viewtype: Viewtype) -> Self { + let mut msg = Message::default(); + msg.type_0 = viewtype; + + msg + } + + pub fn load_from_db(context: &Context, id: u32) -> Result { + context.sql.query_row( + "SELECT \ + m.id,rfc724_mid,m.mime_in_reply_to,m.server_folder,m.server_uid,m.move_state,m.chat_id, \ + m.from_id,m.to_id,m.timestamp,m.timestamp_sent,m.timestamp_rcvd, m.type,m.state,m.msgrmsg,m.txt, \ + m.param,m.starred,m.hidden,m.location_id, c.blocked \ + FROM msgs m \ + LEFT JOIN chats c ON c.id=m.chat_id WHERE m.id=?;", + params![id as i32], + |row| { + let mut msg = Message::default(); + msg.id = row.get::<_, i32>(0)? as u32; + msg.rfc724_mid = row.get::<_, String>(1)?; + msg.in_reply_to = row.get::<_, Option>(2)?; + msg.server_folder = row.get::<_, Option>(3)?; + msg.server_uid = row.get(4)?; + msg.move_state = row.get(5)?; + msg.chat_id = row.get(6)?; + msg.from_id = row.get(7)?; + msg.to_id = row.get(8)?; + msg.timestamp_sort = row.get(9)?; + msg.timestamp_sent = row.get(10)?; + msg.timestamp_rcvd = row.get(11)?; + msg.type_0 = row.get(12)?; + msg.state = row.get(13)?; + msg.is_dc_message = row.get(14)?; + + let text; + if let rusqlite::types::ValueRef::Text(buf) = row.get_raw(15) { + if let Ok(t) = String::from_utf8(buf.to_vec()) { + text = t; + } else { + warn!(context, "dc_msg_load_from_db: could not get text column as non-lossy utf8 id {}", id); + text = String::from_utf8_lossy(buf).into_owned(); + } + } else { + text = "".to_string(); + } + msg.text = Some(text); + + 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 == Blocked::Deaddrop { + if let Some(ref text) = msg.text { + unsafe { + let ptr = text.strdup(); + + dc_truncate_n_unwrap_str(ptr, 256, 0); + + msg.text = Some(to_string(ptr)); + free(ptr.cast()); + } + } + }; + Ok(msg) + }) + } + + pub fn delete_from_db(context: &Context, msg_id: u32) { + if let Ok(msg) = Message::load_from_db(context, msg_id) { + sql::execute( + context, + &context.sql, + "DELETE FROM msgs WHERE id=?;", + params![msg.id as i32], + ) + .ok(); + sql::execute( + context, + &context.sql, + "DELETE FROM msgs_mdns WHERE msg_id=?;", + params![msg.id as i32], + ) + .ok(); + } + } + + pub fn get_filemime(&self) -> String { + if let Some(m) = self.param.get(Param::MimeType) { + return m.to_string(); + } else if let Some(file) = self.param.get(Param::File) { + if let Some((_, mime)) = guess_msgtype_from_suffix(Path::new(file)) { + return mime.to_string(); + } + } + + "application/octet-stream".to_string() + } + + pub fn get_file(&self, context: &Context) -> Option { + self.param + .get(Param::File) + .map(|f| dc_get_abs_path(context, f)) + } + + /// Check if a message has a location bound to it. + /// These messages are also returned by dc_get_locations() + /// and the UI may decide to display a special icon beside such messages, + /// + /// @memberof Message + /// @param msg The message object. + /// @return 1=Message has location bound to it, 0=No location bound to message. + pub fn has_location(&self) -> bool { + self.location_id != 0 + } + + /// Set any location that should be bound to the message object. + /// The function is useful to add a marker to the map + /// at a position different from the self-location. + /// You should not call this function + /// if you want to bind the current self-location to a message; + /// this is done by dc_set_location() and dc_send_locations_to_chat(). + /// + /// Typically results in the event #DC_EVENT_LOCATION_CHANGED with + /// contact_id set to DC_CONTACT_ID_SELF. + /// + /// @param latitude North-south position of the location. + /// @param longitude East-west position of the location. + pub fn set_location(&mut self, latitude: f64, longitude: f64) { + if latitude == 0.0 && longitude == 0.0 { + return; + } + + self.param.set_float(Param::SetLatitude, latitude); + self.param.set_float(Param::SetLongitude, longitude); + } + + pub fn get_timestamp(&self) -> i64 { + if 0 != self.timestamp_sent { + self.timestamp_sent + } else { + self.timestamp_sort + } + } + + pub fn get_id(&self) -> u32 { + self.id + } + + pub fn get_from_id(&self) -> u32 { + self.from_id + } + + pub fn get_chat_id(&self) -> u32 { + if self.chat_blocked != Blocked::Not { + 1 + } else { + self.chat_id + } + } + + pub fn get_viewtype(&self) -> Viewtype { + self.type_0 + } + + pub fn get_state(&self) -> MessageState { + self.state + } + + pub fn get_received_timestamp(&self) -> i64 { + self.timestamp_rcvd + } + + pub fn get_sort_timestamp(&self) -> i64 { + self.timestamp_sort + } + + pub unsafe fn get_text(&self) -> *mut libc::c_char { + if let Some(ref text) = self.text { + dc_truncate(text, 30000, false).strdup() + } else { + ptr::null_mut() + } + } + + #[allow(non_snake_case)] + pub unsafe fn get_filename(&self) -> *mut libc::c_char { + let mut ret = ptr::null_mut(); + + if let Some(file) = self.param.get(Param::File) { + ret = dc_get_filename(file); + } + if !ret.is_null() { + ret + } else { + dc_strdup(0 as *const libc::c_char) + } + } + + pub fn get_filebytes(&self, context: &Context) -> u64 { + if let Some(file) = self.param.get(Param::File) { + return dc_get_filebytes(context, &file); + } + 0 + } + + pub fn get_width(&self) -> libc::c_int { + self.param.get_int(Param::Width).unwrap_or_default() + } + + pub fn get_height(&self) -> libc::c_int { + self.param.get_int(Param::Height).unwrap_or_default() + } + + pub fn get_duration(&self) -> libc::c_int { + self.param.get_int(Param::Duration).unwrap_or_default() + } + + pub fn get_showpadlock(&self) -> bool { + self.param.get_int(Param::GuranteeE2ee).unwrap_or_default() != 0 + } + + pub fn get_summary(&mut self, context: &Context, chat: Option<&Chat>) -> Lot { + let mut ret = Lot::new(); + + let chat_loaded: Chat; + let chat = if let Some(chat) = chat { + chat + } else { + if let Ok(chat) = Chat::load_from_db(context, self.chat_id) { + chat_loaded = chat; + &chat_loaded + } else { + return ret; + } + }; + + let contact = if self.from_id != DC_CONTACT_ID_SELF as libc::c_uint + && ((*chat).typ == Chattype::Group || (*chat).typ == Chattype::VerifiedGroup) + { + Contact::get_by_id(context, self.from_id).ok() + } else { + None + }; + + ret.fill(self, chat, contact.as_ref(), context); + + ret + } + + pub unsafe fn get_summarytext( + &mut self, + context: &Context, + approx_characters: usize, + ) -> *mut libc::c_char { + get_summarytext_by_raw( + self.type_0, + self.text.as_ref(), + &mut self.param, + approx_characters, + context, + ) + .strdup() + } + + pub unsafe fn has_deviating_timestamp(&self) -> libc::c_int { + let cnv_to_local = dc_gm2local_offset(); + let sort_timestamp = self.get_sort_timestamp() as i64 + cnv_to_local; + let send_timestamp = self.get_timestamp() as i64 + cnv_to_local; + + (sort_timestamp / 86400 != send_timestamp / 86400) as libc::c_int + } + + pub fn is_sent(&self) -> bool { + self.state as i32 >= MessageState::OutDelivered as i32 + } + + pub fn is_starred(&self) -> bool { + self.starred + } + + pub fn is_forwarded(&self) -> bool { + 0 != self.param.get_int(Param::Forwarded).unwrap_or_default() + } + + pub fn is_info(&self) -> bool { + let cmd = self.param.get_cmd(); + self.from_id == 2i32 as libc::c_uint + || self.to_id == 2i32 as libc::c_uint + || cmd != SystemMessage::Unknown && cmd != SystemMessage::AutocryptSetupMessage + } + + pub fn is_increation(&self) -> bool { + chat::msgtype_has_file(self.type_0) && self.state == MessageState::OutPreparing + } + + pub fn is_setupmessage(&self) -> bool { + if self.type_0 != Viewtype::File { + return false; + } + + self.param.get_cmd() == SystemMessage::AutocryptSetupMessage + } + + pub unsafe fn get_setupcodebegin(&self, context: &Context) -> *mut libc::c_char { + // just a pointer inside buf, MUST NOT be free()'d + let mut buf_headerline: *const libc::c_char = ptr::null(); + // just a pointer inside buf, MUST NOT be free()'d + let mut buf_setupcodebegin: *const libc::c_char = ptr::null(); + let mut ret: *mut libc::c_char = ptr::null_mut(); + if self.is_setupmessage() { + if let Some(filename) = self.get_file(context) { + if let Some(mut buf) = dc_read_file_safe(context, filename) { + if dc_split_armored_data( + buf.as_mut_ptr().cast(), + &mut buf_headerline, + &mut buf_setupcodebegin, + ptr::null_mut(), + ptr::null_mut(), + ) && 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) + } + } + } + } + if !ret.is_null() { + ret + } else { + dc_strdup(0 as *const libc::c_char) + } + } + + pub fn set_text(&mut self, text: *const libc::c_char) { + self.text = if text.is_null() { + None + } else { + Some(to_string(text)) + }; + } + + pub fn set_file(&mut self, file: *const libc::c_char, filemime: *const libc::c_char) { + if !file.is_null() { + self.param.set(Param::File, as_str(file)); + } + if !filemime.is_null() { + self.param.set(Param::MimeType, as_str(filemime)); + } + } + + pub fn set_dimension(&mut self, width: libc::c_int, height: libc::c_int) { + self.param.set_int(Param::Width, width); + self.param.set_int(Param::Height, height); + } + + pub fn set_duration(&mut self, duration: libc::c_int) { + self.param.set_int(Param::Duration, duration); + } + + pub fn latefiling_mediasize( + &mut self, + context: &Context, + width: libc::c_int, + height: libc::c_int, + duration: libc::c_int, + ) { + if width > 0 && height > 0 { + self.param.set_int(Param::Width, width); + self.param.set_int(Param::Height, height); + } + if duration > 0 { + self.param.set_int(Param::Duration, duration); + } + self.save_param_to_disk(context); + } + + pub fn save_param_to_disk(&mut self, context: &Context) -> bool { + sql::execute( + context, + &context.sql, + "UPDATE msgs SET param=? WHERE id=?;", + params![self.param.to_string(), self.id as i32], + ) + .is_ok() + } +} + #[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql)] +#[repr(i32)] pub enum MessageState { Undefined = 0, InFresh = 10, @@ -88,7 +513,7 @@ impl Lot { self.text1 = Some(context.stock_str(StockMessage::Draft).to_owned().into()); self.text1_meaning = Meaning::Text1Draft; } else if msg.from_id == DC_CONTACT_ID_SELF { - if dc_msg_is_info(msg) || chat.is_self_talk() { + if msg.is_info() || chat.is_self_talk() { self.text1 = None; self.text1_meaning = Meaning::None; } else { @@ -96,7 +521,7 @@ impl Lot { self.text1_meaning = Meaning::Text1Self; } } else if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup { - if dc_msg_is_info(msg) || contact.is_none() { + if msg.is_info() || contact.is_none() { self.text1 = None; self.text1_meaning = Meaning::None; } else { @@ -117,7 +542,7 @@ impl Lot { } } - self.text2 = Some(dc_msg_get_summarytext_by_raw( + self.text2 = Some(get_summarytext_by_raw( msg.type_0, msg.text.as_ref(), &mut msg.param, @@ -125,49 +550,15 @@ impl Lot { context, )); - self.timestamp = dc_msg_get_timestamp(msg); + self.timestamp = msg.get_timestamp(); self.state = msg.state.into(); } } -/// An object representing a single message in memory. -/// The message object is not updated. -/// If you want an update, you have to recreate the object. -/// -/// to check if a mail was sent, use dc_msg_is_sent() -/// approx. max. length returned by dc_msg_get_text() -/// approx. max. length returned by dc_get_msg_info() -#[derive(Debug, Clone)] -pub struct Message { - pub id: u32, - pub from_id: u32, - pub to_id: u32, - pub chat_id: u32, - pub move_state: MoveState, - pub type_0: Viewtype, - pub state: MessageState, - pub hidden: bool, - pub timestamp_sort: i64, - pub timestamp_sent: i64, - pub timestamp_rcvd: i64, - pub text: Option, - pub rfc724_mid: String, - pub in_reply_to: Option, - pub server_folder: Option, - pub server_uid: u32, - // TODO: enum - pub is_dc_message: u32, - pub starred: bool, - pub chat_blocked: Blocked, - pub location_id: u32, - pub param: Params, -} - -// handle messages -pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_char { +pub unsafe fn get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_char { let mut ret = String::new(); - let msg = dc_msg_load_from_db(context, msg_id); + let msg = Message::load_from_db(context, msg_id); if msg.is_err() { return ptr::null_mut(); } @@ -187,7 +578,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(rawtxt.trim(), 100000, false); - let fts = dc_timestamp_to_str(dc_msg_get_timestamp(&msg)); + let fts = dc_timestamp_to_str(msg.get_timestamp()); ret += &format!("Sent: {}", fts); let name = Contact::load_from_db(context, msg.from_id) @@ -249,7 +640,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch _ => ret += &format!("{}", msg.state), } - if dc_msg_has_location(&msg) { + if msg.has_location() { ret += ", Location sent"; } @@ -269,7 +660,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch _ => {} } - if let Some(path) = dc_msg_get_file(context, &msg) { + if let Some(path) = msg.get_file(context) { let bytes = dc_get_filebytes(context, &path); ret += &format!("\nFile: {}, {}, bytes\n", path.display(), bytes); } @@ -278,7 +669,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch ret += "Type: "; ret += &format!("{}", msg.type_0); ret += "\n"; - ret += &format!("Mimetype: {}\n", &dc_msg_get_filemime(&msg)); + ret += &format!("Mimetype: {}\n", &msg.get_filemime()); } let w = msg.param.get_int(Param::Width).unwrap_or_default(); let h = msg.param.get_int(Param::Height).unwrap_or_default(); @@ -304,49 +695,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch ret.strdup() } -pub fn dc_msg_new_untyped() -> Message { - dc_msg_new(Viewtype::Unknown) -} - -pub fn dc_msg_new(viewtype: Viewtype) -> Message { - Message { - id: 0, - from_id: 0, - to_id: 0, - chat_id: 0, - move_state: MoveState::Undefined, - type_0: viewtype, - state: MessageState::Undefined, - hidden: false, - timestamp_sort: 0, - timestamp_sent: 0, - timestamp_rcvd: 0, - text: None, - rfc724_mid: String::default(), - in_reply_to: None, - server_folder: None, - server_uid: 0, - is_dc_message: 0, - starred: false, - chat_blocked: Blocked::Not, - location_id: 0, - param: Params::new(), - } -} - -pub fn dc_msg_get_filemime(msg: &Message) -> String { - if let Some(m) = msg.param.get(Param::MimeType) { - return m.to_string(); - } else if let Some(file) = msg.param.get(Param::File) { - if let Some((_, mime)) = dc_msg_guess_msgtype_from_suffix(Path::new(file)) { - return mime.to_string(); - } - } - - "application/octet-stream".to_string() -} - -pub fn dc_msg_guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)> { +pub fn guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)> { static KNOWN: phf::Map<&'static str, (Viewtype, &'static str)> = phf_map! { "mp3" => (Viewtype::Audio, "audio/mpeg"), "aac" => (Viewtype::Audio, "audio/aac"), @@ -364,121 +713,7 @@ pub fn dc_msg_guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)> KNOWN.get(extension).map(|x| *x) } -pub unsafe fn dc_msg_get_file(context: &Context, msg: &Message) -> Option { - msg.param - .get(Param::File) - .map(|f| dc_get_abs_path(context, f)) -} - -/** - * Check if a message has a location bound to it. - * These messages are also returned by dc_get_locations() - * and the UI may decide to display a special icon beside such messages, - * - * @memberof Message - * @param msg The message object. - * @return 1=Message has location bound to it, 0=No location bound to message. - */ -pub fn dc_msg_has_location(msg: &Message) -> bool { - msg.location_id != 0 -} - -/** - * Set any location that should be bound to the message object. - * The function is useful to add a marker to the map - * at a position different from the self-location. - * You should not call this function - * if you want to bind the current self-location to a message; - * this is done by dc_set_location() and dc_send_locations_to_chat(). - * - * Typically results in the event #DC_EVENT_LOCATION_CHANGED with - * contact_id set to DC_CONTACT_ID_SELF. - * - * @memberof Message - * @param msg The message object. - * @param latitude North-south position of the location. - * @param longitude East-west position of the location. - * @return None. - */ -pub fn dc_msg_set_location(msg: &mut Message, latitude: libc::c_double, longitude: libc::c_double) { - if latitude == 0.0 && longitude == 0.0 { - return; - } - - msg.param.set_float(Param::SetLatitude, latitude); - msg.param.set_float(Param::SetLongitude, longitude); -} - -pub fn dc_msg_get_timestamp(msg: &Message) -> i64 { - if 0 != msg.timestamp_sent { - msg.timestamp_sent - } else { - msg.timestamp_sort - } -} - -pub fn dc_msg_load_from_db(context: &Context, id: u32) -> Result { - context.sql.query_row( - "SELECT \ - m.id,rfc724_mid,m.mime_in_reply_to,m.server_folder,m.server_uid,m.move_state,m.chat_id, \ - m.from_id,m.to_id,m.timestamp,m.timestamp_sent,m.timestamp_rcvd, m.type,m.state,m.msgrmsg,m.txt, \ - m.param,m.starred,m.hidden,m.location_id, c.blocked \ - FROM msgs m \ - LEFT JOIN chats c ON c.id=m.chat_id WHERE m.id=?;", - params![id as i32], - |row| { - unsafe { - let mut msg = dc_msg_new_untyped(); - msg.id = row.get::<_, i32>(0)? as u32; - msg.rfc724_mid = row.get::<_, String>(1)?; - msg.in_reply_to = row.get::<_, Option>(2)?; - msg.server_folder = row.get::<_, Option>(3)?; - msg.server_uid = row.get(4)?; - msg.move_state = row.get(5)?; - msg.chat_id = row.get(6)?; - msg.from_id = row.get(7)?; - msg.to_id = row.get(8)?; - msg.timestamp_sort = row.get(9)?; - msg.timestamp_sent = row.get(10)?; - msg.timestamp_rcvd = row.get(11)?; - msg.type_0 = row.get(12)?; - msg.state = row.get(13)?; - msg.is_dc_message = row.get(14)?; - - let text; - if let rusqlite::types::ValueRef::Text(buf) = row.get_raw(15) { - if let Ok(t) = String::from_utf8(buf.to_vec()) { - text = t; - } else { - warn!(context, "dc_msg_load_from_db: could not get text column as non-lossy utf8 id {}", id); - text = String::from_utf8_lossy(buf).into_owned(); - } - } else { - text = "".to_string(); - } - msg.text = Some(text); - - 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 == Blocked::Deaddrop { - 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(msg) - } - }) -} - -pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: u32) -> *mut libc::c_char { +pub unsafe fn get_mime_headers(context: &Context, msg_id: u32) -> *mut libc::c_char { let headers: Option = context.sql.query_get_value( context, "SELECT mime_headers FROM msgs WHERE id=?;", @@ -493,13 +728,13 @@ pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: u32) -> *mut libc:: } } -pub unsafe fn dc_delete_msgs(context: &Context, msg_ids: *const u32, msg_cnt: libc::c_int) { +pub unsafe fn delete_msgs(context: &Context, msg_ids: *const u32, msg_cnt: libc::c_int) { if msg_ids.is_null() || msg_cnt <= 0i32 { return; } let mut i: libc::c_int = 0i32; while i < msg_cnt { - dc_update_msg_chat_id(context, *msg_ids.offset(i as isize), 3i32 as u32); + update_msg_chat_id(context, *msg_ids.offset(i as isize), 3i32 as u32); job_add( context, Action::DeleteMsgOnImap, @@ -520,7 +755,7 @@ pub unsafe fn dc_delete_msgs(context: &Context, msg_ids: *const u32, msg_cnt: li }; } -fn dc_update_msg_chat_id(context: &Context, msg_id: u32, chat_id: u32) -> bool { +fn update_msg_chat_id(context: &Context, msg_id: u32, chat_id: u32) -> bool { sql::execute( context, &context.sql, @@ -530,7 +765,7 @@ fn dc_update_msg_chat_id(context: &Context, msg_id: u32, chat_id: u32) -> bool { .is_ok() } -pub fn dc_markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize) -> bool { +pub fn markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize) -> bool { if msg_ids.is_null() || msg_cnt <= 0 { return false; } @@ -563,7 +798,7 @@ pub fn dc_markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize) for (id, curr_state, curr_blocked) in msgs.into_iter() { if curr_blocked == Blocked::Not { if curr_state == MessageState::InFresh || curr_state == MessageState::InNoticed { - dc_update_msg_state(context, id, MessageState::InSeen); + update_msg_state(context, id, MessageState::InSeen); info!(context, "Seen message #{}.", id); job_add( @@ -576,7 +811,7 @@ pub fn dc_markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize) send_event = true; } } else if curr_state == MessageState::InFresh { - dc_update_msg_state(context, id, MessageState::InNoticed); + update_msg_state(context, id, MessageState::InNoticed); send_event = true; } } @@ -591,7 +826,7 @@ pub fn dc_markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize) true } -pub fn dc_update_msg_state(context: &Context, msg_id: u32, state: MessageState) -> bool { +pub fn update_msg_state(context: &Context, msg_id: u32, state: MessageState) -> bool { sql::execute( context, &context.sql, @@ -601,7 +836,7 @@ pub fn dc_update_msg_state(context: &Context, msg_id: u32, state: MessageState) .is_ok() } -pub fn dc_star_msgs( +pub fn star_msgs( context: &Context, msg_ids: *const u32, msg_cnt: libc::c_int, @@ -621,132 +856,8 @@ pub fn dc_star_msgs( .is_ok() } -pub fn dc_get_msg(context: &Context, msg_id: u32) -> Result { - dc_msg_load_from_db(context, msg_id) -} - -pub fn dc_msg_get_id(msg: &Message) -> u32 { - msg.id -} - -pub fn dc_msg_get_from_id(msg: &Message) -> u32 { - msg.from_id -} - -pub fn dc_msg_get_chat_id(msg: &Message) -> u32 { - if msg.chat_blocked != Blocked::Not { - 1 - } else { - msg.chat_id - } -} - -pub fn dc_msg_get_viewtype(msg: &Message) -> Viewtype { - msg.type_0 -} - -pub fn dc_msg_get_state(msg: &Message) -> MessageState { - msg.state -} - -pub fn dc_msg_get_received_timestamp(msg: &Message) -> i64 { - msg.timestamp_rcvd -} - -pub fn dc_msg_get_sort_timestamp(msg: &Message) -> i64 { - msg.timestamp_sort -} - -pub unsafe fn dc_msg_get_text(msg: &Message) -> *mut libc::c_char { - if let Some(ref text) = msg.text { - dc_truncate(text, 30000, false).strdup() - } else { - ptr::null_mut() - } -} - -#[allow(non_snake_case)] -pub unsafe fn dc_msg_get_filename(msg: &Message) -> *mut libc::c_char { - let mut ret = ptr::null_mut(); - - if let Some(file) = msg.param.get(Param::File) { - ret = dc_get_filename(file); - } - if !ret.is_null() { - ret - } else { - dc_strdup(0 as *const libc::c_char) - } -} - -pub fn dc_msg_get_filebytes(context: &Context, msg: &Message) -> u64 { - if let Some(file) = msg.param.get(Param::File) { - return dc_get_filebytes(context, &file); - } - 0 -} - -pub fn dc_msg_get_width(msg: &Message) -> libc::c_int { - msg.param.get_int(Param::Width).unwrap_or_default() -} - -pub fn dc_msg_get_height(msg: &Message) -> libc::c_int { - msg.param.get_int(Param::Height).unwrap_or_default() -} - -pub fn dc_msg_get_duration(msg: &Message) -> libc::c_int { - msg.param.get_int(Param::Duration).unwrap_or_default() -} - -pub fn dc_msg_get_showpadlock(msg: &Message) -> bool { - msg.param.get_int(Param::GuranteeE2ee).unwrap_or_default() != 0 -} - -pub fn dc_msg_get_summary(context: &Context, msg: &mut Message, chat: Option<&Chat>) -> Lot { - let mut ret = Lot::new(); - - let chat_loaded: Chat; - let chat = if let Some(chat) = chat { - chat - } else { - if let Ok(chat) = Chat::load_from_db(context, msg.chat_id) { - chat_loaded = chat; - &chat_loaded - } else { - return ret; - } - }; - - let contact = if msg.from_id != DC_CONTACT_ID_SELF as libc::c_uint - && ((*chat).typ == Chattype::Group || (*chat).typ == Chattype::VerifiedGroup) - { - Contact::get_by_id(context, msg.from_id).ok() - } else { - None - }; - - ret.fill(msg, chat, contact.as_ref(), context); - - ret -} - -pub unsafe fn dc_msg_get_summarytext( - context: &Context, - msg: &mut Message, - approx_characters: usize, -) -> *mut libc::c_char { - dc_msg_get_summarytext_by_raw( - msg.type_0, - msg.text.as_ref(), - &mut msg.param, - approx_characters, - context, - ) - .strdup() -} - /// Returns a summary test. -pub fn dc_msg_get_summarytext_by_raw( +pub fn get_summarytext_by_raw( viewtype: Viewtype, text: Option>, param: &mut Params, @@ -811,166 +922,14 @@ pub fn dc_msg_get_summarytext_by_raw( } } -pub unsafe fn dc_msg_has_deviating_timestamp(msg: &Message) -> libc::c_int { - let cnv_to_local = dc_gm2local_offset(); - let sort_timestamp = dc_msg_get_sort_timestamp(msg) as i64 + cnv_to_local; - let send_timestamp = dc_msg_get_timestamp(msg) as i64 + cnv_to_local; - - (sort_timestamp / 86400 != send_timestamp / 86400) as libc::c_int -} - -pub fn dc_msg_is_sent(msg: &Message) -> bool { - msg.state as i32 >= MessageState::OutDelivered as i32 -} - -pub fn dc_msg_is_starred(msg: &Message) -> bool { - msg.starred -} - -pub fn dc_msg_is_forwarded(msg: &Message) -> bool { - 0 != msg.param.get_int(Param::Forwarded).unwrap_or_default() -} - -pub fn dc_msg_is_info(msg: &Message) -> bool { - let cmd = msg.param.get_cmd(); - msg.from_id == 2i32 as libc::c_uint - || msg.to_id == 2i32 as libc::c_uint - || cmd != SystemMessage::Unknown && cmd != SystemMessage::AutocryptSetupMessage -} - -pub fn dc_msg_is_increation(msg: &Message) -> bool { - chat::msgtype_has_file(msg.type_0) && msg.state == MessageState::OutPreparing -} - -pub fn dc_msg_is_setupmessage(msg: &Message) -> bool { - if msg.type_0 != Viewtype::File { - return false; - } - - msg.param.get_cmd() == SystemMessage::AutocryptSetupMessage -} - -pub unsafe fn dc_msg_get_setupcodebegin(context: &Context, msg: &Message) -> *mut libc::c_char { - // just a pointer inside buf, MUST NOT be free()'d - let mut buf_headerline: *const libc::c_char = ptr::null(); - // just a pointer inside buf, MUST NOT be free()'d - let mut buf_setupcodebegin: *const libc::c_char = ptr::null(); - let mut ret: *mut libc::c_char = ptr::null_mut(); - if dc_msg_is_setupmessage(msg) { - if let Some(filename) = dc_msg_get_file(context, msg) { - if let Some(mut buf) = dc_read_file_safe(context, filename) { - if dc_split_armored_data( - buf.as_mut_ptr().cast(), - &mut buf_headerline, - &mut buf_setupcodebegin, - ptr::null_mut(), - ptr::null_mut(), - ) && 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) - } - } - } - } - if !ret.is_null() { - ret - } else { - dc_strdup(0 as *const libc::c_char) - } -} - -pub fn dc_msg_set_text(msg: &mut Message, text: *const libc::c_char) { - msg.text = if text.is_null() { - None - } else { - Some(to_string(text)) - }; -} - -pub fn dc_msg_set_file( - msg: &mut Message, - file: *const libc::c_char, - filemime: *const libc::c_char, -) { - if !file.is_null() { - msg.param.set(Param::File, as_str(file)); - } - if !filemime.is_null() { - msg.param.set(Param::MimeType, as_str(filemime)); - } -} - -pub fn dc_msg_set_dimension(msg: &mut Message, width: libc::c_int, height: libc::c_int) { - msg.param.set_int(Param::Width, width); - msg.param.set_int(Param::Height, height); -} - -pub fn dc_msg_set_duration(msg: &mut Message, duration: libc::c_int) { - msg.param.set_int(Param::Duration, duration); -} - -pub fn dc_msg_latefiling_mediasize( - context: &Context, - msg: &mut Message, - width: libc::c_int, - height: libc::c_int, - duration: libc::c_int, -) { - if width > 0 && height > 0 { - msg.param.set_int(Param::Width, width); - msg.param.set_int(Param::Height, height); - } - if duration > 0 { - msg.param.set_int(Param::Duration, duration); - } - dc_msg_save_param_to_disk(context, msg); -} - -pub fn dc_msg_save_param_to_disk(context: &Context, msg: &mut Message) -> bool { - sql::execute( - context, - &context.sql, - "UPDATE msgs SET param=? WHERE id=?;", - params![msg.param.to_string(), msg.id as i32], - ) - .is_ok() -} - -pub fn dc_msg_new_load(context: &Context, msg_id: u32) -> Result { - dc_msg_load_from_db(context, msg_id) -} - -pub fn dc_delete_msg_from_db(context: &Context, msg_id: u32) { - if let Ok(msg) = dc_msg_load_from_db(context, msg_id) { - sql::execute( - context, - &context.sql, - "DELETE FROM msgs WHERE id=?;", - params![msg.id as i32], - ) - .ok(); - sql::execute( - context, - &context.sql, - "DELETE FROM msgs_mdns WHERE msg_id=?;", - params![msg.id as i32], - ) - .ok(); - } -} - -/* as we do not cut inside words, this results in about 32-42 characters. -Do not use too long subjects - we add a tag after the subject which gets truncated by the clients otherwise. -It should also be very clear, the subject is _not_ the whole message. -The value is also used for CC:-summaries */ +// as we do not cut inside words, this results in about 32-42 characters. +// Do not use too long subjects - we add a tag after the subject which gets truncated by the clients otherwise. +// It should also be very clear, the subject is _not_ the whole message. +// The value is also used for CC:-summaries // Context functions to work with messages -pub fn dc_msg_exists(context: &Context, msg_id: u32) -> bool { +pub fn exists(context: &Context, msg_id: u32) -> bool { if msg_id <= DC_CHAT_ID_LAST_SPECIAL { return false; } @@ -988,7 +947,7 @@ pub fn dc_msg_exists(context: &Context, msg_id: u32) -> bool { } } -pub fn dc_update_msg_move_state(context: &Context, rfc724_mid: &str, state: MoveState) -> bool { +pub fn update_msg_move_state(context: &Context, rfc724_mid: &str, state: MoveState) -> bool { // we update the move_state for all messages belonging to a given Message-ID // so that the state stay intact when parts are deleted sql::execute( @@ -1000,8 +959,8 @@ pub fn dc_update_msg_move_state(context: &Context, rfc724_mid: &str, state: Move .is_ok() } -pub fn dc_set_msg_failed(context: &Context, msg_id: u32, error: Option>) { - if let Ok(mut msg) = dc_msg_load_from_db(context, msg_id) { +pub fn set_msg_failed(context: &Context, msg_id: u32, error: Option>) { + if let Ok(mut msg) = Message::load_from_db(context, msg_id) { if msg.state.can_fail() { msg.state = MessageState::OutFailed; } @@ -1026,8 +985,8 @@ pub fn dc_set_msg_failed(context: &Context, msg_id: u32, error: Option= soll_cnt { - dc_update_msg_state(context, *ret_msg_id, MessageState::OutMdnRcvd); + update_msg_state(context, *ret_msg_id, MessageState::OutMdnRcvd); read_by_all = 1; - } /* else wait for more receipts */ + } // else wait for more receipts } } } @@ -1123,8 +1082,8 @@ pub unsafe fn dc_mdn_from_ext( read_by_all } -/* the number of messages assigned to real chat (!=deaddrop, !=trash) */ -pub fn dc_get_real_msg_cnt(context: &Context) -> libc::c_int { +/// The number of messages assigned to real chat (!=deaddrop, !=trash) +pub fn get_real_msg_cnt(context: &Context) -> libc::c_int { match context.sql.query_row( "SELECT COUNT(*) \ FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id \ @@ -1140,7 +1099,7 @@ pub fn dc_get_real_msg_cnt(context: &Context) -> libc::c_int { } } -pub fn dc_get_deaddrop_msg_cnt(context: &Context) -> libc::size_t { +pub fn get_deaddrop_msg_cnt(context: &Context) -> libc::size_t { match context.sql.query_row( "SELECT COUNT(*) \ FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id \ @@ -1156,8 +1115,8 @@ pub fn dc_get_deaddrop_msg_cnt(context: &Context) -> libc::size_t { } } -pub fn dc_rfc724_mid_cnt(context: &Context, rfc724_mid: &str) -> libc::c_int { - /* check the number of messages with the same rfc724_mid */ +pub fn rfc724_mid_cnt(context: &Context, rfc724_mid: &str) -> libc::c_int { + // check the number of messages with the same rfc724_mid match context.sql.query_row( "SELECT COUNT(*) FROM msgs WHERE rfc724_mid=?;", &[rfc724_mid], @@ -1171,7 +1130,7 @@ pub fn dc_rfc724_mid_cnt(context: &Context, rfc724_mid: &str) -> libc::c_int { } } -pub fn dc_rfc724_mid_exists( +pub fn rfc724_mid_exists( context: &Context, rfc724_mid: &str, ret_server_folder: *mut *mut libc::c_char, @@ -1207,7 +1166,7 @@ pub fn dc_rfc724_mid_exists( } } -pub fn dc_update_server_uid( +pub fn update_server_uid( context: &Context, rfc724_mid: &str, server_folder: impl AsRef, @@ -1230,9 +1189,9 @@ mod tests { use crate::test_utils as test; #[test] - fn test_dc_msg_guess_msgtype_from_suffix() { + fn test_guess_msgtype_from_suffix() { assert_eq!( - dc_msg_guess_msgtype_from_suffix(Path::new("foo/bar-sth.mp3")), + guess_msgtype_from_suffix(Path::new("foo/bar-sth.mp3")), Some((Viewtype::Audio, "audio/mpeg")) ); } @@ -1252,10 +1211,10 @@ mod tests { let chat = chat::create_by_contact_id(ctx, contact).unwrap(); - let mut msg = dc_msg_new(Viewtype::Text); + let mut msg = Message::new(Viewtype::Text); let msg_id = chat::prepare_msg(ctx, chat, &mut msg).unwrap(); - let _msg2 = dc_get_msg(ctx, msg_id).unwrap(); + let _msg2 = Message::load_from_db(ctx, msg_id).unwrap(); } } diff --git a/src/securejoin.rs b/src/securejoin.rs index 660cb4f01..dcaf1db73 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -13,7 +13,7 @@ use crate::error::Error; use crate::events::Event; use crate::key::*; use crate::lot::LotState; -use crate::message::*; +use crate::message::Message; use crate::param::*; use crate::peerstate::*; use crate::qr::check_qr; @@ -266,7 +266,7 @@ fn send_handshake_msg( fingerprint: Option, grpid: impl AsRef, ) { - let mut msg = dc_msg_new_untyped(); + let mut msg = Message::default(); msg.type_0 = Viewtype::Text; msg.text = Some(format!("Secure-Join: {}", step)); msg.hidden = true;