refactor(chat): rust based memory management

This commit is contained in:
dignifiedquire
2019-08-14 23:36:16 +02:00
parent 64117c2964
commit ddfd067e97
12 changed files with 694 additions and 739 deletions

View File

@@ -570,7 +570,10 @@ pub unsafe extern "C" fn dc_get_chat<'a>(
assert!(!context.is_null());
let context = &*context;
chat::dc_get_chat(context, chat_id)
match chat::dc_get_chat(context, chat_id) {
Ok(chat) => Box::into_raw(Box::new(chat)),
Err(_) => std::ptr::null_mut(),
}
}
#[no_mangle]
@@ -1239,7 +1242,9 @@ pub unsafe extern "C" fn dc_chatlist_get_summary<'a>(
) -> *mut dc_lot::dc_lot_t {
assert!(!chatlist.is_null());
let chat = if chat.is_null() { None } else { Some(&*chat) };
let list = &*chatlist;
list.get_summary(index as usize, chat)
}
@@ -1262,12 +1267,13 @@ pub type dc_chat_t<'a> = chat::Chat<'a>;
pub unsafe extern "C" fn dc_chat_unref(chat: *mut dc_chat_t) {
assert!(!chat.is_null());
chat::dc_chat_unref(chat)
Box::from_raw(chat);
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_id(chat: *mut dc_chat_t) -> u32 {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_get_id(chat)
}
@@ -1275,6 +1281,7 @@ pub unsafe extern "C" fn dc_chat_get_id(chat: *mut dc_chat_t) -> u32 {
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_type(chat: *mut dc_chat_t) -> libc::c_int {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_get_type(chat) as libc::c_int
}
@@ -1282,6 +1289,7 @@ pub unsafe extern "C" fn dc_chat_get_type(chat: *mut dc_chat_t) -> libc::c_int {
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_name(chat: *mut dc_chat_t) -> *mut libc::c_char {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_get_name(chat)
}
@@ -1289,6 +1297,7 @@ pub unsafe extern "C" fn dc_chat_get_name(chat: *mut dc_chat_t) -> *mut libc::c_
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_subtitle(chat: *mut dc_chat_t) -> *mut libc::c_char {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_get_subtitle(chat)
}
@@ -1296,6 +1305,7 @@ pub unsafe extern "C" fn dc_chat_get_subtitle(chat: *mut dc_chat_t) -> *mut libc
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_profile_image(chat: *mut dc_chat_t) -> *mut libc::c_char {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_get_profile_image(chat)
}
@@ -1303,6 +1313,7 @@ pub unsafe extern "C" fn dc_chat_get_profile_image(chat: *mut dc_chat_t) -> *mut
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_color(chat: *mut dc_chat_t) -> u32 {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_get_color(chat)
}
@@ -1310,6 +1321,7 @@ pub unsafe extern "C" fn dc_chat_get_color(chat: *mut dc_chat_t) -> u32 {
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_archived(chat: *mut dc_chat_t) -> libc::c_int {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_get_archived(chat) as libc::c_int
}
@@ -1317,6 +1329,7 @@ pub unsafe extern "C" fn dc_chat_get_archived(chat: *mut dc_chat_t) -> libc::c_i
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_unpromoted(chat: *mut dc_chat_t) -> libc::c_int {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_is_unpromoted(chat)
}
@@ -1324,6 +1337,7 @@ pub unsafe extern "C" fn dc_chat_is_unpromoted(chat: *mut dc_chat_t) -> libc::c_
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_self_talk(chat: *mut dc_chat_t) -> libc::c_int {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_is_self_talk(chat)
}
@@ -1331,6 +1345,7 @@ pub unsafe extern "C" fn dc_chat_is_self_talk(chat: *mut dc_chat_t) -> libc::c_i
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_verified(chat: *mut dc_chat_t) -> libc::c_int {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_is_verified(chat)
}
@@ -1338,6 +1353,7 @@ pub unsafe extern "C" fn dc_chat_is_verified(chat: *mut dc_chat_t) -> libc::c_in
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_sending_locations(chat: *mut dc_chat_t) -> libc::c_int {
assert!(!chat.is_null());
let chat = &*chat;
chat::dc_chat_is_sending_locations(chat) as libc::c_int
}
@@ -1500,6 +1516,7 @@ pub unsafe extern "C" fn dc_msg_get_summary<'a>(
chat: *mut dc_chat_t<'a>,
) -> *mut dc_lot::dc_lot_t {
assert!(!msg.is_null());
let chat = if chat.is_null() { None } else { Some(&*chat) };
dc_msg::dc_msg_get_summary(msg, chat)
}

View File

@@ -349,16 +349,16 @@ pub unsafe fn dc_cmdline_skip_auth() {
S_IS_AUTH = 1;
}
unsafe fn chat_prefix(chat: *const Chat) -> &'static str {
(*chat).typ.into()
fn chat_prefix(chat: &Chat) -> &'static str {
chat.typ.into()
}
pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
let chat_id = *context.cmdline_sel_chat_id.read().unwrap();
let mut sel_chat = if chat_id > 0 {
dc_get_chat(context, chat_id)
dc_get_chat(context, chat_id).ok()
} else {
std::ptr::null_mut()
None
};
let mut args = line.splitn(3, ' ');
@@ -606,23 +606,23 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
);
for i in (0..cnt).rev() {
let chat = dc_get_chat(context, chatlist.get_chat_id(i));
let temp_subtitle = dc_chat_get_subtitle(chat);
let temp_name = dc_chat_get_name(chat);
let chat = dc_get_chat(context, chatlist.get_chat_id(i))?;
let temp_subtitle = dc_chat_get_subtitle(&chat);
let temp_name = dc_chat_get_name(&chat);
info!(
context,
0,
"{}#{}: {} [{}] [{} fresh]",
chat_prefix(chat),
dc_chat_get_id(chat) as libc::c_int,
chat_prefix(&chat),
dc_chat_get_id(&chat) as libc::c_int,
as_str(temp_name),
as_str(temp_subtitle),
dc_get_fresh_msg_cnt(context, dc_chat_get_id(chat)) as libc::c_int,
dc_get_fresh_msg_cnt(context, dc_chat_get_id(&chat)) as libc::c_int,
);
free(temp_subtitle as *mut libc::c_void);
free(temp_name as *mut libc::c_void);
let lot = chatlist.get_summary(i, chat);
let statestr = if dc_chat_get_archived(chat) {
let lot = chatlist.get_summary(i, Some(&chat));
let statestr = if dc_chat_get_archived(&chat) {
" [Archived]"
} else {
match dc_lot_get_state(lot) {
@@ -645,7 +645,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
to_string(text2),
statestr,
&timestr,
if dc_chat_is_sending_locations(chat) {
if dc_chat_is_sending_locations(&chat) {
"📍"
} else {
""
@@ -654,7 +654,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
free(text1 as *mut libc::c_void);
free(text2 as *mut libc::c_void);
dc_lot_unref(lot);
dc_chat_unref(chat);
info!(
context, 0,
"================================================================================"
@@ -667,20 +666,18 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
println!("{} chats", cnt);
}
"chat" => {
if sel_chat.is_null() && arg1.is_empty() {
if sel_chat.is_none() && arg1.is_empty() {
bail!("Argument [chat-id] is missing.");
}
if !sel_chat.is_null() && !arg1.is_empty() {
dc_chat_unref(sel_chat);
}
if !arg1.is_empty() {
let chat_id = arg1.parse()?;
println!("Selecting chat #{}", chat_id);
sel_chat = dc_get_chat(context, chat_id);
sel_chat = Some(dc_get_chat(context, chat_id)?);
*context.cmdline_sel_chat_id.write().unwrap() = chat_id;
}
ensure!(!sel_chat.is_null(), "Failed to select chat");
ensure!(sel_chat.is_some(), "Failed to select chat");
let sel_chat = sel_chat.as_ref().unwrap();
let msglist = dc_get_chat_msgs(context, dc_chat_get_id(sel_chat), 0x1, 0);
let temp2 = dc_chat_get_subtitle(sel_chat);
@@ -730,16 +727,10 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
"createchatbymsg" => {
ensure!(!arg1.is_empty(), "Argument <msg-id> missing");
let msg_id_0: libc::c_int = arg1.parse()?;
let chat_id_0: libc::c_int =
dc_create_chat_by_msg_id(context, msg_id_0 as uint32_t) as libc::c_int;
let chat_id_0 = dc_create_chat_by_msg_id(context, msg_id_0 as uint32_t) as libc::c_int;
if chat_id_0 != 0 {
let chat_0: *mut Chat = dc_get_chat(context, chat_id_0 as uint32_t);
println!(
"{}#{} created successfully.",
chat_prefix(chat_0),
chat_id_0,
);
dc_chat_unref(chat_0);
let chat = dc_get_chat(context, chat_id_0 as uint32_t)?;
println!("{}#{} created successfully.", chat_prefix(&chat), chat_id_0,);
} else {
bail!("");
}
@@ -763,13 +754,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
}
"addmember" => {
ensure!(!sel_chat.is_null(), "No chat selected");
ensure!(sel_chat.is_some(), "No chat selected");
ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
let contact_id_0: libc::c_int = arg1.parse()?;
if 0 != dc_add_contact_to_chat(
context,
dc_chat_get_id(sel_chat),
dc_chat_get_id(sel_chat.as_ref().unwrap()),
contact_id_0 as uint32_t,
) {
println!("Contact added to chat.");
@@ -778,12 +769,12 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
}
"removemember" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(sel_chat.is_some(), "No chat selected.");
ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
let contact_id_1: libc::c_int = arg1.parse()?;
if 0 != dc_remove_contact_from_chat(
context,
dc_chat_get_id(sel_chat),
dc_chat_get_id(sel_chat.as_ref().unwrap()),
contact_id_1 as uint32_t,
) {
println!("Contact added to chat.");
@@ -792,21 +783,21 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
}
"groupname" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(sel_chat.is_some(), "No chat selected.");
ensure!(!arg1.is_empty(), "Argument <name> missing.");
if 0 != dc_set_chat_name(context, dc_chat_get_id(sel_chat), arg1_c) {
if 0 != dc_set_chat_name(context, dc_chat_get_id(sel_chat.as_ref().unwrap()), arg1_c) {
println!("Chat name set");
} else {
bail!("Failed to set chat name");
}
}
"groupimage" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(sel_chat.is_some(), "No chat selected.");
ensure!(!arg1.is_empty(), "Argument <image> missing.");
if 0 != dc_set_chat_profile_image(
context,
dc_chat_get_id(sel_chat),
dc_chat_get_id(sel_chat.as_ref().unwrap()),
if !arg1.is_empty() {
arg1_c
} else {
@@ -819,21 +810,33 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
}
"chatinfo" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(sel_chat.is_some(), "No chat selected.");
let contacts = dc_get_chat_contacts(context, dc_chat_get_id(sel_chat));
let contacts =
dc_get_chat_contacts(context, dc_chat_get_id(sel_chat.as_ref().unwrap()));
info!(context, 0, "Memberlist:");
log_contactlist(context, &contacts);
println!(
"{} contacts\nLocation streaming: {}",
contacts.len(),
dc_is_sending_locations_to_chat(context, dc_chat_get_id(sel_chat)),
dc_is_sending_locations_to_chat(
context,
dc_chat_get_id(sel_chat.as_ref().unwrap())
),
);
}
"getlocations" => {
ensure!(sel_chat.is_some(), "No chat selected.");
let contact_id = arg1.parse().unwrap_or_default();
let locations = dc_get_locations(context, dc_chat_get_id(sel_chat), contact_id, 0, 0);
let locations = dc_get_locations(
context,
dc_chat_get_id(sel_chat.as_ref().unwrap()),
contact_id,
0,
0,
);
let default_marker = "-".to_string();
for location in &locations {
let marker = location.marker.as_ref().unwrap_or(&default_marker);
@@ -857,12 +860,16 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
}
"sendlocations" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(sel_chat.is_some(), "No chat selected.");
ensure!(!arg1.is_empty(), "No timeout given.");
let seconds = arg1.parse()?;
dc_send_locations_to_chat(context, dc_chat_get_id(sel_chat), seconds);
println!("Locations will be sent to Chat#{} for {} seconds. Use 'setlocation <lat> <lng>' to play around.", dc_chat_get_id(sel_chat), seconds);
dc_send_locations_to_chat(context, dc_chat_get_id(sel_chat.as_ref().unwrap()), seconds);
println!(
"Locations will be sent to Chat#{} for {} seconds. Use 'setlocation <lat> <lng>' to play around.",
dc_chat_get_id(sel_chat.as_ref().unwrap()),
seconds
);
}
"setlocation" => {
ensure!(
@@ -883,27 +890,31 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
dc_delete_all_locations(context);
}
"send" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(sel_chat.is_some(), "No chat selected.");
ensure!(!arg1.is_empty(), "No message text given.");
let msg = format!("{} {}", arg1, arg2);
if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg) {
if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat.as_ref().unwrap()), msg) {
println!("Message sent.");
} else {
bail!("Sending failed.");
}
}
"sendempty" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), "".into()) {
ensure!(sel_chat.is_some(), "No chat selected.");
if 0 != dc_send_text_msg(
context,
dc_chat_get_id(sel_chat.as_ref().unwrap()),
"".into(),
) {
println!("Message sent.");
} else {
bail!("Sending failed.");
}
}
"sendimage" | "sendfile" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(sel_chat.is_some(), "No chat selected.");
ensure!(!arg1.is_empty() && !arg2.is_empty(), "No file given.");
let msg_0 = dc_msg_new(
@@ -916,13 +927,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
);
dc_msg_set_file(msg_0, arg1_c, 0 as *const libc::c_char);
dc_msg_set_text(msg_0, arg2_c);
dc_send_msg(context, dc_chat_get_id(sel_chat), msg_0);
dc_send_msg(context, dc_chat_get_id(sel_chat.as_ref().unwrap()), msg_0);
dc_msg_unref(msg_0);
}
"listmsgs" => {
ensure!(!arg1.is_empty(), "Argument <query> missing.");
let chat = if !sel_chat.is_null() {
let chat = if let Some(ref sel_chat) = sel_chat {
dc_chat_get_id(sel_chat)
} else {
0 as libc::c_uint
@@ -937,25 +948,29 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
}
"draft" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(sel_chat.is_some(), "No chat selected.");
if !arg1.is_empty() {
let draft_0 = dc_msg_new(context, Viewtype::Text);
dc_msg_set_text(draft_0, arg1_c);
dc_set_draft(context, dc_chat_get_id(sel_chat), draft_0);
dc_set_draft(context, dc_chat_get_id(sel_chat.as_ref().unwrap()), draft_0);
dc_msg_unref(draft_0);
println!("Draft saved.");
} else {
dc_set_draft(context, dc_chat_get_id(sel_chat), 0 as *mut dc_msg_t);
dc_set_draft(
context,
dc_chat_get_id(sel_chat.as_ref().unwrap()),
0 as *mut dc_msg_t,
);
println!("Draft deleted.");
}
}
"listmedia" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(sel_chat.is_some(), "No chat selected.");
let images = dc_get_chat_media(
context,
dc_chat_get_id(sel_chat),
dc_chat_get_id(sel_chat.as_ref().unwrap()),
Viewtype::Image,
Viewtype::Gif,
Viewtype::Video,
@@ -1076,9 +1091,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
if 0 != i {
res += ", ";
}
let chat = dc_get_chat(context, chatlist.get_chat_id(i));
res += &format!("{}#{}", chat_prefix(chat), dc_chat_get_id(chat));
dc_chat_unref(chat);
let chat = dc_get_chat(context, chatlist.get_chat_id(i))?;
res += &format!("{}#{}", chat_prefix(&chat), dc_chat_get_id(&chat));
}
}
@@ -1124,10 +1138,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
_ => bail!("Unknown command: \"{}\" type ? for help.", arg0),
}
if !sel_chat.is_null() {
dc_chat_unref(sel_chat);
}
free(arg1_c as *mut _);
free(arg2_c as *mut _);

View File

@@ -103,7 +103,7 @@ fn main() {
let chats = Chatlist::try_load(&ctx, 0, None, None).unwrap();
for i in 0..chats.len() {
let summary = chats.get_summary(0, std::ptr::null_mut());
let summary = chats.get_summary(0, None);
let text1 = dc_lot_get_text1(summary);
let text2 = dc_lot_get_text2(summary);

File diff suppressed because it is too large Load Diff

View File

@@ -249,7 +249,7 @@ impl<'a> Chatlist<'a> {
/// - dc_lot_t::timestamp: the timestamp of the message. 0 if not applicable.
/// - dc_lot_t::state: The state of the message as one of the DC_STATE_* constants (see #dc_msg_get_state()).
// 0 if not applicable.
pub unsafe fn get_summary(&self, index: usize, mut chat: *mut Chat<'a>) -> *mut dc_lot_t {
pub unsafe fn get_summary(&self, index: usize, chat: Option<&Chat<'a>>) -> *mut dc_lot_t {
// The summary is created by the chat, not by the last message.
// This is because we may want to display drafts here or stuff as
// "is typing".
@@ -261,26 +261,27 @@ impl<'a> Chatlist<'a> {
return ret;
}
let lastmsg_id = self.ids[index].1;
let mut lastcontact = None;
if chat.is_null() {
chat = dc_chat_new(self.context);
let chat_to_delete = chat;
if !dc_chat_load_from_db(chat, self.ids[index].0) {
(*ret).text2 = "ErrCannotReadChat".strdup();
dc_chat_unref(chat_to_delete);
let chat_loaded: Chat;
let chat = if let Some(chat) = chat {
chat
} else {
if let Ok(chat) = dc_get_chat(self.context, self.ids[index].0) {
chat_loaded = chat;
&chat_loaded
} else {
return ret;
}
}
};
let lastmsg_id = self.ids[index].1;
let mut lastcontact = None;
let lastmsg = if 0 != lastmsg_id {
let lastmsg = dc_msg_new_untyped(self.context);
dc_msg_load_from_db(lastmsg, self.context, lastmsg_id);
if (*lastmsg).from_id != 1 as libc::c_uint
&& ((*chat).typ == Chattype::Group || (*chat).typ == Chattype::VerifiedGroup)
&& (chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup)
{
lastcontact = Contact::load_from_db(self.context, (*lastmsg).from_id).ok();
}
@@ -289,7 +290,7 @@ impl<'a> Chatlist<'a> {
std::ptr::null_mut()
};
if (*chat).id == DC_CHAT_ID_ARCHIVED_LINK as u32 {
if chat.id == DC_CHAT_ID_ARCHIVED_LINK as u32 {
(*ret).text2 = dc_strdup(ptr::null())
} else if lastmsg.is_null() || (*lastmsg).from_id == DC_CONTACT_ID_UNDEFINED as u32 {
(*ret).text2 = self.context.stock_str(StockMessage::NoMessages).strdup();

View File

@@ -565,7 +565,7 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
dc_msg_unref(msg);
}
unsafe fn dc_send_mdn(context: &Context, msg_id: uint32_t) {
let mut mimefactory: dc_mimefactory_t = dc_mimefactory_t {
let mut mimefactory = dc_mimefactory_t {
from_addr: ptr::null_mut(),
from_displayname: ptr::null_mut(),
selfstatus: ptr::null_mut(),
@@ -575,7 +575,7 @@ unsafe fn dc_send_mdn(context: &Context, msg_id: uint32_t) {
rfc724_mid: ptr::null_mut(),
loaded: DC_MF_NOTHING_LOADED,
msg: ptr::null_mut(),
chat: ptr::null_mut(),
chat: None,
increation: 0,
in_reply_to: ptr::null_mut(),
references: ptr::null_mut(),
@@ -587,7 +587,7 @@ unsafe fn dc_send_mdn(context: &Context, msg_id: uint32_t) {
error: ptr::null_mut(),
context,
};
dc_mimefactory_init(&mut mimefactory, context);
if !(0 == dc_mimefactory_load_mdn(&mut mimefactory, msg_id)
|| 0 == dc_mimefactory_render(&mut mimefactory))
{
@@ -1014,7 +1014,7 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in
rfc724_mid: 0 as *mut libc::c_char,
loaded: DC_MF_NOTHING_LOADED,
msg: 0 as *mut dc_msg_t,
chat: 0 as *mut Chat,
chat: None,
increation: 0,
in_reply_to: 0 as *mut libc::c_char,
references: 0 as *mut libc::c_char,
@@ -1026,7 +1026,7 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in
error: 0 as *mut libc::c_char,
context,
};
dc_mimefactory_init(&mut mimefactory, context);
/* load message data */
if 0 == dc_mimefactory_load_msg(&mut mimefactory, msg_id) || mimefactory.from_addr.is_null() {
warn!(

View File

@@ -124,7 +124,7 @@ pub unsafe fn dc_lot_get_timestamp(lot: *const dc_lot_t) -> i64 {
pub unsafe fn dc_lot_fill(
mut lot: *mut dc_lot_t,
msg: *mut dc_msg_t,
chat: *const Chat,
chat: &Chat,
contact: Option<&Contact>,
context: &Context,
) {
@@ -142,15 +142,12 @@ pub unsafe fn dc_lot_fill(
(*lot).text1 = context.stock_str(StockMessage::SelfMsg).strdup();
(*lot).text1_meaning = 3i32
}
} else if chat.is_null() {
(*lot).text1 = 0 as *mut libc::c_char;
(*lot).text1_meaning = 0i32
} else if (*chat).typ == Chattype::Group || (*chat).typ == Chattype::VerifiedGroup {
} else if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup {
if 0 != dc_msg_is_info(msg) || contact.is_none() {
(*lot).text1 = 0 as *mut libc::c_char;
(*lot).text1_meaning = 0i32
} else {
if !chat.is_null() && (*chat).id == 1i32 as libc::c_uint {
if chat.id == 1 {
if let Some(contact) = contact {
(*lot).text1 = contact.get_display_name().strdup();
} else {

View File

@@ -24,8 +24,7 @@ use crate::stock::StockMessage;
use crate::types::*;
use crate::x::*;
#[derive(Copy, Clone)]
#[repr(C)]
#[derive(Clone)]
#[allow(non_camel_case_types)]
pub struct dc_mimefactory_t<'a> {
pub from_addr: *mut libc::c_char,
@@ -37,7 +36,7 @@ pub struct dc_mimefactory_t<'a> {
pub rfc724_mid: *mut libc::c_char,
pub loaded: dc_mimefactory_loaded_t,
pub msg: *mut dc_msg_t<'a>,
pub chat: *mut Chat<'a>,
pub chat: Option<Chat<'a>>,
pub increation: libc::c_int,
pub in_reply_to: *mut libc::c_char,
pub references: *mut libc::c_char,
@@ -56,18 +55,6 @@ const DC_MF_MDN_LOADED: dc_mimefactory_loaded_t = 2;
pub const DC_MF_MSG_LOADED: dc_mimefactory_loaded_t = 1;
pub const DC_MF_NOTHING_LOADED: dc_mimefactory_loaded_t = 0;
pub unsafe fn dc_mimefactory_init<'a>(factory: *mut dc_mimefactory_t<'a>, context: &'a Context) {
if factory.is_null() {
return;
}
memset(
factory as *mut libc::c_void,
0,
::std::mem::size_of::<dc_mimefactory_t>(),
);
(*factory).context = context;
}
pub unsafe fn dc_mimefactory_empty(mut factory: *mut dc_mimefactory_t) {
if factory.is_null() {
return;
@@ -92,8 +79,7 @@ pub unsafe fn dc_mimefactory_empty(mut factory: *mut dc_mimefactory_t) {
}
dc_msg_unref((*factory).msg);
(*factory).msg = 0 as *mut dc_msg_t;
dc_chat_unref((*factory).chat);
(*factory).chat = 0 as *mut Chat;
(*factory).chat = None;
free((*factory).in_reply_to as *mut libc::c_void);
(*factory).in_reply_to = 0 as *mut libc::c_char;
free((*factory).references as *mut libc::c_void);
@@ -124,131 +110,139 @@ pub unsafe fn dc_mimefactory_load_msg(
(*factory).recipients_names = clist_new();
(*factory).recipients_addr = clist_new();
(*factory).msg = dc_msg_new_untyped(context);
(*factory).chat = dc_chat_new(context);
if dc_msg_load_from_db((*factory).msg, context, msg_id)
&& dc_chat_load_from_db((*factory).chat, (*(*factory).msg).chat_id)
{
load_from(factory);
(*factory).req_mdn = 0;
if 0 != dc_chat_is_self_talk((*factory).chat) {
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
dc_strdup_keep_null((*factory).from_displayname) as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
dc_strdup((*factory).from_addr) as *mut libc::c_void,
);
} else {
context
.sql
.query_map(
"SELECT c.authname, c.addr \
FROM chats_contacts cc \
LEFT JOIN contacts c ON cc.contact_id=c.id \
WHERE cc.chat_id=? AND cc.contact_id>9;",
params![(*(*factory).msg).chat_id as i32],
|row| {
let authname: String = row.get(0)?;
let addr: String = row.get(1)?;
Ok((authname, addr))
},
|rows| {
for row in rows {
let (authname, addr) = row?;
let addr_c = addr.strdup();
if clist_search_string_nocase((*factory).recipients_addr, addr_c) == 0 {
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
if !authname.is_empty() {
authname.strdup()
} else {
std::ptr::null_mut()
} as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
addr_c as *mut libc::c_void,
);
}
}
Ok(())
},
)
.unwrap();
let command = (*(*factory).msg)
.param
.get_int(Param::Cmd)
.unwrap_or_default();
if dc_msg_load_from_db((*factory).msg, context, msg_id) {
if let Ok(chat) = dc_chat_load_from_db(context, (*(*factory).msg).chat_id) {
(*factory).chat = Some(chat);
if command == 5 {
let email_to_remove = (*(*factory).msg).param.get(Param::Arg).unwrap_or_default();
let email_to_remove_c = email_to_remove.strdup();
let chat = (*factory).chat.as_ref().unwrap();
let self_addr = context
load_from(factory);
(*factory).req_mdn = 0;
if 0 != dc_chat_is_self_talk(chat) {
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
dc_strdup_keep_null((*factory).from_displayname) as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
dc_strdup((*factory).from_addr) as *mut libc::c_void,
);
} else {
context
.sql
.get_config(context, "configured_addr")
.query_map(
"SELECT c.authname, c.addr \
FROM chats_contacts cc \
LEFT JOIN contacts c ON cc.contact_id=c.id \
WHERE cc.chat_id=? AND cc.contact_id>9;",
params![(*(*factory).msg).chat_id as i32],
|row| {
let authname: String = row.get(0)?;
let addr: String = row.get(1)?;
Ok((authname, addr))
},
|rows| {
for row in rows {
let (authname, addr) = row?;
let addr_c = addr.strdup();
if clist_search_string_nocase((*factory).recipients_addr, addr_c)
== 0
{
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
if !authname.is_empty() {
authname.strdup()
} else {
std::ptr::null_mut()
}
as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
addr_c as *mut libc::c_void,
);
}
}
Ok(())
},
)
.unwrap();
let command = (*(*factory).msg)
.param
.get_int(Param::Cmd)
.unwrap_or_default();
if !email_to_remove.is_empty() && email_to_remove != self_addr {
if clist_search_string_nocase((*factory).recipients_addr, email_to_remove_c)
== 0
{
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
0 as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
email_to_remove_c as *mut libc::c_void,
);
if command == 5 {
let email_to_remove =
(*(*factory).msg).param.get(Param::Arg).unwrap_or_default();
let email_to_remove_c = email_to_remove.strdup();
let self_addr = context
.sql
.get_config(context, "configured_addr")
.unwrap_or_default();
if !email_to_remove.is_empty() && email_to_remove != self_addr {
if clist_search_string_nocase((*factory).recipients_addr, email_to_remove_c)
== 0
{
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
0 as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
email_to_remove_c as *mut libc::c_void,
);
}
}
}
if command != 6
&& command != 7
&& 0 != context
.sql
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1)
{
(*factory).req_mdn = 1
}
}
if command != 6
&& command != 7
&& 0 != context
.sql
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1)
{
(*factory).req_mdn = 1
}
}
let row = context.sql.query_row(
"SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?",
params![(*(*factory).msg).id as i32],
|row| {
let in_reply_to: String = row.get(0)?;
let references: String = row.get(1)?;
let row = context.sql.query_row(
"SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?",
params![(*(*factory).msg).id as i32],
|row| {
let in_reply_to: String = row.get(0)?;
let references: String = row.get(1)?;
Ok((in_reply_to, references))
},
);
match row {
Ok((in_reply_to, references)) => {
(*factory).in_reply_to = in_reply_to.strdup();
(*factory).references = references.strdup();
Ok((in_reply_to, references))
},
);
match row {
Ok((in_reply_to, references)) => {
(*factory).in_reply_to = in_reply_to.strdup();
(*factory).references = references.strdup();
}
Err(err) => {
error!(
context,
0, "mimefactory: failed to load mime_in_reply_to: {:?}", err
);
}
}
Err(err) => {
error!(
context,
0, "mimefactory: failed to load mime_in_reply_to: {:?}", err
);
}
}
success = 1;
(*factory).loaded = DC_MF_MSG_LOADED;
(*factory).timestamp = (*(*factory).msg).timestamp_sort;
(*factory).rfc724_mid = dc_strdup((*(*factory).msg).rfc724_mid)
success = 1;
(*factory).loaded = DC_MF_MSG_LOADED;
(*factory).timestamp = (*(*factory).msg).timestamp_sort;
(*factory).rfc724_mid = dc_strdup((*(*factory).msg).rfc724_mid)
}
}
if 0 != success {
(*factory).increation = dc_msg_is_increation((*factory).msg)
@@ -514,11 +508,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
if (*factory).loaded as libc::c_uint == DC_MF_MSG_LOADED as libc::c_int as libc::c_uint {
/* Render a normal message
*********************************************************************/
let chat: *mut Chat = (*factory).chat;
let msg: *mut dc_msg_t = (*factory).msg;
let chat = (*factory).chat.as_ref().unwrap();
let msg = (*factory).msg;
let mut meta_part: *mut mailmime = 0 as *mut mailmime;
let mut placeholdertext: *mut libc::c_char = 0 as *mut libc::c_char;
if (*chat).typ == Chattype::VerifiedGroup {
if chat.typ == Chattype::VerifiedGroup {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -541,27 +535,27 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
.unwrap_or_default()
}
}
if (*chat).gossiped_timestamp == 0
|| ((*chat).gossiped_timestamp + (2 * 24 * 60 * 60)) < time()
if chat.gossiped_timestamp == 0
|| (chat.gossiped_timestamp + (2 * 24 * 60 * 60)) < time()
{
do_gossip = 1
}
/* build header etc. */
let command = (*msg).param.get_int(Param::Cmd).unwrap_or_default();
if (*chat).typ == Chattype::Group || (*chat).typ == Chattype::VerifiedGroup {
if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
strdup(b"Chat-Group-ID\x00" as *const u8 as *const libc::c_char),
dc_strdup((*chat).grpid),
dc_strdup(chat.grpid),
),
);
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
strdup(b"Chat-Group-Name\x00" as *const u8 as *const libc::c_char),
dc_encode_header_words((*chat).name),
dc_encode_header_words(chat.name),
),
);
if command == 5 {
@@ -592,7 +586,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
email_to_add,
),
);
grpimage = (*chat).param.get(Param::ProfileImage);
grpimage = chat.param.get(Param::ProfileImage);
}
if 0 != (*msg).param.get_int(Param::Arg2).unwrap_or_default() & 0x1 {
info!(
@@ -998,7 +992,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
e.as_ptr(),
);
} else {
subject_str = get_subject((*factory).chat, (*factory).msg, afwd_email)
subject_str = get_subject((*factory).chat.as_ref(), (*factory).msg, afwd_email)
}
subject = mailimf_subject_new(dc_encode_header_words(subject_str));
mailimf_fields_add(
@@ -1052,6 +1046,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
success = 1
}
}
if !message.is_null() {
mailmime_free(message);
}
@@ -1064,11 +1059,16 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
}
unsafe fn get_subject(
chat: *const Chat,
chat: Option<&Chat>,
msg: *mut dc_msg_t,
afwd_email: libc::c_int,
) -> *mut libc::c_char {
let context = (*chat).context;
if chat.is_none() {
return std::ptr::null_mut();
}
let chat = chat.unwrap();
let context = chat.context;
let ret: *mut libc::c_char;
let raw_subject = {
@@ -1089,10 +1089,10 @@ unsafe fn get_subject(
};
if (*msg).param.get_int(Param::Cmd).unwrap_or_default() == 6 {
ret = context.stock_str(StockMessage::AcSetupMsgSubject).strdup()
} else if (*chat).typ == Chattype::Group || (*chat).typ == Chattype::VerifiedGroup {
} else if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup {
ret = dc_mprintf(
b"Chat: %s: %s%s\x00" as *const u8 as *const libc::c_char,
(*chat).name,
chat.name,
fwd,
raw_subject,
)

View File

@@ -745,35 +745,35 @@ pub unsafe fn dc_msg_get_showpadlock(msg: *const dc_msg_t) -> libc::c_int {
pub unsafe fn dc_msg_get_summary<'a>(
msg: *mut dc_msg_t<'a>,
mut chat: *const Chat<'a>,
chat: Option<&Chat<'a>>,
) -> *mut dc_lot_t {
let mut ok_to_continue = true;
let ret: *mut dc_lot_t = dc_lot_new();
let mut chat_to_delete: *mut Chat = 0 as *mut Chat;
let ret = dc_lot_new();
if !msg.is_null() {
if chat.is_null() {
chat_to_delete = dc_get_chat((*msg).context, (*msg).chat_id);
if chat_to_delete.is_null() {
ok_to_continue = false;
} else {
chat = chat_to_delete;
}
}
if ok_to_continue {
let contact = if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint
&& ((*chat).typ == Chattype::Group || (*chat).typ == Chattype::VerifiedGroup)
{
Contact::get_by_id((*chat).context, (*msg).from_id).ok()
} else {
None
};
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
}
if msg.is_null() {
return ret;
}
dc_chat_unref(chat_to_delete);
let chat_loaded: Chat;
let chat = if let Some(chat) = chat {
chat
} else {
if let Ok(chat) = dc_get_chat((*msg).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((*chat).context, (*msg).from_id).ok()
} else {
None
};
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
ret
}

View File

@@ -1375,7 +1375,6 @@ unsafe fn create_or_lookup_group(
}
}
if 0 != ok {
let chat = dc_chat_new(context);
info!(
context,
0,
@@ -1386,16 +1385,17 @@ unsafe fn create_or_lookup_group(
to_string(grpimage)
},
);
dc_chat_load_from_db(chat, chat_id);
if grpimage.is_null() {
(*chat).param.remove(Param::ProfileImage);
} else {
(*chat).param.set(Param::ProfileImage, as_str(grpimage));
if let Ok(mut chat) = dc_chat_load_from_db(context, chat_id) {
if grpimage.is_null() {
chat.param.remove(Param::ProfileImage);
} else {
chat.param.set(Param::ProfileImage, as_str(grpimage));
}
dc_chat_update_param(&mut chat);
send_EVENT_CHAT_MODIFIED = 1;
}
dc_chat_update_param(chat);
dc_chat_unref(chat);
free(grpimage as *mut libc::c_void);
send_EVENT_CHAT_MODIFIED = 1
}
}

View File

@@ -36,7 +36,6 @@ pub unsafe fn dc_get_securejoin_qr(
let mut fingerprint = 0 as *mut libc::c_char;
let mut invitenumber: *mut libc::c_char;
let mut auth: *mut libc::c_char;
let mut chat = 0 as *mut Chat;
let mut group_name = 0 as *mut libc::c_char;
let mut group_name_urlencoded = 0 as *mut libc::c_char;
let mut qr: Option<String> = None;
@@ -54,11 +53,10 @@ pub unsafe fn dc_get_securejoin_qr(
}
let self_addr = context.sql.get_config(context, "configured_addr");
let cleanup = |fingerprint, chat, group_name, group_name_urlencoded| {
let cleanup = |fingerprint, group_name, group_name_urlencoded| {
free(fingerprint as *mut libc::c_void);
free(invitenumber as *mut libc::c_void);
free(auth as *mut libc::c_void);
dc_chat_unref(chat);
free(group_name as *mut libc::c_void);
free(group_name_urlencoded as *mut libc::c_void);
@@ -71,7 +69,7 @@ pub unsafe fn dc_get_securejoin_qr(
if self_addr.is_none() {
error!(context, 0, "Not configured, cannot generate QR code.",);
return cleanup(fingerprint, chat, group_name, group_name_urlencoded);
return cleanup(fingerprint, group_name, group_name_urlencoded);
}
let self_addr = self_addr.unwrap();
@@ -83,34 +81,33 @@ pub unsafe fn dc_get_securejoin_qr(
fingerprint = get_self_fingerprint(context);
if fingerprint.is_null() {
return cleanup(fingerprint, chat, group_name, group_name_urlencoded);
return cleanup(fingerprint, group_name, group_name_urlencoded);
}
let self_addr_urlencoded = utf8_percent_encode(&self_addr, NON_ALPHANUMERIC).to_string();
let self_name_urlencoded = utf8_percent_encode(&self_name, NON_ALPHANUMERIC).to_string();
qr = if 0 != group_chat_id {
chat = dc_get_chat(context, group_chat_id);
if chat.is_null() {
if let Ok(chat) = dc_get_chat(context, group_chat_id) {
group_name = dc_chat_get_name(&chat);
group_name_urlencoded = dc_urlencode(group_name);
Some(format!(
"OPENPGP4FPR:{}#a={}&g={}&x={}&i={}&s={}",
as_str(fingerprint),
self_addr_urlencoded,
as_str(group_name_urlencoded),
as_str(chat.grpid),
as_str(invitenumber),
as_str(auth),
))
} else {
error!(
context,
0, "Cannot get QR-code for chat-id {}", group_chat_id,
);
return cleanup(fingerprint, chat, group_name, group_name_urlencoded);
return cleanup(fingerprint, group_name, group_name_urlencoded);
}
group_name = dc_chat_get_name(chat);
group_name_urlencoded = dc_urlencode(group_name);
Some(format!(
"OPENPGP4FPR:{}#a={}&g={}&x={}&i={}&s={}",
as_str(fingerprint),
self_addr_urlencoded,
as_str(group_name_urlencoded),
as_str((*chat).grpid),
as_str(invitenumber),
as_str(auth),
))
} else {
Some(format!(
"OPENPGP4FPR:{}#a={}&n={}&i={}&s={}",
@@ -124,7 +121,7 @@ pub unsafe fn dc_get_securejoin_qr(
info!(context, 0, "Generated QR code: {}", qr.as_ref().unwrap());
cleanup(fingerprint, chat, group_name, group_name_urlencoded)
cleanup(fingerprint, group_name, group_name_urlencoded)
}
fn get_self_fingerprint(context: &Context) -> *mut libc::c_char {

View File

@@ -767,15 +767,13 @@ fn test_chat() {
let chat_id = dc_create_chat_by_contact_id(&context.ctx, contact1);
assert!(chat_id > 9, "chat_id too small {}", chat_id);
let chat = dc_chat_new(&context.ctx);
assert!(dc_chat_load_from_db(chat, chat_id));
let chat = dc_chat_load_from_db(&context.ctx, chat_id).unwrap();
let chat2_id = dc_create_chat_by_contact_id(&context.ctx, contact1);
assert_eq!(chat2_id, chat_id);
let chat2 = dc_chat_new(&context.ctx);
assert!(dc_chat_load_from_db(chat2, chat2_id));
let chat2 = dc_chat_load_from_db(&context.ctx, chat2_id).unwrap();
assert_eq!(as_str((*chat2).name), as_str((*chat).name));
assert_eq!(as_str(chat2.name), as_str(chat.name));
}
}