Merge branch 'master' into remove_gotos_dc_msg

This commit is contained in:
Jikstra
2019-08-09 15:36:58 +02:00
committed by GitHub
52 changed files with 4214 additions and 4055 deletions

341
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -35,14 +35,16 @@ failure_derive = "0.1.5"
rustyline = "4.1.0" rustyline = "4.1.0"
lazy_static = "1.3.0" lazy_static = "1.3.0"
regex = "1.1.6" regex = "1.1.6"
rusqlite = { version = "0.19", features = ["bundled"] } rusqlite = { version = "0.20", features = ["bundled"] }
addr = "0.2.0" addr = "0.2.0"
r2d2_sqlite = "0.11.0" r2d2_sqlite = "0.12.0"
r2d2 = "0.8.5" r2d2 = "0.8.5"
strum = "0.15.0" strum = "0.15.0"
strum_macros = "0.15.0" strum_macros = "0.15.0"
thread-local-object = "0.1.0" thread-local-object = "0.1.0"
backtrace = "0.3.33" backtrace = "0.3.33"
byteorder = "1.3.1"
itertools = "0.8.0"
[dev-dependencies] [dev-dependencies]
tempfile = "3.0" tempfile = "3.0"
@@ -54,10 +56,6 @@ members = [
"deltachat-ffi" "deltachat-ffi"
] ]
[patch.crates-io]
rusqlite = { git = "http://github.com/dignifiedquire/rusqlite", branch = "fix/text", features = ["bundled"] }
[[example]] [[example]]
name = "simple" name = "simple"
path = "examples/simple.rs" path = "examples/simple.rs"

View File

@@ -63,6 +63,11 @@ Single#10: yourfriends@email.org [yourfriends@email.org]
Message sent. Message sent.
``` ```
If `yourfriend@email.org` uses DeltaChat, but does not receive message just
sent, it is advisable to check `Spam` folder. It is known that at least
`gmx.com` treat such test messages as spam, unless told otherwise with web
interface.
List messages when inside a chat: List messages when inside a chat:
``` ```

View File

@@ -4,6 +4,7 @@ set -ex
export RUST_TEST_THREADS=1 export RUST_TEST_THREADS=1
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
export RUSTFLAGS='--deny warnings'
export OPT="--target=$TARGET" export OPT="--target=$TARGET"
export OPT_RELEASE="--release ${OPT}" export OPT_RELEASE="--release ${OPT}"
export OPT_FFI_RELEASE="--manifest-path=deltachat-ffi/Cargo.toml --release" export OPT_FFI_RELEASE="--manifest-path=deltachat-ffi/Cargo.toml --release"

View File

@@ -18,6 +18,7 @@ crate-type = ["cdylib", "staticlib"]
deltachat = { path = "../", default-features = false } deltachat = { path = "../", default-features = false }
libc = "0.2" libc = "0.2"
human-panic = "1.0.1" human-panic = "1.0.1"
num-traits = "0.2.6"
[features] [features]
default = ["vendored", "nightly", "ringbuf"] default = ["vendored", "nightly", "ringbuf"]

File diff suppressed because it is too large Load Diff

View File

@@ -4,11 +4,11 @@ use std::str::FromStr;
use deltachat::chatlist::*; use deltachat::chatlist::*;
use deltachat::config; use deltachat::config;
use deltachat::constants::*; use deltachat::constants::*;
use deltachat::contact::*;
use deltachat::context::*; use deltachat::context::*;
use deltachat::dc_array::*; use deltachat::dc_array::*;
use deltachat::dc_chat::*; use deltachat::dc_chat::*;
use deltachat::dc_configure::*; use deltachat::dc_configure::*;
use deltachat::dc_contact::*;
use deltachat::dc_imex::*; use deltachat::dc_imex::*;
use deltachat::dc_job::*; use deltachat::dc_job::*;
use deltachat::dc_location::*; use deltachat::dc_location::*;
@@ -147,7 +147,7 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
} else { } else {
current_block = 7149356873433890176; current_block = 7149356873433890176;
} }
real_spec = to_cstring(rs.unwrap_or_default()); real_spec = rs.unwrap_or_default().strdup();
} }
match current_block { match current_block {
8522321847195001863 => {} 8522321847195001863 => {}
@@ -184,11 +184,10 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
if name.ends_with(".eml") { if name.ends_with(".eml") {
let path_plus_name = format!("{}/{}", as_str(real_spec), name); let path_plus_name = format!("{}/{}", as_str(real_spec), name);
info!(context, 0, "Import: {}", path_plus_name); info!(context, 0, "Import: {}", path_plus_name);
let path_plus_name_c = to_cstring(path_plus_name); let path_plus_name_c = CString::yolo(path_plus_name);
if 0 != dc_poke_eml_file(context, path_plus_name_c) { if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
read_cnt += 1 read_cnt += 1
} }
free(path_plus_name_c as *mut _);
} }
} }
current_block = 1622411330066726685; current_block = 1622411330066726685;
@@ -219,9 +218,10 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
} }
unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: *mut dc_msg_t) { unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: *mut dc_msg_t) {
let contact: *mut dc_contact_t = dc_get_contact(context, dc_msg_get_from_id(msg)); let contact = Contact::get_by_id(context, dc_msg_get_from_id(msg)).expect("invalid contact");
let contact_name: *mut libc::c_char = dc_contact_get_name(contact); let contact_name = contact.get_name();
let contact_id: libc::c_int = dc_contact_get_id(contact) as libc::c_int; let contact_id = contact.get_id();
let statestr = match dc_msg_get_state(msg) { let statestr = match dc_msg_get_state(msg) {
DC_STATE_OUT_PENDING => " o", DC_STATE_OUT_PENDING => " o",
DC_STATE_OUT_DELIVERED => "", DC_STATE_OUT_DELIVERED => "",
@@ -229,8 +229,8 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: *mut dc_msg_t
DC_STATE_OUT_FAILED => " !!", DC_STATE_OUT_FAILED => " !!",
_ => "", _ => "",
}; };
let temp2: *mut libc::c_char = dc_timestamp_to_str(dc_msg_get_timestamp(msg)); let temp2 = dc_timestamp_to_str(dc_msg_get_timestamp(msg));
let msgtext: *mut libc::c_char = dc_msg_get_text(msg); let msgtext = dc_msg_get_text(msg);
info!( info!(
context, context,
0, 0,
@@ -243,14 +243,10 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: *mut dc_msg_t
"" ""
}, },
if dc_msg_has_location(msg) { "📍" } else { "" }, if dc_msg_has_location(msg) { "📍" } else { "" },
as_str(contact_name), &contact_name,
contact_id, contact_id,
as_str(msgtext), as_str(msgtext),
if 0 != dc_msg_is_starred(msg) { if dc_msg_is_starred(msg) { "" } else { "" },
""
} else {
""
},
if dc_msg_get_from_id(msg) == 1 as libc::c_uint { if dc_msg_get_from_id(msg) == 1 as libc::c_uint {
"" ""
} else if dc_msg_get_state(msg) == DC_STATE_IN_SEEN { } else if dc_msg_get_state(msg) == DC_STATE_IN_SEEN {
@@ -266,12 +262,9 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: *mut dc_msg_t
"" ""
}, },
statestr, statestr,
as_str(temp2), &temp2,
); );
free(msgtext as *mut libc::c_void); free(msgtext as *mut libc::c_void);
free(temp2 as *mut libc::c_void);
free(contact_name as *mut libc::c_void);
dc_contact_unref(contact);
} }
unsafe fn log_msglist(context: &Context, msglist: *mut dc_array_t) { unsafe fn log_msglist(context: &Context, msglist: *mut dc_array_t) {
@@ -309,7 +302,6 @@ unsafe fn log_msglist(context: &Context, msglist: *mut dc_array_t) {
} }
unsafe fn log_contactlist(context: &Context, contacts: *mut dc_array_t) { unsafe fn log_contactlist(context: &Context, contacts: *mut dc_array_t) {
let mut contact: *mut dc_contact_t;
if !dc_array_search_id(contacts, 1 as uint32_t, 0 as *mut size_t) { if !dc_array_search_id(contacts, 1 as uint32_t, 0 as *mut size_t) {
dc_array_add_id(contacts, 1 as uint32_t); dc_array_add_id(contacts, 1 as uint32_t);
} }
@@ -318,13 +310,12 @@ unsafe fn log_contactlist(context: &Context, contacts: *mut dc_array_t) {
let contact_id = dc_array_get_id(contacts, i as size_t); let contact_id = dc_array_get_id(contacts, i as size_t);
let line; let line;
let mut line2 = "".to_string(); let mut line2 = "".to_string();
contact = dc_get_contact(context, contact_id); if let Ok(contact) = Contact::get_by_id(context, contact_id) {
if !contact.is_null() { let name = contact.get_name();
let name: *mut libc::c_char = dc_contact_get_name(contact); let addr = contact.get_addr();
let addr: *mut libc::c_char = dc_contact_get_addr(contact); let verified_state = contact.is_verified();
let verified_state: libc::c_int = dc_contact_is_verified(contact); let verified_str = if VerifiedStatus::Unverified != verified_state {
let verified_str = if 0 != verified_state { if verified_state == VerifiedStatus::BidirectVerified {
if verified_state == 2 {
" √√" " √√"
} else { } else {
"" ""
@@ -334,28 +325,26 @@ unsafe fn log_contactlist(context: &Context, contacts: *mut dc_array_t) {
}; };
line = format!( line = format!(
"{}{} <{}>", "{}{} <{}>",
if !name.is_null() && 0 != *name.offset(0isize) as libc::c_int { if !name.is_empty() {
as_str(name) &name
} else { } else {
"<name unset>" "<name unset>"
}, },
verified_str, verified_str,
if !addr.is_null() && 0 != *addr.offset(0isize) as libc::c_int { if !addr.is_empty() {
as_str(addr) &addr
} else { } else {
"addr unset" "addr unset"
} }
); );
let peerstate = Peerstate::from_addr(context, &context.sql, as_str(addr)); let peerstate = Peerstate::from_addr(context, &context.sql, &addr);
if peerstate.is_some() && contact_id != 1 as libc::c_uint { if peerstate.is_some() && contact_id != 1 as libc::c_uint {
line2 = format!( line2 = format!(
", prefer-encrypt={}", ", prefer-encrypt={}",
peerstate.as_ref().unwrap().prefer_encrypt peerstate.as_ref().unwrap().prefer_encrypt
); );
} }
dc_contact_unref(contact);
free(name as *mut libc::c_void);
free(addr as *mut libc::c_void);
info!(context, 0, "Contact#{}: {}{}", contact_id, line, line2); info!(context, 0, "Contact#{}: {}{}", contact_id, line, line2);
} }
} }
@@ -391,13 +380,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let arg1_c = if arg1.is_empty() { let arg1_c = if arg1.is_empty() {
std::ptr::null() std::ptr::null()
} else { } else {
to_cstring(arg1) as *const _ arg1.strdup() as *const _
}; };
let arg2 = args.next().unwrap_or_default(); let arg2 = args.next().unwrap_or_default();
let arg2_c = if arg2.is_empty() { let arg2_c = if arg2.is_empty() {
std::ptr::null() std::ptr::null()
} else { } else {
to_cstring(arg2) as *const _ arg2.strdup() as *const _
}; };
match arg0 { match arg0 {
@@ -503,10 +492,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
"open" => { "open" => {
ensure!(!arg1.is_empty(), "Argument <file> missing"); ensure!(!arg1.is_empty(), "Argument <file> missing");
dc_close(context); dc_close(context);
ensure!( ensure!(dc_open(context, arg1, None), "Open failed");
0 != dc_open(context, arg1_c, 0 as *const libc::c_char),
"Open failed"
);
} }
"close" => { "close" => {
dc_close(context); dc_close(context);
@@ -570,30 +556,17 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
} }
"export-setup" => { "export-setup" => {
let setup_code = dc_create_setup_code(context); let setup_code = dc_create_setup_code(context);
let setup_code_c = CString::new(setup_code.clone()).unwrap();
let file_name: *mut libc::c_char = dc_mprintf( let file_name: *mut libc::c_char = dc_mprintf(
b"%s/autocrypt-setup-message.html\x00" as *const u8 as *const libc::c_char, b"%s/autocrypt-setup-message.html\x00" as *const u8 as *const libc::c_char,
context.get_blobdir(), context.get_blobdir(),
); );
let file_content: *mut libc::c_char; let file_content = dc_render_setup_file(context, &setup_code)?;
file_content = dc_render_setup_file(context, setup_code_c.as_ptr()); std::fs::write(as_str(file_name), file_content)?;
if !file_content.is_null() println!(
&& 0 != dc_write_file( "Setup message written to: {}\nSetup code: {}",
context, as_str(file_name),
file_name, &setup_code,
file_content as *const libc::c_void, );
strlen(file_content),
)
{
println!(
"Setup message written to: {}\nSetup code: {}",
as_str(file_name),
&setup_code,
)
} else {
bail!("");
}
free(file_content as *mut libc::c_void);
free(file_name as *mut libc::c_void); free(file_name as *mut libc::c_void);
} }
"poke" => { "poke" => {
@@ -682,7 +655,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
if !text1.is_null() { ": " } else { "" }, if !text1.is_null() { ": " } else { "" },
to_string(text2), to_string(text2),
statestr, statestr,
as_str(timestr), &timestr,
if 0 != dc_chat_is_sending_locations(chat) { if 0 != dc_chat_is_sending_locations(chat) {
"📍" "📍"
} else { } else {
@@ -691,7 +664,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
); );
free(text1 as *mut libc::c_void); free(text1 as *mut libc::c_void);
free(text2 as *mut libc::c_void); free(text2 as *mut libc::c_void);
free(timestr as *mut libc::c_void);
dc_lot_unref(lot); dc_lot_unref(lot);
dc_chat_unref(chat); dc_chat_unref(chat);
info!( info!(
@@ -886,7 +858,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
0, 0,
"Loc#{}: {}: lat={} lng={} acc={} Chat#{} Contact#{} Msg#{} {}", "Loc#{}: {}: lat={} lng={} acc={} Chat#{} Contact#{} Msg#{} {}",
dc_array_get_id(loc, j as size_t), dc_array_get_id(loc, j as size_t),
as_str(timestr_0), &timestr_0,
dc_array_get_latitude(loc, j as size_t), dc_array_get_latitude(loc, j as size_t),
dc_array_get_longitude(loc, j as size_t), dc_array_get_longitude(loc, j as size_t),
dc_array_get_accuracy(loc, j as size_t), dc_array_get_accuracy(loc, j as size_t),
@@ -899,7 +871,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
"-" "-"
}, },
); );
free(timestr_0 as *mut libc::c_void);
free(marker as *mut libc::c_void); free(marker as *mut libc::c_void);
j += 1 j += 1
} }
@@ -938,32 +909,17 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(!sel_chat.is_null(), "No chat selected."); ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(!arg1.is_empty(), "No message text given."); ensure!(!arg1.is_empty(), "No message text given.");
let msg = to_cstring(format!("{} {}", arg1, arg2)); 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), msg) {
println!("Message sent."); println!("Message sent.");
free(msg as *mut _);
} else { } else {
free(msg as *mut _);
bail!("Sending failed."); bail!("Sending failed.");
} }
} }
"send-garbage" => {
ensure!(!sel_chat.is_null(), "No chat selected.");
let msg = b"\xff\x00"; // NUL-terminated C-string, that is malformed utf-8
if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg.as_ptr().cast()) {
println!("Malformed utf-8 succesfully send. Not nice.");
} else {
bail!("Garbage sending failed, as expected.");
}
}
"sendempty" => { "sendempty" => {
ensure!(!sel_chat.is_null(), "No chat selected."); ensure!(!sel_chat.is_null(), "No chat selected.");
if 0 != dc_send_text_msg( if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), "".into()) {
context,
dc_chat_get_id(sel_chat),
b"\x00" as *const u8 as *const libc::c_char,
) {
println!("Message sent."); println!("Message sent.");
} else { } else {
bail!("Sending failed."); bail!("Sending failed.");
@@ -973,7 +929,14 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(!sel_chat.is_null(), "No chat selected."); ensure!(!sel_chat.is_null(), "No chat selected.");
ensure!(!arg1.is_empty() && !arg2.is_empty(), "No file given."); ensure!(!arg1.is_empty() && !arg2.is_empty(), "No file given.");
let msg_0 = dc_msg_new(context, if arg0 == "sendimage" { 20 } else { 60 }); let msg_0 = dc_msg_new(
context,
if arg0 == "sendimage" {
Viewtype::Image
} else {
Viewtype::File
},
);
dc_msg_set_file(msg_0, arg1_c, 0 as *const libc::c_char); dc_msg_set_file(msg_0, arg1_c, 0 as *const libc::c_char);
dc_msg_set_text(msg_0, arg2_c); 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), msg_0);
@@ -1000,7 +963,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(!sel_chat.is_null(), "No chat selected."); ensure!(!sel_chat.is_null(), "No chat selected.");
if !arg1.is_empty() { if !arg1.is_empty() {
let draft_0 = dc_msg_new(context, 10); let draft_0 = dc_msg_new(context, Viewtype::Text);
dc_msg_set_text(draft_0, arg1_c); dc_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), draft_0);
dc_msg_unref(draft_0); dc_msg_unref(draft_0);
@@ -1013,7 +976,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
"listmedia" => { "listmedia" => {
ensure!(!sel_chat.is_null(), "No chat selected."); ensure!(!sel_chat.is_null(), "No chat selected.");
let images = dc_get_chat_media(context, dc_chat_get_id(sel_chat), 20, 21, 50); let images = dc_get_chat_media(
context,
dc_chat_get_id(sel_chat),
Viewtype::Image,
Viewtype::Gif,
Viewtype::Video,
);
let icnt: libc::c_int = dc_array_get_cnt(images) as libc::c_int; let icnt: libc::c_int = dc_array_get_cnt(images) as libc::c_int;
println!("{} images or videos: ", icnt); println!("{} images or videos: ", icnt);
for i in 0..icnt { for i in 0..icnt {
@@ -1086,15 +1055,15 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
dc_delete_msgs(context, ids.as_mut_ptr(), 1); dc_delete_msgs(context, ids.as_mut_ptr(), 1);
} }
"listcontacts" | "contacts" | "listverified" => { "listcontacts" | "contacts" | "listverified" => {
let contacts = dc_get_contacts( let contacts = Contact::get_all(
context, context,
if arg0 == "listverified" { if arg0 == "listverified" {
0x1 | 0x2 0x1 | 0x2
} else { } else {
0x2 0x2
}, },
arg1_c, Some(arg1),
); )?;
if !contacts.is_null() { if !contacts.is_null() {
log_contactlist(context, contacts); log_contactlist(context, contacts);
println!("{} contacts.", dc_array_get_cnt(contacts) as libc::c_int,); println!("{} contacts.", dc_array_get_cnt(contacts) as libc::c_int,);
@@ -1107,33 +1076,22 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(!arg1.is_empty(), "Arguments [<name>] <addr> expected."); ensure!(!arg1.is_empty(), "Arguments [<name>] <addr> expected.");
if !arg2.is_empty() { if !arg2.is_empty() {
let book = dc_mprintf( let book = format!("{}\n{}", arg1, arg2);
b"%s\n%s\x00" as *const u8 as *const libc::c_char, Contact::add_address_book(context, book)?;
arg1_c,
arg2_c,
);
dc_add_address_book(context, book);
free(book as *mut libc::c_void);
} else { } else {
if 0 == dc_create_contact(context, 0 as *const libc::c_char, arg1_c) { Contact::create(context, "", arg1)?;
bail!("Failed to create contact");
}
} }
} }
"contactinfo" => { "contactinfo" => {
ensure!(!arg1.is_empty(), "Argument <contact-id> missing."); ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
let contact_id = arg1.parse()?; let contact_id = arg1.parse()?;
let contact = dc_get_contact(context, contact_id); let contact = Contact::get_by_id(context, contact_id)?;
let name_n_addr = dc_contact_get_name_n_addr(contact); let name_n_addr = contact.get_name_n_addr();
let mut res = format!("Contact info for: {}:\n\n", as_str(name_n_addr),); let mut res = format!("Contact info for: {}:\n\n", name_n_addr);
free(name_n_addr as *mut libc::c_void);
dc_contact_unref(contact);
let encrinfo = dc_get_contact_encrinfo(context, contact_id); res += &Contact::get_encrinfo(context, contact_id);
res += as_str(encrinfo);
free(encrinfo as *mut libc::c_void);
let chatlist = Chatlist::try_load(context, 0, None, Some(contact_id))?; let chatlist = Chatlist::try_load(context, 0, None, Some(contact_id))?;
let chatlist_cnt = chatlist.len(); let chatlist_cnt = chatlist.len();
@@ -1156,9 +1114,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
} }
"delcontact" => { "delcontact" => {
ensure!(!arg1.is_empty(), "Argument <contact-id> missing."); ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
if !dc_delete_contact(context, arg1.parse()?) { Contact::delete(context, arg1.parse()?)?;
bail!("Failed to delete contact");
}
} }
"checkqr" => { "checkqr" => {
ensure!(!arg1.is_empty(), "Argument <qr-content> missing."); ensure!(!arg1.is_empty(), "Argument <qr-content> missing.");

View File

@@ -291,7 +291,7 @@ const DB_COMMANDS: [&'static str; 11] = [
"housekeeping", "housekeeping",
]; ];
const CHAT_COMMANDS: [&'static str; 25] = [ const CHAT_COMMANDS: [&'static str; 24] = [
"listchats", "listchats",
"listarchived", "listarchived",
"chat", "chat",
@@ -309,7 +309,6 @@ const CHAT_COMMANDS: [&'static str; 25] = [
"dellocations", "dellocations",
"getlocations", "getlocations",
"send", "send",
"send-garbage",
"sendimage", "sendimage",
"sendfile", "sendfile",
"draft", "draft",
@@ -393,18 +392,13 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
let mut context = dc_context_new( let mut context = dc_context_new(
Some(receive_event), Some(receive_event),
0 as *mut libc::c_void, 0 as *mut libc::c_void,
b"CLI\x00" as *const u8 as *const libc::c_char, Some("CLI".into()),
); );
unsafe { dc_cmdline_skip_auth() }; unsafe { dc_cmdline_skip_auth() };
if args.len() == 2 { if args.len() == 2 {
if 0 == unsafe { if unsafe { !dc_open(&mut context, &args[1], None) } {
let a = to_cstring(&args[1]);
let res = dc_open(&mut context, a, 0 as *const _);
free(a as *mut _);
res
} {
println!("Error: Cannot open {}.", args[0],); println!("Error: Cannot open {}.", args[0],);
} }
} else if args.len() != 1 { } else if args.len() != 1 {
@@ -486,7 +480,7 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
let arg1_c = if arg1.is_empty() { let arg1_c = if arg1.is_empty() {
std::ptr::null() std::ptr::null()
} else { } else {
to_cstring(arg1) arg1.strdup()
}; };
match arg0 { match arg0 {

View File

@@ -1,6 +1,6 @@
extern crate deltachat; extern crate deltachat;
use std::ffi::{CStr, CString}; use std::ffi::CStr;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use std::{thread, time}; use std::{thread, time};
use tempfile::tempdir; use tempfile::tempdir;
@@ -8,10 +8,10 @@ use tempfile::tempdir;
use deltachat::chatlist::*; use deltachat::chatlist::*;
use deltachat::config; use deltachat::config;
use deltachat::constants::Event; use deltachat::constants::Event;
use deltachat::contact::*;
use deltachat::context::*; use deltachat::context::*;
use deltachat::dc_chat::*; use deltachat::dc_chat::*;
use deltachat::dc_configure::*; use deltachat::dc_configure::*;
use deltachat::dc_contact::*;
use deltachat::dc_job::{ use deltachat::dc_job::{
dc_perform_imap_fetch, dc_perform_imap_idle, dc_perform_imap_jobs, dc_perform_smtp_idle, dc_perform_imap_fetch, dc_perform_imap_idle, dc_perform_imap_jobs, dc_perform_smtp_idle,
dc_perform_smtp_jobs, dc_perform_smtp_jobs,
@@ -41,7 +41,7 @@ extern "C" fn cb(_ctx: &Context, event: Event, data1: usize, data2: usize) -> us
fn main() { fn main() {
unsafe { unsafe {
let ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut()); let ctx = dc_context_new(Some(cb), std::ptr::null_mut(), None);
let running = Arc::new(RwLock::new(true)); let running = Arc::new(RwLock::new(true));
let info = dc_get_info(&ctx); let info = dc_get_info(&ctx);
let info_s = CStr::from_ptr(info); let info_s = CStr::from_ptr(info);
@@ -76,11 +76,11 @@ fn main() {
}); });
let dir = tempdir().unwrap(); let dir = tempdir().unwrap();
let dbfile = CString::new(dir.path().join("db.sqlite").to_str().unwrap()).unwrap(); let dbfile = dir.path().join("db.sqlite");
println!("opening database {:?}", dbfile); println!("opening database {:?}", dbfile);
assert_eq!(dc_open(&ctx, dbfile.as_ptr(), std::ptr::null()), 1); assert!(dc_open(&ctx, dbfile.to_str().unwrap(), None));
println!("configuring"); println!("configuring");
let args = std::env::args().collect::<Vec<String>>(); let args = std::env::args().collect::<Vec<String>>();
@@ -93,12 +93,11 @@ fn main() {
thread::sleep(duration); thread::sleep(duration);
let email = CString::new("dignifiedquire@gmail.com").unwrap();
println!("sending a message"); println!("sending a message");
let contact_id = dc_create_contact(&ctx, std::ptr::null(), email.as_ptr()); let contact_id =
Contact::create(&ctx, "dignifiedquire", "dignifiedquire@gmail.com").unwrap();
let chat_id = dc_create_chat_by_contact_id(&ctx, contact_id); let chat_id = dc_create_chat_by_contact_id(&ctx, contact_id);
let msg_text = CString::new("Hi, here is my first message!").unwrap(); dc_send_text_msg(&ctx, chat_id, "Hi, here is my first message!".into());
dc_send_text_msg(&ctx, chat_id, msg_text.as_ptr());
println!("fetching chats.."); println!("fetching chats..");
let chats = Chatlist::try_load(&ctx, 0, None, None).unwrap(); let chats = Chatlist::try_load(&ctx, 0, None, None).unwrap();

View File

@@ -20,6 +20,7 @@ class Message(object):
self._dc_context = account._dc_context self._dc_context = account._dc_context
assert isinstance(self._dc_context, ffi.CData) assert isinstance(self._dc_context, ffi.CData)
assert isinstance(dc_msg, ffi.CData) assert isinstance(dc_msg, ffi.CData)
assert dc_msg != ffi.NULL
self._dc_msg = dc_msg self._dc_msg = dc_msg
self.id = lib.dc_msg_get_id(dc_msg) self.id = lib.dc_msg_get_id(dc_msg)
assert self.id is not None and self.id >= 0, repr(self.id) assert self.id is not None and self.id >= 0, repr(self.id)

View File

@@ -120,6 +120,8 @@ def acfactory(pytestconfig, tmpdir, request):
pytest.skip("specify a --liveconfig file to run tests with real accounts") pytest.skip("specify a --liveconfig file to run tests with real accounts")
self.live_count += 1 self.live_count += 1
configdict = self.configlist.pop(0) configdict = self.configlist.pop(0)
if "e2ee_enabled" not in configdict:
configdict["e2ee_enabled"] = "1"
tmpdb = tmpdir.join("livedb%d" % self.live_count) tmpdb = tmpdir.join("livedb%d" % self.live_count)
ac = Account(tmpdb.strpath, logid="ac{}".format(self.live_count)) ac = Account(tmpdb.strpath, logid="ac{}".format(self.live_count))
ac._evlogger.init_time = self.init_time ac._evlogger.init_time = self.init_time

View File

@@ -421,10 +421,43 @@ class TestOnlineAccount:
lp.sec("mark message as seen on ac2, wait for changes on ac1") lp.sec("mark message as seen on ac2, wait for changes on ac1")
ac2.mark_seen_messages([msg_in]) ac2.mark_seen_messages([msg_in])
lp.step("1") lp.step("1")
ac1._evlogger.get_matching("DC_EVENT_MSG_READ") ev = ac1._evlogger.get_matching("DC_EVENT_MSG_READ")
assert ev[1] >= const.DC_CHAT_ID_LAST_SPECIAL
assert ev[2] >= const.DC_MSG_ID_LAST_SPECIAL
lp.step("2") lp.step("2")
assert msg_out.is_out_mdn_received() assert msg_out.is_out_mdn_received()
def test_send_and_receive_will_encrypt_decrypt(self, acfactory, lp):
lp.sec("starting accounts, waiting for configuration")
ac1 = acfactory.get_online_configuring_account()
ac2 = acfactory.get_online_configuring_account()
c2 = ac1.create_contact(email=ac2.get_config("addr"))
chat = ac1.create_chat_by_contact(c2)
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
wait_configuration_progress(ac1, 1000)
wait_configuration_progress(ac2, 1000)
lp.sec("sending text message from ac1 to ac2")
msg_out = chat.send_text("message1")
lp.sec("wait for ac2 to receive message")
ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
assert ev[2] == msg_out.id
msg_in = ac2.get_message_by_id(msg_out.id)
assert msg_in.text == "message1"
lp.sec("create new chat with contact and send back (encrypted) message")
chat2b = ac2.create_chat_by_message(msg_in)
chat2b.send_text("message-back")
lp.sec("wait for ac1 to receive message")
ev = ac1._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
assert ev[1] == chat.id
assert ev[2] > msg_out.id
msg_back = ac1.get_message_by_id(ev[2])
assert msg_back.text == "message-back"
def test_saved_mime_on_received_message(self, acfactory, lp): def test_saved_mime_on_received_message(self, acfactory, lp):
lp.sec("starting accounts, waiting for configuration") lp.sec("starting accounts, waiting for configuration")
ac1 = acfactory.get_online_configuring_account() ac1 = acfactory.get_online_configuring_account()

View File

@@ -6,7 +6,7 @@ use std::{fmt, str};
use mmime::mailimf_types::*; use mmime::mailimf_types::*;
use crate::constants::*; use crate::constants::*;
use crate::dc_contact::*; use crate::contact::*;
use crate::dc_tools::as_str; use crate::dc_tools::as_str;
use crate::key::*; use crate::key::*;
@@ -94,7 +94,7 @@ impl Aheader {
match Self::from_str(value) { match Self::from_str(value) {
Ok(test) => { Ok(test) => {
if dc_addr_cmp(&test.addr, as_str(wanted_from)) { if addr_cmp(&test.addr, as_str(wanted_from)) {
if fine_header.is_none() { if fine_header.is_none() {
fine_header = Some(test); fine_header = Some(test);
} else { } else {

View File

@@ -1,7 +1,7 @@
use crate::constants::*; use crate::constants::*;
use crate::contact::*;
use crate::context::*; use crate::context::*;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_lot::*; use crate::dc_lot::*;
use crate::dc_msg::*; use crate::dc_msg::*;
use crate::dc_tools::*; use crate::dc_tools::*;
@@ -155,7 +155,7 @@ impl<'a> Chatlist<'a> {
let query = query.trim().to_string(); let query = query.trim().to_string();
ensure!(!query.is_empty(), "missing query"); ensure!(!query.is_empty(), "missing query");
let strLikeCmd = format!("%{}%", query); let str_like_cmd = format!("%{}%", query);
context.sql.query_map( context.sql.query_map(
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \ "SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \ ON c.id=m.chat_id \
@@ -164,7 +164,7 @@ impl<'a> Chatlist<'a> {
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \ AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.name LIKE ? \ AND c.blocked=0 AND c.name LIKE ? \
GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;", GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![strLikeCmd], params![str_like_cmd],
process_row, process_row,
process_rows, process_rows,
)? )?
@@ -256,18 +256,18 @@ impl<'a> Chatlist<'a> {
let mut ret = dc_lot_new(); let mut ret = dc_lot_new();
if index >= self.ids.len() { if index >= self.ids.len() {
(*ret).text2 = to_cstring("ErrBadChatlistIndex"); (*ret).text2 = "ErrBadChatlistIndex".strdup();
return ret; return ret;
} }
let lastmsg_id = self.ids[index].1; let lastmsg_id = self.ids[index].1;
let mut lastcontact = 0 as *mut dc_contact_t; let mut lastcontact = None;
if chat.is_null() { if chat.is_null() {
chat = dc_chat_new(self.context); chat = dc_chat_new(self.context);
let chat_to_delete = chat; let chat_to_delete = chat;
if !dc_chat_load_from_db(chat, self.ids[index].0) { if !dc_chat_load_from_db(chat, self.ids[index].0) {
(*ret).text2 = to_cstring("ErrCannotReadChat"); (*ret).text2 = "ErrCannotReadChat".strdup();
dc_chat_unref(chat_to_delete); dc_chat_unref(chat_to_delete);
return ret; return ret;
@@ -282,8 +282,7 @@ impl<'a> Chatlist<'a> {
&& ((*chat).type_0 == DC_CHAT_TYPE_GROUP && ((*chat).type_0 == DC_CHAT_TYPE_GROUP
|| (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP) || (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP)
{ {
lastcontact = dc_contact_new(self.context); lastcontact = Contact::load_from_db(self.context, (*lastmsg).from_id).ok();
dc_contact_load_from_db(lastcontact, &self.context.sql, (*lastmsg).from_id);
} }
lastmsg lastmsg
} else { } else {
@@ -292,14 +291,13 @@ impl<'a> Chatlist<'a> {
if (*chat).id == DC_CHAT_ID_ARCHIVED_LINK as u32 { if (*chat).id == DC_CHAT_ID_ARCHIVED_LINK as u32 {
(*ret).text2 = dc_strdup(0 as *const libc::c_char) (*ret).text2 = dc_strdup(0 as *const libc::c_char)
} else if lastmsg.is_null() || (*lastmsg).from_id == DC_CONTACT_ID_SELF as u32 { } else if lastmsg.is_null() || (*lastmsg).from_id == DC_CONTACT_ID_UNDEFINED as u32 {
(*ret).text2 = to_cstring(self.context.stock_str(StockMessage::NoMessages)); (*ret).text2 = self.context.stock_str(StockMessage::NoMessages).strdup();
} else { } else {
dc_lot_fill(ret, lastmsg, chat, lastcontact, self.context); dc_lot_fill(ret, lastmsg, chat, lastcontact.as_ref(), self.context);
} }
dc_msg_unref(lastmsg); dc_msg_unref(lastmsg);
dc_contact_unref(lastcontact);
ret ret
} }

View File

@@ -7,7 +7,6 @@ use crate::dc_job::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::error::Error; use crate::error::Error;
use crate::stock::StockMessage; use crate::stock::StockMessage;
use crate::x::*;
/// The available configuration keys. /// The available configuration keys.
#[derive( #[derive(
@@ -70,17 +69,7 @@ impl Context {
let value = match key { let value = match key {
Config::Selfavatar => { Config::Selfavatar => {
let rel_path = self.sql.get_config(self, key); let rel_path = self.sql.get_config(self, key);
rel_path.map(|p| { rel_path.map(|p| dc_get_abs_path_safe(self, &p).to_str().unwrap().to_string())
let v = unsafe {
let n = to_cstring(p);
let res = dc_get_abs_path(self, n);
free(n as *mut libc::c_void);
res
};
let r = to_string(v);
unsafe { free(v as *mut _) };
r
})
} }
Config::SysVersion => Some(std::str::from_utf8(DC_VERSION_STR).unwrap().into()), Config::SysVersion => Some(std::str::from_utf8(DC_VERSION_STR).unwrap().into()),
Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)), Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)),

View File

@@ -1,5 +1,8 @@
#![allow(non_camel_case_types)]
//! Constants //! Constants
#![allow(non_camel_case_types)]
use num_traits::{FromPrimitive, ToPrimitive};
use rusqlite as sql;
use rusqlite::types::*;
pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00"; pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00";
@@ -86,6 +89,7 @@ pub const DC_MAX_GET_TEXT_LEN: usize = 30000;
/// approx. max. length returned by dc_get_msg_info() /// approx. max. length returned by dc_get_msg_info()
pub const DC_MAX_GET_INFO_LEN: usize = 100000; pub const DC_MAX_GET_INFO_LEN: usize = 100000;
pub const DC_CONTACT_ID_UNDEFINED: usize = 0;
pub const DC_CONTACT_ID_SELF: usize = 1; pub const DC_CONTACT_ID_SELF: usize = 1;
pub const DC_CONTACT_ID_DEVICE: usize = 2; pub const DC_CONTACT_ID_DEVICE: usize = 2;
pub const DC_CONTACT_ID_LAST_SPECIAL: usize = 9; pub const DC_CONTACT_ID_LAST_SPECIAL: usize = 9;
@@ -96,46 +100,6 @@ pub const DC_TEXT1_SELF: usize = 3;
pub const DC_CREATE_MVBOX: usize = 1; pub const DC_CREATE_MVBOX: usize = 1;
/// Text message.
/// The text of the message is set using dc_msg_set_text()
/// and retrieved with dc_msg_get_text().
pub const DC_MSG_TEXT: i32 = 10;
/// Image message.
/// If the image is an animated GIF, the type DC_MSG_GIF should be used.
/// File, width and height are set via dc_msg_set_file(), dc_msg_set_dimension
/// and retrieved via dc_msg_set_file(), dc_msg_set_dimension().
pub const DC_MSG_IMAGE: i32 = 20;
/// Animated GIF message.
/// File, width and height are set via dc_msg_set_file(), dc_msg_set_dimension()
/// and retrieved via dc_msg_get_file(), dc_msg_get_width(), dc_msg_get_height().
pub const DC_MSG_GIF: i32 = 21;
/// Message containing an Audio file.
/// File and duration are set via dc_msg_set_file(), dc_msg_set_duration()
/// and retrieved via dc_msg_get_file(), dc_msg_get_duration().
pub const DC_MSG_AUDIO: i32 = 40;
/// A voice message that was directly recorded by the user.
/// For all other audio messages, the type #DC_MSG_AUDIO should be used.
/// File and duration are set via dc_msg_set_file(), dc_msg_set_duration()
/// and retrieved via dc_msg_get_file(), dc_msg_get_duration()
pub const DC_MSG_VOICE: i32 = 41;
/// Video messages.
/// File, width, height and durarion
/// are set via dc_msg_set_file(), dc_msg_set_dimension(), dc_msg_set_duration()
/// and retrieved via
/// dc_msg_get_file(), dc_msg_get_width(),
/// dc_msg_get_height(), dc_msg_get_duration().
pub const DC_MSG_VIDEO: i32 = 50;
/// Message containing any file, eg. a PDF.
/// The file is set via dc_msg_set_file()
/// and retrieved via dc_msg_get_file().
pub const DC_MSG_FILE: i32 = 60;
// Flags for configuring IMAP and SMTP servers. // Flags for configuring IMAP and SMTP servers.
// These flags are optional // These flags are optional
// and may be set together with the username, password etc. // and may be set together with the username, password etc.
@@ -183,6 +147,78 @@ pub const DC_LP_IMAP_SOCKET_FLAGS: usize =
pub const DC_LP_SMTP_SOCKET_FLAGS: usize = pub const DC_LP_SMTP_SOCKET_FLAGS: usize =
(DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN); (DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN);
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
#[repr(i32)]
pub enum Viewtype {
Unknown = 0,
/// Text message.
/// The text of the message is set using dc_msg_set_text()
/// and retrieved with dc_msg_get_text().
Text = 10,
/// Image message.
/// If the image is an animated GIF, the type DC_MSG_GIF should be used.
/// File, width and height are set via dc_msg_set_file(), dc_msg_set_dimension
/// and retrieved via dc_msg_set_file(), dc_msg_set_dimension().
Image = 20,
/// Animated GIF message.
/// File, width and height are set via dc_msg_set_file(), dc_msg_set_dimension()
/// and retrieved via dc_msg_get_file(), dc_msg_get_width(), dc_msg_get_height().
Gif = 21,
/// Message containing an Audio file.
/// File and duration are set via dc_msg_set_file(), dc_msg_set_duration()
/// and retrieved via dc_msg_get_file(), dc_msg_get_duration().
Audio = 40,
/// A voice message that was directly recorded by the user.
/// For all other audio messages, the type #DC_MSG_AUDIO should be used.
/// File and duration are set via dc_msg_set_file(), dc_msg_set_duration()
/// and retrieved via dc_msg_get_file(), dc_msg_get_duration()
Voice = 41,
/// Video messages.
/// File, width, height and durarion
/// are set via dc_msg_set_file(), dc_msg_set_dimension(), dc_msg_set_duration()
/// and retrieved via
/// dc_msg_get_file(), dc_msg_get_width(),
/// dc_msg_get_height(), dc_msg_get_duration().
Video = 50,
/// Message containing any file, eg. a PDF.
/// The file is set via dc_msg_set_file()
/// and retrieved via dc_msg_get_file().
File = 60,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn derive_display_works_as_expected() {
assert_eq!(format!("{}", Viewtype::Audio), "Audio");
}
}
impl ToSql for Viewtype {
fn to_sql(&self) -> sql::Result<ToSqlOutput> {
let num: i64 = self
.to_i64()
.expect("impossible: Viewtype -> i64 conversion failed");
Ok(ToSqlOutput::Owned(Value::Integer(num)))
}
}
impl FromSql for Viewtype {
fn column_result(col: ValueRef) -> FromSqlResult<Self> {
let inner = FromSql::column_result(col)?;
FromPrimitive::from_i64(inner).ok_or(FromSqlError::InvalidType)
}
}
// These constants are used as events // These constants are used as events
// reported to the callback given to dc_context_new(). // reported to the callback given to dc_context_new().
// If you do not want to handle an event, it is always safe to return 0, // If you do not want to handle an event, it is always safe to return 0,

1093
src/contact.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::sync::{Arc, Condvar, Mutex, RwLock};
use crate::constants::*; use crate::constants::*;
use crate::contact::*;
use crate::dc_array::*; use crate::dc_array::*;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_job::*; use crate::dc_job::*;
use crate::dc_jobthread::*; use crate::dc_jobthread::*;
use crate::dc_loginparam::*; use crate::dc_loginparam::*;
@@ -27,15 +27,15 @@ pub struct Context {
pub blobdir: Arc<RwLock<*mut libc::c_char>>, pub blobdir: Arc<RwLock<*mut libc::c_char>>,
pub sql: Sql, pub sql: Sql,
pub inbox: Arc<RwLock<Imap>>, pub inbox: Arc<RwLock<Imap>>,
pub perform_inbox_jobs_needed: Arc<RwLock<i32>>, pub perform_inbox_jobs_needed: Arc<RwLock<bool>>,
pub probe_imap_network: Arc<RwLock<i32>>, pub probe_imap_network: Arc<RwLock<bool>>,
pub sentbox_thread: Arc<RwLock<dc_jobthread_t>>, pub sentbox_thread: Arc<RwLock<dc_jobthread_t>>,
pub mvbox_thread: Arc<RwLock<dc_jobthread_t>>, pub mvbox_thread: Arc<RwLock<dc_jobthread_t>>,
pub smtp: Arc<Mutex<Smtp>>, pub smtp: Arc<Mutex<Smtp>>,
pub smtp_state: Arc<(Mutex<SmtpState>, Condvar)>, pub smtp_state: Arc<(Mutex<SmtpState>, Condvar)>,
pub oauth2_critical: Arc<Mutex<()>>, pub oauth2_critical: Arc<Mutex<()>>,
pub cb: Option<dc_callback_t>, pub cb: Option<dc_callback_t>,
pub os_name: *mut libc::c_char, pub os_name: Option<String>,
pub cmdline_sel_chat_id: Arc<RwLock<u32>>, pub cmdline_sel_chat_id: Arc<RwLock<u32>>,
pub bob: Arc<RwLock<BobStatus>>, pub bob: Arc<RwLock<BobStatus>>,
pub last_smeared_timestamp: Arc<RwLock<i64>>, pub last_smeared_timestamp: Arc<RwLock<i64>>,
@@ -106,17 +106,17 @@ impl Default for BobStatus {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct SmtpState { pub struct SmtpState {
pub idle: bool, pub idle: bool,
pub suspended: i32, pub suspended: bool,
pub doing_jobs: i32, pub doing_jobs: bool,
pub perform_jobs_needed: i32, pub perform_jobs_needed: i32,
pub probe_network: i32, pub probe_network: bool,
} }
// create/open/config/information // create/open/config/information
pub fn dc_context_new( pub fn dc_context_new(
cb: Option<dc_callback_t>, cb: Option<dc_callback_t>,
userdata: *mut libc::c_void, userdata: *mut libc::c_void,
os_name: *const libc::c_char, os_name: Option<String>,
) -> Context { ) -> Context {
Context { Context {
blobdir: Arc::new(RwLock::new(std::ptr::null_mut())), blobdir: Arc::new(RwLock::new(std::ptr::null_mut())),
@@ -131,7 +131,7 @@ pub fn dc_context_new(
})), })),
userdata, userdata,
cb, cb,
os_name: unsafe { dc_strdup_keep_null(os_name) }, os_name: os_name,
running_state: Arc::new(RwLock::new(Default::default())), running_state: Arc::new(RwLock::new(Default::default())),
sql: Sql::new(), sql: Sql::new(),
smtp: Arc::new(Mutex::new(Smtp::new())), smtp: Arc::new(Mutex::new(Smtp::new())),
@@ -160,8 +160,18 @@ pub fn dc_context_new(
cb_receive_imf, cb_receive_imf,
), ),
))), ))),
probe_imap_network: Arc::new(RwLock::new(0)), probe_imap_network: Arc::new(RwLock::new(false)),
perform_inbox_jobs_needed: Arc::new(RwLock::new(0)), perform_inbox_jobs_needed: Arc::new(RwLock::new(false)),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_crashes_on_context_deref() {
let mut ctx = dc_context_new(None, std::ptr::null_mut(), Some("Test OS".into()));
unsafe { dc_context_unref(&mut ctx) };
} }
} }
@@ -233,13 +243,8 @@ unsafe fn cb_precheck_imf(
return rfc724_mid_exists; return rfc724_mid_exists;
} }
unsafe fn cb_set_config(context: &Context, key: *const libc::c_char, value: *const libc::c_char) { fn cb_set_config(context: &Context, key: &str, value: Option<&str>) {
let v = if value.is_null() { context.sql.set_config(context, key, value).ok();
None
} else {
Some(as_str(value))
};
context.sql.set_config(context, as_str(key), v).ok();
} }
/* * /* *
@@ -249,24 +254,14 @@ unsafe fn cb_set_config(context: &Context, key: *const libc::c_char, value: *con
* *
* @private @memberof Context * @private @memberof Context
*/ */
unsafe fn cb_get_config( fn cb_get_config(context: &Context, key: &str) -> Option<String> {
context: &Context, context.sql.get_config(context, key)
key: *const libc::c_char,
def: *const libc::c_char,
) -> *mut libc::c_char {
let res = context
.sql
.get_config(context, as_str(key))
.unwrap_or_else(|| to_string(def));
to_cstring(res)
} }
pub unsafe fn dc_context_unref(context: &mut Context) { pub unsafe fn dc_context_unref(context: &mut Context) {
if 0 != dc_is_open(context) { if 0 != dc_is_open(context) {
dc_close(context); dc_close(context);
} }
free(context.os_name as *mut libc::c_void);
} }
pub unsafe fn dc_close(context: &Context) { pub unsafe fn dc_close(context: &Context) {
@@ -310,32 +305,26 @@ pub unsafe fn dc_get_userdata(context: &mut Context) -> *mut libc::c_void {
context.userdata as *mut _ context.userdata as *mut _
} }
pub unsafe fn dc_open( pub unsafe fn dc_open(context: &Context, dbfile: &str, blobdir: Option<&str>) -> bool {
context: &Context, let mut success = false;
dbfile: *const libc::c_char,
blobdir: *const libc::c_char,
) -> libc::c_int {
let mut success = 0;
if 0 != dc_is_open(context) { if 0 != dc_is_open(context) {
return 0; return false;
} }
if !dbfile.is_null() { *context.dbfile.write().unwrap() = dbfile.strdup();
*context.dbfile.write().unwrap() = dc_strdup(dbfile); if blobdir.is_some() && blobdir.unwrap().len() > 0 {
if !blobdir.is_null() && 0 != *blobdir.offset(0isize) as libc::c_int { let dir = dc_ensure_no_slash_safe(blobdir.unwrap()).strdup();
let dir = dc_strdup(blobdir); *context.blobdir.write().unwrap() = dir;
dc_ensure_no_slash(dir); } else {
*context.blobdir.write().unwrap() = dir; let dir = (dbfile.to_string() + "-blobs").strdup();
} else { dc_create_folder(context, dir);
let dir = dc_mprintf(b"%s-blobs\x00" as *const u8 as *const libc::c_char, dbfile); *context.blobdir.write().unwrap() = dir;
dc_create_folder(context, dir);
*context.blobdir.write().unwrap() = dir;
}
// Create/open sqlite database, this may already use the blobdir
if context.sql.open(context, as_path(dbfile), 0) {
success = 1i32
}
} }
if 0 == success { // Create/open sqlite database, this may already use the blobdir
let dbfile_path = std::path::Path::new(dbfile);
if context.sql.open(context, dbfile_path, 0) {
success = true
}
if !success {
dc_close(context); dc_close(context);
} }
success success
@@ -357,7 +346,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
let chats = dc_get_chat_cnt(context) as usize; let chats = dc_get_chat_cnt(context) as usize;
let real_msgs = dc_get_real_msg_cnt(context) as usize; let real_msgs = dc_get_real_msg_cnt(context) as usize;
let deaddrop_msgs = dc_get_deaddrop_msg_cnt(context) as usize; let deaddrop_msgs = dc_get_deaddrop_msg_cnt(context) as usize;
let contacts = dc_get_real_contact_cnt(context) as usize; let contacts = Contact::get_real_cnt(context) as usize;
let is_configured = context let is_configured = context
.sql .sql
.get_config_int(context, "configured") .get_config_int(context, "configured")
@@ -494,7 +483,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
fingerprint_str, fingerprint_str,
); );
to_cstring(res) res.strdup()
} }
pub unsafe fn dc_get_version_str() -> *mut libc::c_char { pub unsafe fn dc_get_version_str() -> *mut libc::c_char {

View File

@@ -4,6 +4,7 @@ use crate::types::*;
/* * the structure behind dc_array_t */ /* * the structure behind dc_array_t */
#[derive(Clone)] #[derive(Clone)]
#[allow(non_camel_case_types)]
pub enum dc_array_t { pub enum dc_array_t {
Locations(Vec<dc_location>), Locations(Vec<dc_location>),
Uint(Vec<uintptr_t>), Uint(Vec<uintptr_t>),
@@ -136,6 +137,20 @@ impl dc_array_t {
panic!("Attempt to search for id in array of other type"); panic!("Attempt to search for id in array of other type");
} }
} }
pub fn sort_ids(&mut self) {
if let dc_array_t::Uint(v) = self {
v.sort();
} else {
panic!("Attempt to sort array of something other than uints");
}
}
}
impl From<Vec<dc_location>> for dc_array_t {
fn from(array: Vec<dc_location>) -> Self {
dc_array_t::Locations(array)
}
} }
pub unsafe fn dc_array_unref(array: *mut dc_array_t) { pub unsafe fn dc_array_unref(array: *mut dc_array_t) {
@@ -256,7 +271,7 @@ pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *m
if let dc_array_t::Locations(v) = &*array { if let dc_array_t::Locations(v) = &*array {
if let Some(s) = &v[index].marker { if let Some(s) = &v[index].marker {
to_cstring(s) s.strdup()
} else { } else {
std::ptr::null_mut() std::ptr::null_mut()
} }
@@ -339,17 +354,6 @@ pub unsafe fn dc_array_duplicate(array: *const dc_array_t) -> *mut dc_array_t {
} }
} }
pub unsafe fn dc_array_sort_ids(array: *mut dc_array_t) {
if array.is_null() || (*array).len() <= 1 {
return;
}
if let dc_array_t::Uint(v) = &mut *array {
v.sort();
} else {
panic!("Attempt to sort array of something other than uints");
}
}
pub unsafe fn dc_array_get_string( pub unsafe fn dc_array_get_string(
array: *const dc_array_t, array: *const dc_array_t,
sep: *const libc::c_char, sep: *const libc::c_char,
@@ -371,7 +375,7 @@ pub unsafe fn dc_array_get_string(
res + sep + &n.to_string() res + sep + &n.to_string()
} }
}); });
to_cstring(res) res.strdup()
} else { } else {
panic!("Attempt to get string from array of other type"); panic!("Attempt to get string from array of other type");
} }
@@ -416,7 +420,7 @@ mod tests {
dc_array_add_id(arr, 0 as uint32_t); dc_array_add_id(arr, 0 as uint32_t);
dc_array_add_id(arr, 5000 as uint32_t); dc_array_add_id(arr, 5000 as uint32_t);
dc_array_sort_ids(arr); (*arr).sort_ids();
assert_eq!(dc_array_get_id(arr, 0 as size_t), 0); assert_eq!(dc_array_get_id(arr, 0 as size_t), 0);
assert_eq!(dc_array_get_id(arr, 1 as size_t), 7); assert_eq!(dc_array_get_id(arr, 1 as size_t), 7);

View File

@@ -2,9 +2,9 @@ use std::ffi::CString;
use crate::chatlist::*; use crate::chatlist::*;
use crate::constants::*; use crate::constants::*;
use crate::contact::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_array::*; use crate::dc_array::*;
use crate::dc_contact::*;
use crate::dc_job::*; use crate::dc_job::*;
use crate::dc_msg::*; use crate::dc_msg::*;
use crate::dc_tools::*; use crate::dc_tools::*;
@@ -52,7 +52,7 @@ pub unsafe fn dc_create_chat_by_msg_id(context: &Context, msg_id: uint32_t) -> u
dc_unblock_chat(context, (*chat).id); dc_unblock_chat(context, (*chat).id);
send_event = 1i32 send_event = 1i32
} }
dc_scaleup_contact_origin(context, (*msg).from_id, 0x800i32); Contact::scaleup_origin_by_id(context, (*msg).from_id, Origin::CreateChat);
} }
dc_msg_unref(msg); dc_msg_unref(msg);
@@ -137,14 +137,8 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
c.id = row.get(0)?; c.id = row.get(0)?;
c.type_0 = row.get(1)?; c.type_0 = row.get(1)?;
c.name = { c.name = unsafe { row.get::<_, String>(2)?.strdup() };
let raw: String = row.get(2)?; c.grpid = unsafe { row.get::<_, String>(3)?.strdup() };
unsafe { to_cstring(raw) }
};
c.grpid = {
let raw: String = row.get(3)?;
unsafe { to_cstring(raw) }
};
c.param = row.get::<_, String>(4)?.parse().unwrap_or_default(); c.param = row.get::<_, String>(4)?.parse().unwrap_or_default();
c.archived = row.get(5)?; c.archived = row.get(5)?;
@@ -172,24 +166,27 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
match c.id { match c.id {
1 => unsafe { 1 => unsafe {
free((*chat).name as *mut libc::c_void); free((*chat).name as *mut libc::c_void);
(*chat).name = to_cstring((*chat).context.stock_str(StockMessage::DeadDrop)); (*chat).name = (*chat).context.stock_str(StockMessage::DeadDrop).strdup();
}, },
6 => unsafe { 6 => unsafe {
free((*chat).name as *mut libc::c_void); free((*chat).name as *mut libc::c_void);
let tempname = (*chat).context.stock_str(StockMessage::ArchivedChats); let tempname = (*chat).context.stock_str(StockMessage::ArchivedChats);
let cnt = dc_get_archived_cnt((*chat).context); let cnt = dc_get_archived_cnt((*chat).context);
(*chat).name = to_cstring(format!("{} ({})", tempname, cnt)); (*chat).name = format!("{} ({})", tempname, cnt).strdup();
}, },
5 => unsafe { 5 => unsafe {
free((*chat).name as *mut libc::c_void); free((*chat).name as *mut libc::c_void);
(*chat).name = to_cstring((*chat).context.stock_str(StockMessage::StarredMsgs)); (*chat).name = (*chat)
.context
.stock_str(StockMessage::StarredMsgs)
.strdup();
}, },
_ => { _ => {
if unsafe { &(*chat).param }.exists(Param::Selftalk) { if unsafe { &(*chat).param }.exists(Param::Selftalk) {
unsafe { unsafe {
free((*chat).name as *mut libc::c_void); free((*chat).name as *mut libc::c_void);
(*chat).name = (*chat).name =
to_cstring((*chat).context.stock_str(StockMessage::SelfMsg)); (*chat).context.stock_str(StockMessage::SelfMsg).strdup();
} }
} }
} }
@@ -209,7 +206,9 @@ pub unsafe fn dc_create_chat_by_contact_id(context: &Context, contact_id: uint32
dc_unblock_chat(context, chat_id); dc_unblock_chat(context, chat_id);
send_event = 1i32 send_event = 1i32
} }
} else if !dc_real_contact_exists(context, contact_id) && contact_id != 1i32 as libc::c_uint { } else if !Contact::real_exists_by_id(context, contact_id)
&& contact_id != DC_CONTACT_ID_SELF as u32
{
warn!( warn!(
context, context,
0, "Cannot create chat, contact {} does not exist.", contact_id as libc::c_int, 0, "Cannot create chat, contact {} does not exist.", contact_id as libc::c_int,
@@ -225,7 +224,7 @@ pub unsafe fn dc_create_chat_by_contact_id(context: &Context, contact_id: uint32
if 0 != chat_id { if 0 != chat_id {
send_event = 1; send_event = 1;
} }
dc_scaleup_contact_origin(context, contact_id, 0x800i32); Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat);
} }
if 0 != send_event { if 0 != send_event {
context.call_cb(Event::MSGS_CHANGED, 0i32 as uintptr_t, 0i32 as uintptr_t); context.call_cb(Event::MSGS_CHANGED, 0i32 as uintptr_t, 0i32 as uintptr_t);
@@ -242,8 +241,6 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
) { ) {
let mut chat_id = 0; let mut chat_id = 0;
let mut chat_blocked = 0; let mut chat_blocked = 0;
let contact: *mut dc_contact_t;
let chat_name: *mut libc::c_char;
if !ret_chat_id.is_null() { if !ret_chat_id.is_null() {
*ret_chat_id = 0; *ret_chat_id = 0;
@@ -267,14 +264,8 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
} }
return; return;
} }
contact = dc_contact_new(context); if let Ok(contact) = Contact::load_from_db(context, contact_id) {
if dc_contact_load_from_db(contact, &context.sql, contact_id) { let chat_name = contact.get_display_name();
chat_name =
if !(*contact).name.is_null() && 0 != *(*contact).name.offset(0isize) as libc::c_int {
(*contact).name
} else {
(*contact).addr
};
if sql::execute( if sql::execute(
context, context,
@@ -282,10 +273,10 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
format!( format!(
"INSERT INTO chats (type, name, param, blocked, grpid) VALUES({}, '{}', '{}', {}, '{}')", "INSERT INTO chats (type, name, param, blocked, grpid) VALUES({}, '{}', '{}', {}, '{}')",
100, 100,
as_str(chat_name), chat_name,
if contact_id == 1 { "K=1" } else { "" }, if contact_id == DC_CONTACT_ID_SELF as u32 { "K=1" } else { "" },
create_blocked, create_blocked,
as_str((*contact).addr), contact.get_addr(),
), ),
params![], params![],
).is_ok() { ).is_ok() {
@@ -294,7 +285,7 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
&context.sql, &context.sql,
"chats", "chats",
"grpid", "grpid",
as_str((*contact).addr), contact.get_addr(),
); );
sql::execute( sql::execute(
@@ -306,7 +297,6 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
} }
} }
dc_contact_unref(contact);
if !ret_chat_id.is_null() { if !ret_chat_id.is_null() {
*ret_chat_id = chat_id *ret_chat_id = chat_id
} }
@@ -371,14 +361,14 @@ pub unsafe fn dc_prepare_msg<'a>(
return msg_id; return msg_id;
} }
pub fn msgtype_has_file(msgtype: i32) -> bool { pub fn msgtype_has_file(msgtype: Viewtype) -> bool {
match msgtype { match msgtype {
DC_MSG_IMAGE => true, Viewtype::Image => true,
DC_MSG_GIF => true, Viewtype::Gif => true,
DC_MSG_AUDIO => true, Viewtype::Audio => true,
DC_MSG_VOICE => true, Viewtype::Voice => true,
DC_MSG_VIDEO => true, Viewtype::Video => true,
DC_MSG_FILE => true, Viewtype::File => true,
_ => false, _ => false,
} }
} }
@@ -392,13 +382,13 @@ unsafe fn prepare_msg_common<'a>(
let mut OK_TO_CONTINUE = true; let mut OK_TO_CONTINUE = true;
(*msg).id = 0i32 as uint32_t; (*msg).id = 0i32 as uint32_t;
(*msg).context = context; (*msg).context = context;
if (*msg).type_0 == DC_MSG_TEXT { if (*msg).type_0 == Viewtype::Text {
/* the caller should check if the message text is empty */ /* the caller should check if the message text is empty */
} else if msgtype_has_file((*msg).type_0) { } else if msgtype_has_file((*msg).type_0) {
let mut pathNfilename = (*msg) let mut pathNfilename = (*msg)
.param .param
.get(Param::File) .get(Param::File)
.map(|s| to_cstring(s)) .map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut()); .unwrap_or_else(|| std::ptr::null_mut());
if pathNfilename.is_null() { if pathNfilename.is_null() {
error!( error!(
@@ -417,16 +407,16 @@ unsafe fn prepare_msg_common<'a>(
OK_TO_CONTINUE = false; OK_TO_CONTINUE = false;
} else { } else {
(*msg).param.set(Param::File, as_str(pathNfilename)); (*msg).param.set(Param::File, as_str(pathNfilename));
if (*msg).type_0 == DC_MSG_FILE || (*msg).type_0 == DC_MSG_IMAGE { if (*msg).type_0 == Viewtype::File || (*msg).type_0 == Viewtype::Image {
/* Correct the type, take care not to correct already very special formats as GIF or VOICE. /* Correct the type, take care not to correct already very special formats as GIF or VOICE.
Typical conversions: Typical conversions:
- from FILE to AUDIO/VIDEO/IMAGE - from FILE to AUDIO/VIDEO/IMAGE
- from FILE/IMAGE to GIF */ - from FILE/IMAGE to GIF */
let mut better_type = 0; let mut better_type = Viewtype::Unknown;
let mut better_mime = std::ptr::null_mut(); let mut better_mime = std::ptr::null_mut();
dc_msg_guess_msgtype_from_suffix(pathNfilename, &mut better_type, &mut better_mime); dc_msg_guess_msgtype_from_suffix(pathNfilename, &mut better_type, &mut better_mime);
if 0 != better_type && !better_mime.is_null() { if Viewtype::Unknown != better_type && !better_mime.is_null() {
(*msg).type_0 = better_type; (*msg).type_0 = better_type;
(*msg).param.set(Param::MimeType, as_str(better_mime)); (*msg).param.set(Param::MimeType, as_str(better_mime));
} }
@@ -436,7 +426,7 @@ unsafe fn prepare_msg_common<'a>(
dc_msg_guess_msgtype_from_suffix( dc_msg_guess_msgtype_from_suffix(
pathNfilename, pathNfilename,
0 as *mut libc::c_int, 0 as *mut Viewtype,
&mut better_mime, &mut better_mime,
); );
@@ -516,16 +506,15 @@ unsafe fn prepare_msg_raw(
if from.is_none() { if from.is_none() {
error!(context, 0, "Cannot send message, not configured.",); error!(context, 0, "Cannot send message, not configured.",);
} else { } else {
let from_c = to_cstring(from.unwrap()); let from_c = CString::yolo(from.unwrap());
new_rfc724_mid = dc_create_outgoing_rfc724_mid( new_rfc724_mid = dc_create_outgoing_rfc724_mid(
if (*chat).type_0 == 120 || (*chat).type_0 == 130 { if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
(*chat).grpid (*chat).grpid
} else { } else {
0 as *mut libc::c_char 0 as *mut libc::c_char
}, },
from_c, from_c.as_ptr(),
); );
free(from_c as *mut _);
if (*chat).type_0 == DC_CHAT_TYPE_SINGLE { if (*chat).type_0 == DC_CHAT_TYPE_SINGLE {
if let Some(id) = context.sql.query_row_col( if let Some(id) = context.sql.query_row_col(
@@ -729,7 +718,7 @@ unsafe fn prepare_msg_raw(
timestamp, timestamp,
(*msg).type_0, (*msg).type_0,
(*msg).state, (*msg).state,
if !(*msg).text.is_null() { Some(as_str((*msg).text)) } else { None }, (*msg).text,
(*msg).param.to_string(), (*msg).param.to_string(),
(*msg).hidden, (*msg).hidden,
to_string(new_in_reply_to), to_string(new_in_reply_to),
@@ -780,18 +769,19 @@ unsafe fn get_parent_mime_headers(
|| parent_in_reply_to.is_null() || parent_in_reply_to.is_null()
|| parent_references.is_null()) || parent_references.is_null())
{ {
// prefer a last message that isn't from us
success = (*chat) success = (*chat)
.context .context
.sql .sql
.query_row( .query_row(
"SELECT rfc724_mid, mime_in_reply_to, mime_references \ "SELECT rfc724_mid, mime_in_reply_to, mime_references \
FROM msgs WHERE timestamp=(SELECT max(timestamp) \ FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT max(timestamp) \
FROM msgs WHERE chat_id=? AND from_id!=?);", FROM msgs WHERE chat_id=?1 AND from_id!=?2);",
params![(*chat).id as i32, 1], params![(*chat).id as i32, DC_CONTACT_ID_SELF as i32],
|row| { |row| {
*parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?); *parent_rfc724_mid = row.get::<_, String>(0)?.strdup();
*parent_in_reply_to = to_cstring(row.get::<_, String>(1)?); *parent_in_reply_to = row.get::<_, String>(1)?.strdup();
*parent_references = to_cstring(row.get::<_, String>(2)?); *parent_references = row.get::<_, String>(2)?.strdup();
Ok(()) Ok(())
}, },
) )
@@ -803,13 +793,13 @@ unsafe fn get_parent_mime_headers(
.sql .sql
.query_row( .query_row(
"SELECT rfc724_mid, mime_in_reply_to, mime_references \ "SELECT rfc724_mid, mime_in_reply_to, mime_references \
FROM msgs WHERE timestamp=(SELECT min(timestamp) \ FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT min(timestamp) \
FROM msgs WHERE chat_id=? AND from_id==?);", FROM msgs WHERE chat_id=?1 AND from_id==?2);",
params![(*chat).id as i32, 1], params![(*chat).id as i32, DC_CONTACT_ID_SELF as i32],
|row| { |row| {
*parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?); *parent_rfc724_mid = row.get::<_, String>(0)?.strdup();
*parent_in_reply_to = to_cstring(row.get::<_, String>(1)?); *parent_in_reply_to = row.get::<_, String>(1)?.strdup();
*parent_references = to_cstring(row.get::<_, String>(2)?); *parent_references = row.get::<_, String>(2)?.strdup();
Ok(()) Ok(())
}, },
) )
@@ -954,7 +944,7 @@ pub unsafe fn dc_send_msg<'a>(
pub unsafe fn dc_send_text_msg( pub unsafe fn dc_send_text_msg(
context: &Context, context: &Context,
chat_id: uint32_t, chat_id: uint32_t,
text_to_send: *const libc::c_char, text_to_send: String,
) -> uint32_t { ) -> uint32_t {
if chat_id <= 9 { if chat_id <= 9 {
warn!( warn!(
@@ -964,18 +954,8 @@ pub unsafe fn dc_send_text_msg(
return 0; return 0;
} }
if text_to_send.is_null() { let mut msg = dc_msg_new(context, Viewtype::Text);
warn!(context, 0, "dc_send_text_msg: text_to_send is emtpy"); (*msg).text = Some(text_to_send);
return 0;
}
if let Err(err) = as_str_safe(text_to_send) {
warn!(context, 0, "{}", err);
return 0;
}
let mut msg = dc_msg_new(context, 10);
(*msg).text = dc_strdup(text_to_send);
let ret = dc_send_msg(context, chat_id, msg); let ret = dc_send_msg(context, chat_id, msg);
dc_msg_unref(msg); dc_msg_unref(msg);
ret ret
@@ -1004,15 +984,13 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t
} }
// save new draft // save new draft
if !msg.is_null() { if !msg.is_null() {
if (*msg).type_0 == DC_MSG_TEXT { if (*msg).type_0 == Viewtype::Text {
if (*msg).text.is_null() || *(*msg).text.offset(0isize) as libc::c_int == 0i32 { OK_TO_CONTINUE = (*msg).text.as_ref().map_or(false, |s| !s.is_empty());
OK_TO_CONTINUE = false;
}
} else if msgtype_has_file((*msg).type_0) { } else if msgtype_has_file((*msg).type_0) {
let mut pathNfilename = (*msg) let mut pathNfilename = (*msg)
.param .param
.get(Param::File) .get(Param::File)
.map(|s| to_cstring(s)) .map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut()); .unwrap_or_else(|| std::ptr::null_mut());
if pathNfilename.is_null() { if pathNfilename.is_null() {
OK_TO_CONTINUE = false; OK_TO_CONTINUE = false;
@@ -1040,11 +1018,7 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t
time(), time(),
(*msg).type_0, (*msg).type_0,
DC_STATE_OUT_DRAFT, DC_STATE_OUT_DRAFT,
if !(*msg).text.is_null() { (*msg).text.as_ref().map(String::as_str).unwrap_or(""),
as_str((*msg).text)
} else {
""
},
(*msg).param.to_string(), (*msg).param.to_string(),
1, 1,
], ],
@@ -1258,20 +1232,20 @@ pub fn dc_marknoticed_all_chats(context: &Context) -> bool {
pub fn dc_get_chat_media( pub fn dc_get_chat_media(
context: &Context, context: &Context,
chat_id: uint32_t, chat_id: uint32_t,
msg_type: libc::c_int, msg_type: Viewtype,
msg_type2: libc::c_int, msg_type2: Viewtype,
msg_type3: libc::c_int, msg_type3: Viewtype,
) -> *mut dc_array_t { ) -> *mut dc_array_t {
context.sql.query_map( context.sql.query_map(
"SELECT id FROM msgs WHERE chat_id=? AND (type=? OR type=? OR type=?) ORDER BY timestamp, id;", "SELECT id FROM msgs WHERE chat_id=? AND (type=? OR type=? OR type=?) ORDER BY timestamp, id;",
params![ params![
chat_id as i32, chat_id as i32,
msg_type, msg_type,
if msg_type2 > 0 { if msg_type2 != Viewtype::Unknown {
msg_type2 msg_type2
} else { } else {
msg_type msg_type
}, if msg_type3 > 0 { }, if msg_type3 != Viewtype::Unknown {
msg_type3 msg_type3
} else { } else {
msg_type msg_type
@@ -1292,9 +1266,9 @@ pub unsafe fn dc_get_next_media(
context: &Context, context: &Context,
curr_msg_id: uint32_t, curr_msg_id: uint32_t,
dir: libc::c_int, dir: libc::c_int,
msg_type: libc::c_int, msg_type: Viewtype,
msg_type2: libc::c_int, msg_type2: Viewtype,
msg_type3: libc::c_int, msg_type3: Viewtype,
) -> uint32_t { ) -> uint32_t {
let mut ret_msg_id: uint32_t = 0i32 as uint32_t; let mut ret_msg_id: uint32_t = 0i32 as uint32_t;
let msg: *mut dc_msg_t = dc_msg_new_untyped(context); let msg: *mut dc_msg_t = dc_msg_new_untyped(context);
@@ -1306,7 +1280,7 @@ pub unsafe fn dc_get_next_media(
list = dc_get_chat_media( list = dc_get_chat_media(
context, context,
(*msg).chat_id, (*msg).chat_id,
if msg_type > 0i32 { if msg_type != Viewtype::Unknown {
msg_type msg_type
} else { } else {
(*msg).type_0 (*msg).type_0
@@ -1494,7 +1468,7 @@ pub unsafe fn dc_create_group_chat(
let draft_txt = let draft_txt =
CString::new(context.stock_string_repl_str(StockMessage::NewGroupDraft, as_str(chat_name))) CString::new(context.stock_string_repl_str(StockMessage::NewGroupDraft, as_str(chat_name)))
.unwrap(); .unwrap();
let grpid = as_str(dc_create_id()); let grpid = dc_create_id();
if sql::execute( if sql::execute(
context, context,
&context.sql, &context.sql,
@@ -1510,7 +1484,7 @@ pub unsafe fn dc_create_group_chat(
chat_id = sql::get_rowid(context, &context.sql, "chats", "grpid", grpid); chat_id = sql::get_rowid(context, &context.sql, "chats", "grpid", grpid);
if chat_id != 0 { if chat_id != 0 {
if 0 != dc_add_to_chat_contacts_table(context, chat_id, 1) { if 0 != dc_add_to_chat_contacts_table(context, chat_id, 1) {
let draft_msg = dc_msg_new(context, 10); let draft_msg = dc_msg_new(context, Viewtype::Text);
dc_msg_set_text(draft_msg, draft_txt.as_ptr()); dc_msg_set_text(draft_msg, draft_txt.as_ptr());
set_draft_raw(context, chat_id, draft_msg); set_draft_raw(context, chat_id, draft_msg);
dc_msg_unref(draft_msg); dc_msg_unref(draft_msg);
@@ -1561,15 +1535,18 @@ pub unsafe fn dc_add_contact_to_chat_ex(
) -> libc::c_int { ) -> libc::c_int {
let mut OK_TO_CONTINUE = true; let mut OK_TO_CONTINUE = true;
let mut success: libc::c_int = 0; let mut success: libc::c_int = 0;
let contact: *mut dc_contact_t = dc_get_contact(context, contact_id); let contact = Contact::get_by_id(context, contact_id);
let chat: *mut Chat = dc_chat_new(context); let chat: *mut Chat = dc_chat_new(context);
let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context); let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context);
if !(contact.is_null() || chat_id <= 9 as libc::c_uint) { if !(contact.is_err() || chat_id <= 9 as libc::c_uint) {
dc_reset_gossiped_timestamp(context, chat_id); dc_reset_gossiped_timestamp(context, chat_id);
let contact = contact.unwrap();
/*this also makes sure, not contacts are added to special or normal chats*/ /*this also makes sure, not contacts are added to special or normal chats*/
if !(0 == real_group_exists(context, chat_id) if !(0 == real_group_exists(context, chat_id)
|| !dc_real_contact_exists(context, contact_id) && contact_id != 1 as libc::c_uint || !Contact::real_exists_by_id(context, contact_id)
&& contact_id != DC_CONTACT_ID_SELF as u32
|| !dc_chat_load_from_db(chat, chat_id)) || !dc_chat_load_from_db(chat, chat_id))
{ {
if !(dc_is_contact_in_chat(context, chat_id, 1 as uint32_t) == 1) { if !(dc_is_contact_in_chat(context, chat_id, 1 as uint32_t) == 1) {
@@ -1591,7 +1568,7 @@ pub unsafe fn dc_add_contact_to_chat_ex(
.sql .sql
.get_config(context, "configured_addr") .get_config(context, "configured_addr")
.unwrap_or_default(); .unwrap_or_default();
if as_str((*contact).addr) != &self_addr { if contact.get_addr() != &self_addr {
// ourself is added using DC_CONTACT_ID_SELF, do not add it explicitly. // ourself is added using DC_CONTACT_ID_SELF, do not add it explicitly.
// if SELF is not in the group, members cannot be added at all. // if SELF is not in the group, members cannot be added at all.
@@ -1603,7 +1580,7 @@ pub unsafe fn dc_add_contact_to_chat_ex(
} else { } else {
// else continue and send status mail // else continue and send status mail
if (*chat).type_0 == 130 { if (*chat).type_0 == 130 {
if dc_contact_is_verified(contact) != 2 { if contact.is_verified() != VerifiedStatus::BidirectVerified {
error!( error!(
context, 0, context, 0,
"Only bidirectional verified contacts can be added to verified groups." "Only bidirectional verified contacts can be added to verified groups."
@@ -1619,17 +1596,15 @@ pub unsafe fn dc_add_contact_to_chat_ex(
} }
if OK_TO_CONTINUE { if OK_TO_CONTINUE {
if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
(*msg).type_0 = DC_MSG_TEXT; (*msg).type_0 = Viewtype::Text;
(*msg).text = to_cstring(context.stock_system_msg( (*msg).text = Some(context.stock_system_msg(
StockMessage::MsgAddMember, StockMessage::MsgAddMember,
as_str((*contact).addr), contact.get_addr(),
"", "",
DC_CONTACT_ID_SELF as uint32_t, DC_CONTACT_ID_SELF as uint32_t,
)); ));
(*msg).param.set_int(Param::Cmd, 4); (*msg).param.set_int(Param::Cmd, 4);
if !(*contact).addr.is_null() { (*msg).param.set(Param::Arg, contact.get_addr());
(*msg).param.set(Param::Arg, as_str((*contact).addr));
}
(*msg).param.set_int(Param::Arg2, flags); (*msg).param.set_int(Param::Arg2, flags);
(*msg).id = dc_send_msg(context, chat_id, msg); (*msg).id = dc_send_msg(context, chat_id, msg);
context.call_cb( context.call_cb(
@@ -1646,7 +1621,6 @@ pub unsafe fn dc_add_contact_to_chat_ex(
} }
} }
dc_chat_unref(chat); dc_chat_unref(chat);
dc_contact_unref(contact);
dc_msg_unref(msg); dc_msg_unref(msg);
success success
@@ -1708,13 +1682,12 @@ pub unsafe fn dc_remove_contact_from_chat(
chat_id: u32, chat_id: u32,
contact_id: u32, contact_id: u32,
) -> libc::c_int { ) -> libc::c_int {
let mut success: libc::c_int = 0; let mut success = 0;
let contact: *mut dc_contact_t = dc_get_contact(context, contact_id);
let chat: *mut Chat = dc_chat_new(context); let chat: *mut Chat = dc_chat_new(context);
let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context); let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context);
if !(chat_id <= 9 as libc::c_uint if !(chat_id <= 9 as libc::c_uint
|| contact_id <= 9 as libc::c_uint && contact_id != 1 as libc::c_uint) || contact_id <= 9 as libc::c_uint && contact_id != DC_CONTACT_ID_SELF as u32)
{ {
/* we do not check if "contact_id" exists but just delete all records with the id from chats_contacts */ /* we do not check if "contact_id" exists but just delete all records with the id from chats_contacts */
/* this allows to delete pending references to deleted contacts. Of course, this should _not_ happen. */ /* this allows to delete pending references to deleted contacts. Of course, this should _not_ happen. */
@@ -1728,29 +1701,27 @@ pub unsafe fn dc_remove_contact_from_chat(
); );
} else { } else {
/* we should respect this - whatever we send to the group, it gets discarded anyway! */ /* we should respect this - whatever we send to the group, it gets discarded anyway! */
if !contact.is_null() { if let Ok(contact) = Contact::get_by_id(context, contact_id) {
if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
(*msg).type_0 = DC_MSG_TEXT; (*msg).type_0 = Viewtype::Text;
if (*contact).id == 1 as libc::c_uint { if contact.id == DC_CONTACT_ID_SELF as u32 {
dc_set_group_explicitly_left(context, (*chat).grpid); dc_set_group_explicitly_left(context, (*chat).grpid);
(*msg).text = to_cstring(context.stock_system_msg( (*msg).text = Some(context.stock_system_msg(
StockMessage::MsgGroupLeft, StockMessage::MsgGroupLeft,
"", "",
"", "",
DC_CONTACT_ID_SELF as u32, DC_CONTACT_ID_SELF as u32,
)); ));
} else { } else {
(*msg).text = to_cstring(context.stock_system_msg( (*msg).text = Some(context.stock_system_msg(
StockMessage::MsgDelMember, StockMessage::MsgDelMember,
as_str((*contact).addr), contact.get_addr(),
"", "",
DC_CONTACT_ID_SELF as u32, DC_CONTACT_ID_SELF as u32,
)); ));
} }
(*msg).param.set_int(Param::Cmd, 5); (*msg).param.set_int(Param::Cmd, 5);
if !(*contact).addr.is_null() { (*msg).param.set(Param::Arg, contact.get_addr());
(*msg).param.set(Param::Arg, as_str((*contact).addr));
}
(*msg).id = dc_send_msg(context, chat_id, msg); (*msg).id = dc_send_msg(context, chat_id, msg);
context.call_cb( context.call_cb(
Event::MSGS_CHANGED, Event::MSGS_CHANGED,
@@ -1775,7 +1746,6 @@ pub unsafe fn dc_remove_contact_from_chat(
} }
dc_chat_unref(chat); dc_chat_unref(chat);
dc_contact_unref(contact);
dc_msg_unref(msg); dc_msg_unref(msg);
success success
@@ -1845,8 +1815,8 @@ pub unsafe fn dc_set_chat_name(
.is_ok() .is_ok()
{ {
if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
(*msg).type_0 = DC_MSG_TEXT; (*msg).type_0 = Viewtype::Text;
(*msg).text = to_cstring(context.stock_system_msg( (*msg).text = Some(context.stock_system_msg(
StockMessage::MsgGrpName, StockMessage::MsgGrpName,
as_str((*chat).name), as_str((*chat).name),
as_str(new_name), as_str(new_name),
@@ -1917,8 +1887,8 @@ pub unsafe fn dc_set_chat_profile_image(
if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 { if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
(*msg).param.set_int(Param::Cmd, 3); (*msg).param.set_int(Param::Cmd, 3);
(*msg).param.set(Param::Arg, as_str(new_image_rel)); (*msg).param.set(Param::Arg, as_str(new_image_rel));
(*msg).type_0 = DC_MSG_TEXT; (*msg).type_0 = Viewtype::Text;
(*msg).text = to_cstring(context.stock_system_msg( (*msg).text = Some(context.stock_system_msg(
if !new_image_rel.is_null() { if !new_image_rel.is_null() {
StockMessage::MsgGrpImgChanged StockMessage::MsgGrpImgChanged
} else { } else {
@@ -1966,8 +1936,7 @@ pub unsafe fn dc_forward_msgs(
let msg = dc_msg_new_untyped(context); let msg = dc_msg_new_untyped(context);
let chat = dc_chat_new(context); let chat = dc_chat_new(context);
let contact = dc_contact_new(context); let mut created_db_entries = Vec::new();
let created_db_entries = carray_new(16);
let mut curr_timestamp: i64; let mut curr_timestamp: i64;
dc_unarchive_chat(context, chat_id); dc_unarchive_chat(context, chat_id);
@@ -2000,7 +1969,7 @@ pub unsafe fn dc_forward_msgs(
break; break;
} }
let original_param = (*msg).param.clone(); let original_param = (*msg).param.clone();
if (*msg).from_id != 1 { if (*msg).from_id != DC_CONTACT_ID_SELF as u32 {
(*msg).param.set_int(Param::Forwarded, 1); (*msg).param.set_int(Param::Forwarded, 1);
} }
(*msg).param.remove(Param::GuranteeE2ee); (*msg).param.remove(Param::GuranteeE2ee);
@@ -2034,33 +2003,18 @@ pub unsafe fn dc_forward_msgs(
new_msg_id = prepare_msg_raw(context, chat, msg, fresh10); new_msg_id = prepare_msg_raw(context, chat, msg, fresh10);
dc_job_send_msg(context, new_msg_id); dc_job_send_msg(context, new_msg_id);
} }
carray_add( created_db_entries.push(chat_id);
created_db_entries, created_db_entries.push(new_msg_id);
chat_id as uintptr_t as *mut libc::c_void,
0 as *mut libc::c_uint,
);
carray_add(
created_db_entries,
new_msg_id as uintptr_t as *mut libc::c_void,
0 as *mut libc::c_uint,
);
} }
} }
if !created_db_entries.is_null() { for i in (0..created_db_entries.len()).step_by(2) {
let mut i = 0u32; context.call_cb(
let icnt = carray_count(created_db_entries); Event::MSGS_CHANGED,
while i < icnt { created_db_entries[i] as uintptr_t,
context.call_cb( created_db_entries[i + 1] as uintptr_t,
Event::MSGS_CHANGED, );
carray_get(created_db_entries, i) as uintptr_t,
carray_get(created_db_entries, i.wrapping_add(1)) as uintptr_t,
);
i = i.wrapping_add(2);
}
carray_free(created_db_entries);
} }
dc_contact_unref(contact);
dc_msg_unref(msg); dc_msg_unref(msg);
dc_chat_unref(chat); dc_chat_unref(chat);
} }
@@ -2094,7 +2048,10 @@ pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char {
let mut ret: *mut libc::c_char = std::ptr::null_mut(); let mut ret: *mut libc::c_char = std::ptr::null_mut();
if (*chat).type_0 == 100 && (*chat).param.exists(Param::Selftalk) { if (*chat).type_0 == 100 && (*chat).param.exists(Param::Selftalk) {
ret = to_cstring((*chat).context.stock_str(StockMessage::SelfTalkSubTitle)); ret = (*chat)
.context
.stock_str(StockMessage::SelfTalkSubTitle)
.strdup();
} else if (*chat).type_0 == 100 { } else if (*chat).type_0 == 100 {
let ret_raw: String = (*chat) let ret_raw: String = (*chat)
.context .context
@@ -2108,17 +2065,16 @@ pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char {
0, 0,
) )
.unwrap_or_else(|| "Err".into()); .unwrap_or_else(|| "Err".into());
ret = to_cstring(ret_raw); ret = ret_raw.strdup();
} else if (*chat).type_0 == 120 || (*chat).type_0 == 130 { } else if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
if (*chat).id == 1 { if (*chat).id == 1 {
ret = to_cstring((*chat).context.stock_str(StockMessage::DeadDrop)); ret = (*chat).context.stock_str(StockMessage::DeadDrop).strdup();
} else { } else {
let cnt = dc_get_chat_contact_cnt((*chat).context, (*chat).id); let cnt = dc_get_chat_contact_cnt((*chat).context, (*chat).id);
ret = to_cstring( ret = (*chat)
(*chat) .context
.context .stock_string_repl_int(StockMessage::Member, cnt)
.stock_string_repl_int(StockMessage::Member, cnt), .strdup();
);
} }
} }
return if !ret.is_null() { return if !ret.is_null() {
@@ -2144,23 +2100,29 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char
let mut image_rel: *mut libc::c_char = 0 as *mut libc::c_char; let mut image_rel: *mut libc::c_char = 0 as *mut libc::c_char;
let mut image_abs: *mut libc::c_char = 0 as *mut libc::c_char; let mut image_abs: *mut libc::c_char = 0 as *mut libc::c_char;
let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t; let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t;
let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t;
if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) { if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) {
image_rel = to_cstring((*chat).param.get(Param::ProfileImage).unwrap_or_default()); image_rel = (*chat)
.param
.get(Param::ProfileImage)
.unwrap_or_default()
.strdup();
if !image_rel.is_null() && 0 != *image_rel.offset(0isize) as libc::c_int { if !image_rel.is_null() && 0 != *image_rel.offset(0isize) as libc::c_int {
image_abs = dc_get_abs_path((*chat).context, image_rel) image_abs = dc_get_abs_path((*chat).context, image_rel)
} else if (*chat).type_0 == 100i32 { } else if (*chat).type_0 == 100i32 {
contacts = dc_get_chat_contacts((*chat).context, (*chat).id); contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
if !(*contacts).is_empty() { if !(*contacts).is_empty() {
contact = dc_get_contact((*chat).context, (*contacts).get_id(0)); if let Ok(contact) = Contact::get_by_id((*chat).context, (*contacts).get_id(0)) {
image_abs = dc_contact_get_profile_image(contact) if let Some(img) = contact.get_profile_image() {
image_abs = img.strdup();
}
}
} }
} }
} }
free(image_rel as *mut libc::c_void); free(image_rel as *mut libc::c_void);
dc_array_unref(contacts); dc_array_unref(contacts);
dc_contact_unref(contact);
image_abs image_abs
} }
@@ -2168,13 +2130,14 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char
pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t { pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t {
let mut color: uint32_t = 0i32 as uint32_t; let mut color: uint32_t = 0i32 as uint32_t;
let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t; let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t;
let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t;
if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) { if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) {
if (*chat).type_0 == 100i32 { if (*chat).type_0 == 100i32 {
contacts = dc_get_chat_contacts((*chat).context, (*chat).id); contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
if !(*contacts).is_empty() { if !(*contacts).is_empty() {
contact = dc_get_contact((*chat).context, (*contacts).get_id(0)); if let Ok(contact) = Contact::get_by_id((*chat).context, (*contacts).get_id(0)) {
color = dc_str_to_color((*contact).addr) as uint32_t color = contact.get_color();
}
} }
} else { } else {
color = dc_str_to_color((*chat).name) as uint32_t color = dc_str_to_color((*chat).name) as uint32_t
@@ -2182,7 +2145,6 @@ pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t {
} }
dc_array_unref(contacts); dc_array_unref(contacts);
dc_contact_unref(contact);
color color
} }
@@ -2287,7 +2249,7 @@ pub fn dc_add_device_msg(context: &Context, chat_id: uint32_t, text: *const libc
2, 2,
2, 2,
unsafe {dc_create_smeared_timestamp(context)}, unsafe {dc_create_smeared_timestamp(context)},
DC_MSG_TEXT, Viewtype::Text,
DC_STATE_IN_NOTICED, DC_STATE_IN_NOTICED,
as_str(text), as_str(text),
as_str(rfc724_mid), as_str(rfc724_mid),

View File

@@ -1102,14 +1102,14 @@ unsafe fn moz_autoconfigure(
tag_config: 0, tag_config: 0,
}; };
let url_c = to_cstring(url); let url_c = url.strdup();
let xml_raw = read_autoconf_file(context, url_c); let xml_raw = read_autoconf_file(context, url_c);
free(url_c as *mut libc::c_void); free(url_c as *mut libc::c_void);
if xml_raw.is_null() { if xml_raw.is_null() {
return None; return None;
} }
moz_ac.in_emaillocalpart = to_cstring(&param_in.addr); moz_ac.in_emaillocalpart = param_in.addr.strdup();
let p = strchr(moz_ac.in_emaillocalpart, '@' as i32); let p = strchr(moz_ac.in_emaillocalpart, '@' as i32);
if p.is_null() { if p.is_null() {
@@ -1166,7 +1166,7 @@ unsafe fn moz_autoconfigure_text_cb(
let mut moz_ac: *mut moz_autoconfigure_t = userdata as *mut moz_autoconfigure_t; let mut moz_ac: *mut moz_autoconfigure_t = userdata as *mut moz_autoconfigure_t;
let mut val: *mut libc::c_char = dc_strdup(text); let mut val: *mut libc::c_char = dc_strdup(text);
dc_trim(val); dc_trim(val);
let addr = to_cstring(&(*moz_ac).in_0.addr); let addr = (*moz_ac).in_0.addr.strdup();
dc_str_replace( dc_str_replace(
&mut val, &mut val,
b"%EMAILADDRESS%\x00" as *const u8 as *const libc::c_char, b"%EMAILADDRESS%\x00" as *const u8 as *const libc::c_char,
@@ -1306,7 +1306,7 @@ fn read_autoconf_file(context: &Context, url: *const libc::c_char) -> *mut libc:
.send() .send()
.and_then(|mut res| res.text()) .and_then(|mut res| res.text())
{ {
Ok(res) => unsafe { to_cstring(res) }, Ok(res) => unsafe { res.strdup() },
Err(_err) => { Err(_err) => {
info!(context, 0, "Can\'t read file.",); info!(context, 0, "Can\'t read file.",);
@@ -1322,7 +1322,7 @@ unsafe fn outlk_autodiscover(
) -> Option<dc_loginparam_t> { ) -> Option<dc_loginparam_t> {
let current_block: u64; let current_block: u64;
let mut xml_raw: *mut libc::c_char = 0 as *mut libc::c_char; let mut xml_raw: *mut libc::c_char = 0 as *mut libc::c_char;
let mut url = to_cstring(url__); let mut url = url__.strdup();
let mut outlk_ad = outlk_autodiscover_t { let mut outlk_ad = outlk_autodiscover_t {
in_0: param_in, in_0: param_in,
out: dc_loginparam_new(), out: dc_loginparam_new(),

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@ lazy_static! {
struct Dehtml { struct Dehtml {
strbuilder: String, strbuilder: String,
add_text: AddText, add_text: AddText,
last_href: *mut libc::c_char, last_href: Option<String>,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@@ -32,7 +32,7 @@ pub unsafe fn dc_dehtml(buf_terminated: *mut libc::c_char) -> *mut libc::c_char
let mut dehtml = Dehtml { let mut dehtml = Dehtml {
strbuilder: String::with_capacity(strlen(buf_terminated)), strbuilder: String::with_capacity(strlen(buf_terminated)),
add_text: AddText::YesRemoveLineEnds, add_text: AddText::YesRemoveLineEnds,
last_href: 0 as *mut libc::c_char, last_href: None,
}; };
let mut saxparser = dc_saxparser_t { let mut saxparser = dc_saxparser_t {
starttag_cb: None, starttag_cb: None,
@@ -51,9 +51,8 @@ pub unsafe fn dc_dehtml(buf_terminated: *mut libc::c_char) -> *mut libc::c_char
); );
dc_saxparser_set_text_handler(&mut saxparser, Some(dehtml_text_cb)); dc_saxparser_set_text_handler(&mut saxparser, Some(dehtml_text_cb));
dc_saxparser_parse(&mut saxparser, buf_terminated); dc_saxparser_parse(&mut saxparser, buf_terminated);
free(dehtml.last_href as *mut libc::c_void);
to_cstring(dehtml.strbuilder) dehtml.strbuilder.strdup()
} }
unsafe fn dehtml_text_cb( unsafe fn dehtml_text_cb(
@@ -66,7 +65,11 @@ unsafe fn dehtml_text_cb(
if dehtml.add_text == AddText::YesPreserveLineEnds if dehtml.add_text == AddText::YesPreserveLineEnds
|| dehtml.add_text == AddText::YesRemoveLineEnds || dehtml.add_text == AddText::YesRemoveLineEnds
{ {
let last_added = std::ffi::CStr::from_ptr(text).to_string_lossy(); let last_added = std::ffi::CStr::from_ptr(text)
.to_str()
.expect("invalid utf8");
// TODO: why does len does not match?
// assert_eq!(last_added.len(), len as usize);
if dehtml.add_text == AddText::YesRemoveLineEnds { if dehtml.add_text == AddText::YesRemoveLineEnds {
dehtml.strbuilder += LINE_RE.replace_all(last_added.as_ref(), "\r").as_ref(); dehtml.strbuilder += LINE_RE.replace_all(last_added.as_ref(), "\r").as_ref();
@@ -86,14 +89,10 @@ unsafe fn dehtml_endtag_cb(userdata: *mut libc::c_void, tag: *const libc::c_char
dehtml.add_text = AddText::YesRemoveLineEnds; dehtml.add_text = AddText::YesRemoveLineEnds;
} }
"a" => { "a" => {
if !dehtml.last_href.is_null() { if let Some(ref last_href) = dehtml.last_href.take() {
dehtml.strbuilder += "]("; dehtml.strbuilder += "](";
dehtml.strbuilder += std::ffi::CStr::from_ptr((*dehtml).last_href) dehtml.strbuilder += last_href;
.to_string_lossy()
.as_ref();
dehtml.strbuilder += ")"; dehtml.strbuilder += ")";
free(dehtml.last_href as *mut libc::c_void);
dehtml.last_href = 0 as *mut libc::c_char;
} }
} }
"b" | "strong" => { "b" | "strong" => {
@@ -131,12 +130,13 @@ unsafe fn dehtml_starttag_cb(
dehtml.add_text = AddText::YesPreserveLineEnds; dehtml.add_text = AddText::YesPreserveLineEnds;
} }
"a" => { "a" => {
free(dehtml.last_href as *mut libc::c_void); let text_c = std::ffi::CStr::from_ptr(dc_attr_find(
dehtml.last_href = dc_strdup_keep_null(dc_attr_find(
attr, attr,
b"href\x00" as *const u8 as *const libc::c_char, b"href\x00" as *const u8 as *const libc::c_char,
)); ));
if !dehtml.last_href.is_null() { let text_r = text_c.to_str().expect("invalid utf8");
if !text_r.is_empty() {
dehtml.last_href = Some(text_r.to_string());
dehtml.strbuilder += "["; dehtml.strbuilder += "[";
} }
} }

View File

@@ -66,7 +66,7 @@ pub unsafe fn dc_e2ee_encrypt(
mut in_out_message: *mut mailmime, mut in_out_message: *mut mailmime,
helper: &mut dc_e2ee_helper_t, helper: &mut dc_e2ee_helper_t,
) { ) {
let mut current_block: u64 = 0; let mut ok_to_continue = true;
let mut col: libc::c_int = 0i32; let mut col: libc::c_int = 0i32;
let mut do_encrypt: libc::c_int = 0i32; let mut do_encrypt: libc::c_int = 0i32;
/*just a pointer into mailmime structure, must not be freed*/ /*just a pointer into mailmime structure, must not be freed*/
@@ -115,11 +115,22 @@ pub unsafe fn dc_e2ee_encrypt(
|| 0 != e2ee_guaranteed) || 0 != e2ee_guaranteed)
{ {
let peerstate = peerstate.unwrap(); let peerstate = peerstate.unwrap();
info!(
context,
0, "dc_e2ee_encrypt {} has peerstate", recipient_addr
);
if let Some(key) = peerstate.peek_key(min_verified as usize) { if let Some(key) = peerstate.peek_key(min_verified as usize) {
keyring.add_owned(key.clone()); keyring.add_owned(key.clone());
peerstates.push(peerstate); peerstates.push(peerstate);
} }
} else { } else {
info!(
context,
0,
"dc_e2ee_encrypt {} HAS NO peerstate {}",
recipient_addr,
peerstate.is_some()
);
do_encrypt = 0i32; do_encrypt = 0i32;
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */ /* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
break; break;
@@ -177,16 +188,12 @@ pub unsafe fn dc_e2ee_encrypt(
let p = peerstates[i as usize] let p = peerstates[i as usize]
.render_gossip_header(min_verified as usize); .render_gossip_header(min_verified as usize);
if p.is_some() { if let Some(header) = p {
let header = to_cstring(p.unwrap());
mailimf_fields_add( mailimf_fields_add(
imffields_encrypted, imffields_encrypted,
mailimf_field_new_custom( mailimf_field_new_custom(
strdup( "Autocrypt-Gossip".strdup(),
b"Autocrypt-Gossip\x00" as *const u8 header.strdup(),
as *const libc::c_char,
),
header,
), ),
); );
} }
@@ -287,7 +294,7 @@ pub unsafe fn dc_e2ee_encrypt(
); );
mailmime_write_mem(plain, &mut col, message_to_encrypt); mailmime_write_mem(plain, &mut col, message_to_encrypt);
if (*plain).str_0.is_null() || (*plain).len <= 0 { if (*plain).str_0.is_null() || (*plain).len <= 0 {
current_block = 14181132614457621749; ok_to_continue = false;
} else { } else {
if let Some(ctext_v) = dc_pgp_pk_encrypt( if let Some(ctext_v) = dc_pgp_pk_encrypt(
(*plain).str_0 as *const libc::c_void, (*plain).str_0 as *const libc::c_void,
@@ -296,8 +303,8 @@ pub unsafe fn dc_e2ee_encrypt(
sign_key.as_ref(), sign_key.as_ref(),
) { ) {
let ctext_bytes = ctext_v.len(); let ctext_bytes = ctext_v.len();
let ctext = to_cstring(ctext_v); let ctext = ctext_v.strdup();
(*helper).cdata_to_free = ctext as *mut _; helper.cdata_to_free = ctext as *mut _;
/* create MIME-structure that will contain the encrypted text */ /* create MIME-structure that will contain the encrypted text */
let mut encrypted_part: *mut mailmime = new_data_part( let mut encrypted_part: *mut mailmime = new_data_part(
@@ -343,27 +350,19 @@ pub unsafe fn dc_e2ee_encrypt(
(*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part; (*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part;
(*encrypted_part).mm_parent = in_out_message; (*encrypted_part).mm_parent = in_out_message;
mailmime_free(message_to_encrypt); mailmime_free(message_to_encrypt);
(*helper).encryption_successfull = 1i32; helper.encryption_successfull = 1i32;
current_block = 13824533195664196414;
} }
} }
} else {
current_block = 13824533195664196414;
} }
match current_block { if ok_to_continue {
14181132614457621749 => {} let aheader = Aheader::new(addr, public_key, prefer_encrypt);
_ => { mailimf_fields_add(
let aheader = Aheader::new(addr, public_key, prefer_encrypt); imffields_unprotected,
let rendered = to_cstring(aheader.to_string()); mailimf_field_new_custom(
"Autocrypt".strdup(),
mailimf_fields_add( aheader.to_string().strdup(),
imffields_unprotected, ),
mailimf_field_new_custom( );
strdup(b"Autocrypt\x00" as *const u8 as *const libc::c_char),
rendered,
),
);
}
} }
} }
} }
@@ -384,7 +383,7 @@ unsafe fn new_data_part(
default_content_type: *mut libc::c_char, default_content_type: *mut libc::c_char,
default_encoding: libc::c_int, default_encoding: libc::c_int,
) -> *mut mailmime { ) -> *mut mailmime {
let mut current_block: u64; let mut ok_to_continue = true;
//char basename_buf[PATH_MAX]; //char basename_buf[PATH_MAX];
let mut encoding: *mut mailmime_mechanism; let mut encoding: *mut mailmime_mechanism;
let content: *mut mailmime_content; let content: *mut mailmime_content;
@@ -404,7 +403,7 @@ unsafe fn new_data_part(
} }
content = mailmime_content_new_with_str(content_type_str); content = mailmime_content_new_with_str(content_type_str);
if content.is_null() { if content.is_null() {
current_block = 16266721588079097885; ok_to_continue = false;
} else { } else {
do_encoding = 1i32; do_encoding = 1i32;
if (*(*content).ct_type).tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int { if (*(*content).ct_type).tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int {
@@ -432,54 +431,44 @@ unsafe fn new_data_part(
} }
encoding = mailmime_mechanism_new(encoding_type, 0 as *mut libc::c_char); encoding = mailmime_mechanism_new(encoding_type, 0 as *mut libc::c_char);
if encoding.is_null() { if encoding.is_null() {
current_block = 16266721588079097885; ok_to_continue = false;
} else {
current_block = 11057878835866523405;
} }
} else {
current_block = 11057878835866523405;
} }
match current_block { if ok_to_continue {
16266721588079097885 => {} mime_fields = mailmime_fields_new_with_data(
_ => { encoding,
mime_fields = mailmime_fields_new_with_data( 0 as *mut libc::c_char,
encoding, 0 as *mut libc::c_char,
0 as *mut libc::c_char, 0 as *mut mailmime_disposition,
0 as *mut libc::c_char, 0 as *mut mailmime_language,
0 as *mut mailmime_disposition, );
0 as *mut mailmime_language, if mime_fields.is_null() {
); ok_to_continue = false;
if mime_fields.is_null() { } else {
current_block = 16266721588079097885; mime = mailmime_new_empty(content, mime_fields);
if mime.is_null() {
mailmime_fields_free(mime_fields);
mailmime_content_free(content);
} else { } else {
mime = mailmime_new_empty(content, mime_fields); if !data.is_null()
if mime.is_null() { && data_bytes > 0
mailmime_fields_free(mime_fields); && (*mime).mm_type == MAILMIME_SINGLE as libc::c_int
mailmime_content_free(content); {
} else { mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes);
if !data.is_null()
&& data_bytes > 0
&& (*mime).mm_type == MAILMIME_SINGLE as libc::c_int
{
mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes);
}
return mime;
} }
current_block = 13668317689588454213; return mime;
} }
} }
} }
} }
match current_block {
16266721588079097885 => { if ok_to_continue == false {
if !encoding.is_null() { if !encoding.is_null() {
mailmime_mechanism_free(encoding); mailmime_mechanism_free(encoding);
} }
if !content.is_null() { if !content.is_null() {
mailmime_content_free(content); mailmime_content_free(content);
}
} }
_ => {}
} }
return 0 as *mut mailmime; return 0 as *mut mailmime;
} }
@@ -596,7 +585,7 @@ pub unsafe fn dc_e2ee_decrypt(
} }
} else if let Some(ref header) = autocryptheader { } else if let Some(ref header) = autocryptheader {
let p = Peerstate::from_header(context, header, message_time); let p = Peerstate::from_header(context, header, message_time);
p.save_to_db(&context.sql, true); assert!(p.save_to_db(&context.sql, true));
peerstate = Some(p); peerstate = Some(p);
} }
} }
@@ -841,7 +830,7 @@ unsafe fn decrypt_part(
ret_valid_signatures: &mut HashSet<String>, ret_valid_signatures: &mut HashSet<String>,
ret_decrypted_mime: *mut *mut mailmime, ret_decrypted_mime: *mut *mut mailmime,
) -> libc::c_int { ) -> libc::c_int {
let current_block: u64; let mut ok_to_continue = true;
let mime_data: *mut mailmime_data; let mime_data: *mut mailmime_data;
let mut mime_transfer_encoding: libc::c_int = MAILMIME_MECHANISM_BINARY as libc::c_int; let mut mime_transfer_encoding: libc::c_int = MAILMIME_MECHANISM_BINARY as libc::c_int;
/* mmap_string_unref()'d if set */ /* mmap_string_unref()'d if set */
@@ -889,9 +878,7 @@ unsafe fn decrypt_part(
decoded_data_bytes = (*mime_data).dt_data.dt_text.dt_length; decoded_data_bytes = (*mime_data).dt_data.dt_text.dt_length;
if decoded_data.is_null() || decoded_data_bytes <= 0 { if decoded_data.is_null() || decoded_data_bytes <= 0 {
/* no error - but no data */ /* no error - but no data */
current_block = 2554982661806928548; ok_to_continue = false;
} else {
current_block = 4488286894823169796;
} }
} else { } else {
let r: libc::c_int; let r: libc::c_int;
@@ -908,53 +895,49 @@ unsafe fn decrypt_part(
|| transfer_decoding_buffer.is_null() || transfer_decoding_buffer.is_null()
|| decoded_data_bytes <= 0 || decoded_data_bytes <= 0
{ {
current_block = 2554982661806928548; ok_to_continue = false;
} else { } else {
decoded_data = transfer_decoding_buffer; decoded_data = transfer_decoding_buffer;
current_block = 4488286894823169796;
} }
} }
match current_block { if ok_to_continue {
2554982661806928548 => {} /* encrypted, decoded data in decoded_data now ... */
_ => { if !(0 == has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int)) {
/* encrypted, decoded data in decoded_data now ... */ let add_signatures = if ret_valid_signatures.is_empty() {
if !(0 == has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int)) Some(ret_valid_signatures)
{ } else {
let add_signatures = if ret_valid_signatures.is_empty() { None
Some(ret_valid_signatures) };
} else {
None
};
/*if we already have fingerprints, do not add more; this ensures, only the fingerprints from the outer-most part are collected */ /*if we already have fingerprints, do not add more; this ensures, only the fingerprints from the outer-most part are collected */
if let Some(plain) = dc_pgp_pk_decrypt( if let Some(plain) = dc_pgp_pk_decrypt(
decoded_data as *const libc::c_void, decoded_data as *const libc::c_void,
decoded_data_bytes, decoded_data_bytes,
&private_keyring, &private_keyring,
&public_keyring_for_validate, &public_keyring_for_validate,
add_signatures, add_signatures,
) { ) {
let plain_bytes = plain.len(); let plain_bytes = plain.len();
let plain_buf = plain.as_ptr() as *const libc::c_char; let plain_buf = plain.as_ptr() as *const libc::c_char;
let mut index: size_t = 0i32 as size_t; let mut index: size_t = 0i32 as size_t;
let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime; let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime;
if mailmime_parse( if mailmime_parse(
plain_buf as *const _, plain_buf as *const _,
plain_bytes, plain_bytes,
&mut index, &mut index,
&mut decrypted_mime, &mut decrypted_mime,
) != MAIL_NO_ERROR as libc::c_int ) != MAIL_NO_ERROR as libc::c_int
|| decrypted_mime.is_null() || decrypted_mime.is_null()
{ {
if !decrypted_mime.is_null() { if !decrypted_mime.is_null() {
mailmime_free(decrypted_mime); mailmime_free(decrypted_mime);
}
} else {
*ret_decrypted_mime = decrypted_mime;
sth_decrypted = 1i32
} }
} else {
*ret_decrypted_mime = decrypted_mime;
sth_decrypted = 1i32
} }
std::mem::forget(plain);
} }
} }
} }
@@ -1084,3 +1067,69 @@ pub unsafe fn dc_ensure_secret_key_exists(context: &Context) -> libc::c_int {
success success
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mailmime_parse() {
let plain = b"Chat-Disposition-Notification-To: holger@deltachat.de
Chat-Group-ID: CovhGgau8M-
Chat-Group-Name: Delta Chat Dev
Subject: =?utf-8?Q?Chat=3A?= Delta Chat =?utf-8?Q?Dev=3A?= sidenote for
=?utf-8?Q?all=3A?= rust core master ...
Content-Type: text/plain; charset=\"utf-8\"; protected-headers=\"v1\"
Content-Transfer-Encoding: quoted-printable
sidenote for all: rust core master is broken currently ... so dont recomm=
end to try to run with desktop or ios unless you are ready to hunt bugs
-- =20
Sent with my Delta Chat Messenger: https://delta.chat";
let plain_bytes = plain.len();
let plain_buf = plain.as_ptr() as *const libc::c_char;
let mut index = 0;
let mut decrypted_mime = std::ptr::null_mut();
let res = unsafe {
mailmime_parse(
plain_buf as *const _,
plain_bytes,
&mut index,
&mut decrypted_mime,
)
};
unsafe {
let msg1 = (*decrypted_mime).mm_data.mm_message.mm_msg_mime;
let mut decoded_data = 0 as *const libc::c_char;
let mut decoded_data_bytes = 0;
let mut transfer_decoding_buffer: *mut libc::c_char = 0 as *mut libc::c_char;
assert_eq!(
mailmime_transfer_decode(
msg1,
&mut decoded_data,
&mut decoded_data_bytes,
&mut transfer_decoding_buffer,
),
1
);
println!(
"{:?}",
String::from_utf8_lossy(std::slice::from_raw_parts(
decoded_data as *const u8,
decoded_data_bytes as usize,
))
);
free(decoded_data as *mut _);
}
assert_eq!(res, 0);
assert!(!decrypted_mime.is_null());
unsafe { free(decrypted_mime as *mut _) };
}
}

View File

@@ -5,6 +5,7 @@ use mmime::mmapstring::*;
use mmime::other::*; use mmime::other::*;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use crate::config::Config;
use crate::constants::*; use crate::constants::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_chat::*; use crate::dc_chat::*;
@@ -13,6 +14,7 @@ use crate::dc_e2ee::*;
use crate::dc_job::*; use crate::dc_job::*;
use crate::dc_msg::*; use crate::dc_msg::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::error::*;
use crate::key::*; use crate::key::*;
use crate::param::*; use crate::param::*;
use crate::pgp::*; use crate::pgp::*;
@@ -98,101 +100,85 @@ pub unsafe fn dc_imex_has_backup(
} }
pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
let current_block: u64;
let mut success: libc::c_int = 0i32;
let mut setup_code: *mut libc::c_char;
let mut setup_file_content: *mut libc::c_char = 0 as *mut libc::c_char;
let mut setup_file_name: *mut libc::c_char = 0 as *mut libc::c_char; let mut setup_file_name: *mut libc::c_char = 0 as *mut libc::c_char;
let chat_id: uint32_t;
let mut msg: *mut dc_msg_t = 0 as *mut dc_msg_t; let mut msg: *mut dc_msg_t = 0 as *mut dc_msg_t;
let msg_id: uint32_t; if dc_alloc_ongoing(context) == 0 {
if 0 == dc_alloc_ongoing(context) { return std::ptr::null_mut();
return 0 as *mut libc::c_char;
} }
setup_code = to_cstring(dc_create_setup_code(context)); let setup_code = dc_create_setup_code(context);
if !setup_code.is_null() { /* this may require a keypair to be created. this may take a second ... */
/* this may require a keypair to be created. this may take a second ... */ if !context
if !context .running_state
.running_state .clone()
.clone() .read()
.read() .unwrap()
.unwrap() .shall_stop_ongoing
.shall_stop_ongoing {
{ if let Ok(setup_file_content) = dc_render_setup_file(context, &setup_code) {
setup_file_content = dc_render_setup_file(context, setup_code); let setup_file_content_c = CString::yolo(setup_file_content.as_str());
if !setup_file_content.is_null() { /* encrypting may also take a while ... */
/* encrypting may also take a while ... */ if !context
if !context .running_state
.running_state .clone()
.clone() .read()
.read() .unwrap()
.unwrap() .shall_stop_ongoing
.shall_stop_ongoing {
{ setup_file_name = dc_get_fine_pathNfilename(
setup_file_name = dc_get_fine_pathNfilename( context,
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
b"autocrypt-setup-message.html\x00" as *const u8 as *const libc::c_char,
);
if !(setup_file_name.is_null()
|| 0 == dc_write_file(
context, context,
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, setup_file_name,
b"autocrypt-setup-message.html\x00" as *const u8 as *const libc::c_char, setup_file_content_c.as_ptr() as *const libc::c_void,
); setup_file_content_c.as_bytes().len(),
if !(setup_file_name.is_null() ))
|| 0 == dc_write_file( {
context, let chat_id = dc_create_chat_by_contact_id(context, 1i32 as uint32_t);
setup_file_name, if !(chat_id == 0i32 as libc::c_uint) {
setup_file_content as *const libc::c_void, msg = dc_msg_new_untyped(context);
strlen(setup_file_content), (*msg).type_0 = Viewtype::File;
)) (*msg).param.set(Param::File, as_str(setup_file_name));
{
chat_id = dc_create_chat_by_contact_id(context, 1i32 as uint32_t);
if !(chat_id == 0i32 as libc::c_uint) {
msg = dc_msg_new_untyped(context);
(*msg).type_0 = DC_MSG_FILE;
(*msg).param.set(Param::File, as_str(setup_file_name));
(*msg) (*msg)
.param .param
.set(Param::MimeType, "application/autocrypt-setup"); .set(Param::MimeType, "application/autocrypt-setup");
(*msg).param.set_int(Param::Cmd, 6); (*msg).param.set_int(Param::Cmd, 6);
(*msg).param.set_int(Param::ForcePlaintext, 2); (*msg).param.set_int(Param::ForcePlaintext, 2);
if !context if !context
.running_state .running_state
.clone() .clone()
.read() .read()
.unwrap() .unwrap()
.shall_stop_ongoing .shall_stop_ongoing
{ {
msg_id = dc_send_msg(context, chat_id, msg); let msg_id = dc_send_msg(context, chat_id, msg);
if !(msg_id == 0i32 as libc::c_uint) { if msg_id != 0 {
dc_msg_unref(msg);
msg = 0 as *mut dc_msg_t;
info!(context, 0, "Wait for setup message being sent ...",);
loop {
if context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
break;
}
std::thread::sleep(std::time::Duration::from_secs(1));
msg = dc_get_msg(context, msg_id);
if 0 != dc_msg_is_sent(msg) {
info!(context, 0, "... setup message sent.",);
break;
}
dc_msg_unref(msg); dc_msg_unref(msg);
msg = 0 as *mut dc_msg_t; msg = 0 as *mut dc_msg_t
info!(context, 0, "Wait for setup message being sent ...",);
loop {
if context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
current_block = 6116957410927263949;
break;
}
std::thread::sleep(std::time::Duration::from_secs(1));
msg = dc_get_msg(context, msg_id);
if 0 != dc_msg_is_sent(msg) {
current_block = 6450636197030046351;
break;
}
dc_msg_unref(msg);
msg = 0 as *mut dc_msg_t
}
match current_block {
6116957410927263949 => {}
_ => {
info!(context, 0, "... setup message sent.",);
success = 1;
}
}
} }
} }
} }
@@ -201,88 +187,77 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
} }
} }
} }
if 0 == success {
free(setup_code as *mut libc::c_void);
setup_code = 0 as *mut libc::c_char
}
free(setup_file_name as *mut libc::c_void); free(setup_file_name as *mut libc::c_void);
free(setup_file_content as *mut libc::c_void);
dc_msg_unref(msg); dc_msg_unref(msg);
dc_free_ongoing(context); dc_free_ongoing(context);
setup_code setup_code.strdup()
} }
pub unsafe extern "C" fn dc_render_setup_file( pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result<String> {
context: &Context, ensure!(
passphrase: *const libc::c_char, passphrase.len() >= 2,
) -> *mut libc::c_char { "Passphrase must be at least 2 chars long."
let stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; );
unsafe {
let mut passphrase_begin: [libc::c_char; 8] = [0; 8]; ensure!(
let mut ret_setupfilecontent: *mut libc::c_char = 0 as *mut libc::c_char; !(dc_ensure_secret_key_exists(context) == 0),
if !(passphrase.is_null() || strlen(passphrase) < 2) { "No secret key available."
strncpy(passphrase_begin.as_mut_ptr(), passphrase, 2); );
passphrase_begin[2usize] = 0i32 as libc::c_char;
/* create the payload */
if !(0 == dc_ensure_secret_key_exists(context)) {
let self_addr = context
.sql
.get_config(context, "configured_addr")
.unwrap_or_default();
let curr_private_key = Key::from_self_private(context, self_addr, &context.sql);
let e2ee_enabled = context
.sql
.get_config_int(context, "e2ee_enabled")
.unwrap_or_else(|| 1);
let headers = if 0 != e2ee_enabled {
Some(("Autocrypt-Prefer-Encrypt", "mutual"))
} else {
None
};
if let Some(payload_key_asc) = curr_private_key.map(|k| k.to_asc_c(headers)) {
if let Some(encr) = dc_pgp_symm_encrypt(
passphrase,
payload_key_asc as *const libc::c_void,
strlen(payload_key_asc),
) {
let encr_string_c = CString::new(encr).unwrap();
let mut encr_string = strdup(encr_string_c.as_ptr());
free(payload_key_asc as *mut libc::c_void);
let replacement: *mut libc::c_char =
dc_mprintf(b"-----BEGIN PGP MESSAGE-----\r\nPassphrase-Format: numeric9x4\r\nPassphrase-Begin: %s\x00"
as *const u8 as *const libc::c_char,
passphrase_begin.as_mut_ptr());
dc_str_replace(
&mut encr_string,
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
replacement,
);
free(replacement as *mut libc::c_void);
let setup_message_title =
CString::new(context.stock_str(StockMessage::AcSetupMsgSubject).as_ref())
.unwrap();
let setup_message_body = context.stock_str(StockMessage::AcSetupMsgBody);
let msg_body_head: &str = setup_message_body.split('\r').next().unwrap();
let msg_body_html = CString::new(msg_body_head.replace("\n", "<br>")).unwrap();
ret_setupfilecontent =
dc_mprintf(b"<!DOCTYPE html>\r\n<html>\r\n<head>\r\n<title>%s</title>\r\n</head>\r\n<body>\r\n<h1>%s</h1>\r\n<p>%s</p>\r\n<pre>\r\n%s\r\n</pre>\r\n</body>\r\n</html>\r\n\x00"
as *const u8 as *const libc::c_char,
setup_message_title.as_ptr(),
setup_message_title.as_ptr(),
msg_body_html.as_ptr(),
encr_string);
free(encr_string as *mut libc::c_void);
}
}
}
} }
sqlite3_finalize(stmt); let self_addr = context
.get_config(Config::ConfiguredAddr)
.ok_or(format_err!("Failed to get self address."))?;
let private_key = Key::from_self_private(context, self_addr, &context.sql)
.ok_or(format_err!("Failed to get private key."))?;
let ac_headers = match context
.sql
.get_config_int(context, Config::E2eeEnabled)
.unwrap_or(1)
{
0 => None,
_ => Some(("Autocrypt-Prefer-Encrypt", "mutual")),
};
let private_key_asc = private_key.to_asc(ac_headers);
let encr = {
let private_key_asc_c = CString::yolo(private_key_asc);
let passphrase_c = CString::yolo(passphrase);
dc_pgp_symm_encrypt(
passphrase_c.as_ptr(),
private_key_asc_c.as_ptr() as *const libc::c_void,
private_key_asc_c.as_bytes().len(),
)
.ok_or(format_err!("Failed to encrypt private key."))?
};
let replacement = format!(
concat!(
"-----BEGIN PGP MESSAGE-----\r\n",
"Passphrase-Format: numeric9x4\r\n",
"Passphrase-Begin: {}"
),
&passphrase[..2]
);
let pgp_msg = encr.replace("-----BEGIN PGP MESSAGE-----", &replacement);
ret_setupfilecontent let msg_subj = context.stock_str(StockMessage::AcSetupMsgSubject);
let msg_body = context.stock_str(StockMessage::AcSetupMsgBody);
let msg_body_html = msg_body.replace("\r", "").replace("\n", "<br>");
Ok(format!(
concat!(
"<!DOCTYPE html>\r\n",
"<html>\r\n",
" <head>\r\n",
" <title>{}</title>\r\n",
" </head>\r\n",
" <body>\r\n",
" <h1>{}</h1>\r\n",
" <p>{}</p>\r\n",
" <pre>\r\n{}\r\n</pre>\r\n",
" </body>\r\n",
"</html>\r\n"
),
msg_subj, msg_subj, msg_body_html, pgp_msg
))
} }
pub fn dc_create_setup_code(_context: &Context) -> String { pub fn dc_create_setup_code(_context: &Context) -> String {
@@ -351,7 +326,7 @@ pub unsafe fn dc_continue_key_transfer(
armored_key = dc_decrypt_setup_file(context, norm_sc, filecontent); armored_key = dc_decrypt_setup_file(context, norm_sc, filecontent);
if armored_key.is_null() { if armored_key.is_null() {
warn!(context, 0, "Cannot decrypt Autocrypt Setup Message.",); warn!(context, 0, "Cannot decrypt Autocrypt Setup Message.",);
} else if !(0 == set_self_key(context, armored_key, 1i32)) { } else if set_self_key(context, armored_key, 1) {
/*set default*/ /*set default*/
/* error already logged */ /* error already logged */
success = 1i32 success = 1i32
@@ -368,12 +343,11 @@ pub unsafe fn dc_continue_key_transfer(
success success
} }
// TODO should return bool /rtn
fn set_self_key( fn set_self_key(
context: &Context, context: &Context,
armored_c: *const libc::c_char, armored_c: *const libc::c_char,
set_default: libc::c_int, set_default: libc::c_int,
) -> libc::c_int { ) -> bool {
assert!(!armored_c.is_null(), "invalid buffer"); assert!(!armored_c.is_null(), "invalid buffer");
let armored = as_str(armored_c); let armored = as_str(armored_c);
@@ -383,7 +357,7 @@ fn set_self_key(
if keys.is_none() { if keys.is_none() {
error!(context, 0, "File does not contain a valid private key.",); error!(context, 0, "File does not contain a valid private key.",);
return 0; return false;
} }
let (private_key, public_key, header) = keys.unwrap(); let (private_key, public_key, header) = keys.unwrap();
@@ -397,7 +371,7 @@ fn set_self_key(
) )
.is_err() .is_err()
{ {
return 0; return false;
} }
if 0 != set_default { if 0 != set_default {
@@ -409,7 +383,7 @@ fn set_self_key(
) )
.is_err() .is_err()
{ {
return 0; return false;
} }
} else { } else {
error!(context, 0, "File does not contain a private key.",); error!(context, 0, "File does not contain a private key.",);
@@ -419,7 +393,7 @@ fn set_self_key(
if self_addr.is_none() { if self_addr.is_none() {
error!(context, 0, "Missing self addr"); error!(context, 0, "Missing self addr");
return 0; return false;
} }
if !dc_key_save_self_keypair( if !dc_key_save_self_keypair(
@@ -431,20 +405,20 @@ fn set_self_key(
&context.sql, &context.sql,
) { ) {
error!(context, 0, "Cannot save keypair."); error!(context, 0, "Cannot save keypair.");
return 0; return false;
} }
match preferencrypt.map(|s| s.as_str()) { match preferencrypt.map(|s| s.as_str()) {
Some("") => 0, Some("") => false,
Some("nopreference") => context Some("nopreference") => context
.sql .sql
.set_config_int(context, "e2ee_enabled", 0) .set_config_int(context, "e2ee_enabled", 0)
.is_ok() as libc::c_int, .is_ok(),
Some("mutual") => context Some("mutual") => context
.sql .sql
.set_config_int(context, "e2ee_enabled", 1) .set_config_int(context, "e2ee_enabled", 1)
.is_ok() as libc::c_int, .is_ok(),
_ => 1, _ => true,
} }
} }
@@ -462,20 +436,18 @@ pub unsafe fn dc_decrypt_setup_file(
let mut payload: *mut libc::c_char = 0 as *mut libc::c_char; let mut payload: *mut libc::c_char = 0 as *mut libc::c_char;
fc_buf = dc_strdup(filecontent); fc_buf = dc_strdup(filecontent);
if !(0 if dc_split_armored_data(
== dc_split_armored_data( fc_buf,
fc_buf, &mut fc_headerline,
&mut fc_headerline, 0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char, 0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char, &mut fc_base64,
&mut fc_base64, ) && !fc_headerline.is_null()
) && strcmp(
|| fc_headerline.is_null()
|| strcmp(
fc_headerline, fc_headerline,
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
) != 0i32 ) == 0
|| fc_base64.is_null()) && !fc_base64.is_null()
{ {
/* convert base64 to binary */ /* convert base64 to binary */
/*must be freed using mmap_string_unref()*/ /*must be freed using mmap_string_unref()*/
@@ -536,7 +508,7 @@ pub unsafe fn dc_normalize_setup_code(
p1 = p1.offset(1); p1 = p1.offset(1);
} }
to_cstring(out) out.strdup()
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@@ -545,16 +517,14 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
let mut success: libc::c_int = 0; let mut success: libc::c_int = 0;
let mut ongoing_allocated_here: libc::c_int = 0; let mut ongoing_allocated_here: libc::c_int = 0;
let what: libc::c_int; let what: libc::c_int;
let mut param1 = 0 as *mut libc::c_char;
let mut param2 = 0 as *mut libc::c_char;
if !(0 == dc_alloc_ongoing(context)) { if !(0 == dc_alloc_ongoing(context)) {
ongoing_allocated_here = 1; ongoing_allocated_here = 1;
what = (*job).param.get_int(Param::Cmd).unwrap_or_default(); what = (*job).param.get_int(Param::Cmd).unwrap_or_default();
param1 = to_cstring((*job).param.get(Param::Arg).unwrap_or_default()); let param1 = CString::yolo((*job).param.get(Param::Arg).unwrap_or_default());
param2 = to_cstring((*job).param.get(Param::Arg2).unwrap_or_default()); let _param2 = CString::yolo((*job).param.get(Param::Arg2).unwrap_or_default());
if strlen(param1) == 0 { if strlen(param1.as_ptr()) == 0 {
error!(context, 0, "No Import/export dir/file given.",); error!(context, 0, "No Import/export dir/file given.",);
} else { } else {
info!(context, 0, "Import/export process started.",); info!(context, 0, "Import/export process started.",);
@@ -572,7 +542,7 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
); );
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
dc_create_folder(context, param1); dc_create_folder(context, param1.as_ptr());
current_block = 4495394744059808450; current_block = 4495394744059808450;
} }
} else { } else {
@@ -585,28 +555,28 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
current_block = 10991094515395304355; current_block = 10991094515395304355;
match current_block { match current_block {
2973387206439775448 => { 2973387206439775448 => {
if 0 == import_backup(context, param1) { if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
11250025114629486028 => { 11250025114629486028 => {
if 0 == import_self_keys(context, param1) { if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
12669919903773909120 => { 12669919903773909120 => {
if 0 == export_backup(context, param1) { if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
_ => { _ => {
if 0 == export_self_keys(context, param1) { if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
@@ -625,28 +595,28 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
current_block = 11250025114629486028; current_block = 11250025114629486028;
match current_block { match current_block {
2973387206439775448 => { 2973387206439775448 => {
if 0 == import_backup(context, param1) { if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
11250025114629486028 => { 11250025114629486028 => {
if 0 == import_self_keys(context, param1) { if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
12669919903773909120 => { 12669919903773909120 => {
if 0 == export_backup(context, param1) { if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
_ => { _ => {
if 0 == export_self_keys(context, param1) { if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
@@ -665,28 +635,28 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
current_block = 12669919903773909120; current_block = 12669919903773909120;
match current_block { match current_block {
2973387206439775448 => { 2973387206439775448 => {
if 0 == import_backup(context, param1) { if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
11250025114629486028 => { 11250025114629486028 => {
if 0 == import_self_keys(context, param1) { if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
12669919903773909120 => { 12669919903773909120 => {
if 0 == export_backup(context, param1) { if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
_ => { _ => {
if 0 == export_self_keys(context, param1) { if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
@@ -705,28 +675,28 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
current_block = 2973387206439775448; current_block = 2973387206439775448;
match current_block { match current_block {
2973387206439775448 => { 2973387206439775448 => {
if 0 == import_backup(context, param1) { if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
11250025114629486028 => { 11250025114629486028 => {
if 0 == import_self_keys(context, param1) { if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
12669919903773909120 => { 12669919903773909120 => {
if 0 == export_backup(context, param1) { if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
} }
} }
_ => { _ => {
if 0 == export_self_keys(context, param1) { if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280; current_block = 3568988166330621280;
} else { } else {
current_block = 1118134448028020070; current_block = 1118134448028020070;
@@ -748,8 +718,6 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
} }
} }
free(param1 as *mut libc::c_void);
free(param2 as *mut libc::c_void);
if 0 != ongoing_allocated_here { if 0 != ongoing_allocated_here {
dc_free_ongoing(context); dc_free_ongoing(context);
} }
@@ -896,9 +864,8 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
let res = chrono::NaiveDateTime::from_timestamp(now as i64, 0) let res = chrono::NaiveDateTime::from_timestamp(now as i64, 0)
.format("delta-chat-%Y-%m-%d.bak") .format("delta-chat-%Y-%m-%d.bak")
.to_string(); .to_string();
let buffer = to_cstring(res); let buffer = CString::yolo(res);
let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer); let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer.as_ptr());
free(buffer as *mut _);
if dest_pathNfilename.is_null() { if dest_pathNfilename.is_null() {
error!(context, 0, "Cannot get backup file name.",); error!(context, 0, "Cannot get backup file name.",);
@@ -1097,7 +1064,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
let mut imported_cnt: libc::c_int = 0; let mut imported_cnt: libc::c_int = 0;
let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char; let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char;
let mut path_plus_name: *mut libc::c_char = 0 as *mut libc::c_char; let mut path_plus_name: *mut libc::c_char = 0 as *mut libc::c_char;
let mut name_c: *mut libc::c_char = 0 as *mut libc::c_char;
let mut set_default: libc::c_int; let mut set_default: libc::c_int;
let mut buf: *mut libc::c_char = 0 as *mut libc::c_char; let mut buf: *mut libc::c_char = 0 as *mut libc::c_char;
let mut buf_bytes: size_t = 0 as size_t; let mut buf_bytes: size_t = 0 as size_t;
@@ -1125,9 +1091,8 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
let entry = entry.unwrap(); let entry = entry.unwrap();
free(suffix as *mut libc::c_void); free(suffix as *mut libc::c_void);
let name_f = entry.file_name(); let name_f = entry.file_name();
free(name_c as *mut libc::c_void); let name_c = name_f.to_c_string().unwrap();
name_c = to_cstring(name_f.to_string_lossy()); suffix = dc_get_filesuffix_lc(name_c.as_ptr());
suffix = dc_get_filesuffix_lc(name_c);
if suffix.is_null() if suffix.is_null()
|| strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0 || strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0
{ {
@@ -1137,7 +1102,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
path_plus_name = dc_mprintf( path_plus_name = dc_mprintf(
b"%s/%s\x00" as *const u8 as *const libc::c_char, b"%s/%s\x00" as *const u8 as *const libc::c_char,
dir_name, dir_name,
name_c, name_c.as_ptr(),
); );
info!(context, 0, "Checking: {}", as_str(path_plus_name)); info!(context, 0, "Checking: {}", as_str(path_plus_name));
free(buf as *mut libc::c_void); free(buf as *mut libc::c_void);
@@ -1154,7 +1119,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
private_key = buf; private_key = buf;
free(buf2 as *mut libc::c_void); free(buf2 as *mut libc::c_void);
buf2 = dc_strdup(buf); buf2 = dc_strdup(buf);
if 0 != dc_split_armored_data( if dc_split_armored_data(
buf2, buf2,
&mut buf2_headerline, &mut buf2_headerline,
0 as *mut *const libc::c_char, 0 as *mut *const libc::c_char,
@@ -1175,7 +1140,12 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
} }
} }
set_default = 1; set_default = 1;
if !strstr(name_c, b"legacy\x00" as *const u8 as *const libc::c_char).is_null() { if !strstr(
name_c.as_ptr(),
b"legacy\x00" as *const u8 as *const libc::c_char,
)
.is_null()
{
info!( info!(
context, context,
0, 0,
@@ -1184,7 +1154,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
); );
set_default = 0i32 set_default = 0i32
} }
if 0 == set_self_key(context, private_key, set_default) { if !set_self_key(context, private_key, set_default) {
continue; continue;
} }
imported_cnt += 1 imported_cnt += 1
@@ -1200,7 +1170,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
} }
} }
free(name_c as *mut libc::c_void);
free(suffix as *mut libc::c_void); free(suffix as *mut libc::c_void);
free(path_plus_name as *mut libc::c_void); free(path_plus_name as *mut libc::c_void);
free(buf as *mut libc::c_void); free(buf as *mut libc::c_void);
@@ -1310,3 +1279,201 @@ unsafe fn export_key_to_asc_file(
success success
} }
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::CStr;
use num_traits::ToPrimitive;
use crate::config::Config;
use crate::key;
use crate::test_utils::*;
unsafe extern "C" fn logging_cb(
_ctx: &Context,
evt: Event,
_d1: uintptr_t,
d2: uintptr_t,
) -> uintptr_t {
let to_str = |x| CStr::from_ptr(x as *const libc::c_char).to_str().unwrap();
match evt {
Event::INFO => println!("I: {}", to_str(d2)),
Event::WARNING => println!("W: {}", to_str(d2)),
Event::ERROR => println!("E: {}", to_str(d2)),
_ => (),
}
0
}
/// Create Alice with a pre-generated keypair.
fn create_alice_keypair(ctx: &Context) {
ctx.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
.unwrap();
// The keypair was created using:
// let (public, private) = crate::pgp::dc_pgp_create_keypair("alice@example.com")
// .unwrap();
// println!("{}", public.to_base64(64));
// println!("{}", private.to_base64(64));
let public = key::Key::from_base64(
concat!(
"xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl",
"LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai",
"x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9",
"OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK",
"A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea",
"6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6",
"GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK",
"u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD",
"Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG",
"9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av",
"62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R",
"noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q",
"4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm",
"jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4",
"AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW",
"qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX",
"FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m",
"MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf",
"qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw",
"sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw",
"jTglkixw+aSTXw=="
),
KeyType::Public,
)
.unwrap();
let private = key::Key::from_base64(
concat!(
"xcLYBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAEACAChqzVOuErmVRqvcYtq",
"m1xt1H+ZjX20z5Sn1fhTLYAcq236AWMqJvwxCXoKlc8bt2UfB+Ls9cQb1YcVq353",
"r0QiExiDeK3YlCxqd/peXJwFYTNKFC3QcnUhtpG9oS/jWjN+BRotGbjtu6Vj3M68",
"JJAq+mHJ0/9OyrqrREvGfo7uLZt7iMGemDlrDakvrbIyZrPLgay+nZ3dEFKeOQ6F",
"FrU05jyUVdoHBy0Tqx/6VpFUX9+IHcMHL2lTJB0nynBj+XZ/G4aX3WYoo3YlixHb",
"Iu35fGFA0TChoGaGPzqcI/kg2Z+b/BryG9NM3LA2cO8iGrGXAE1nPFp91jmCrQ3V",
"WushBADERP+uojjjfdO5J+RkmcFe9mFYDdtkhN+kV+LdePjiNNtcXMBhasstio0S",
"ut0GKnE7DFRhX7mkN9w2apJ2ooeFeVVWot18eSdp6Rzh6/1Z7TmhYFJ3oUxxLbnQ",
"sWIXIec1SzqWBFJUCn3IP0mCnJktFg/uGW6yLs01r5ds52uSBQQA2LSWiTwk9tEm",
"dr9mz3tHnmrkyGiyKhKGM1Z7Rch63D5yQc1s4kUMBlyuLL2QtM/e4dtaz2JAkO8k",
"QrYCnNgJ+2roTAK3kDZgYtymjdvK3HpQNtjVo7dds5RJVb6U618phZwU5WNFAEJW",
"yyImmycGfjLv+18cW/3mq0QVZejkM78D/2kHaIeJAowtBOFY2zDrKyDRoBHaUSgj",
"5BjGoviRC5rYihWDEyYDQ6mBJQstAD0Ty3MYzyUxl6ruB/BMWnMDFq5+TqtdBzu3",
"jCtZ8OEyH8A5Kdo68Wzo/PGxzMtusOdNj9+3PBmSq4yibJxbLSrn59aVUYpGLjeG",
"Kyvm9OTKkrOGN27NEzxhbGljZUBleGFtcGxlLmNvbT7CwIkEEAEIADMCGQEFAl08",
"6fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQ",
"k6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9OHUl3MrXtZ7QmHyOAFvbXE/6n5Ee",
"h+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkKA8e4cJqwDOHsyAnvQXZ7WNje9+BM",
"zcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea6zjGF0/qljTdoxTtsYpv5wXYuhwb",
"YklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6GkquJN814Y+xny4xhZzGOfue6SeP",
"12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUKu5wO9FFbgDySOSlEjByGejSGuBmh",
"o0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxDFcfC2ARdPOnsAQgA5oLxXRLnyugz",
"OmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG9JzDeQql+sYXgUSxOoIayItuXtnF",
"n7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av62n18Venlm0yNKpROPcZ6M/sc4m6",
"uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/RnoW+/fhmwIg08dQ5m8hQe3GEOZEe",
"LrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q4zW8vk2ztB8ngwbnqYy8zrN1DCIC",
"N1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAmjxLZfVDcoObFH3Cv2GB7BEYxv86K",
"C2Y6T74Q/wARAQABAAgAhSvFEYZoj1sSrXrHDjZOrryViGjCCH9t3pmkxLDrGIdd",
"KsFyN8ORUo6KUZS745yx3yFnI9EZ1IZvm9aF+jxk2lGJFtgLvfoxFOvGckwCSy8T",
"/MCiJZkz01hWo5s2VCLJheWL/GqTKjS5wXDcm+y8Wtilh+UawycdlDsSNr/D4MZL",
"j3Chq9K03l5UIR8DcC7SavNi55R2oGOfboXsdvwOlrNZdCkZOlXDI4ZKFwbDHCtp",
"Do5FS30hnJi2TecUPZWB1CaGFWnevINd4ikugVjcAoZj/QAIvfrOCgqisF/Ylg9u",
"RMUPBapmcJUueILwd0iQqvGG0aCqtchvSmlg15/lQQQA9G1NNjNAH+NQrXvDJFJe",
"/V1U3F3pz7jCjQa69c0dxSBUeNX1pG8XXD6tSkkd4Ni1mzZGcZXOmVUM6cA9I7RH",
"95RqV+QIfnXVneCRrlCjV8m6OBlkivkESXc3nW5wtCIfw7oKg9w1xuVNUaAlbCt9",
"QVLaxXJiY7ad0f5U9XJ1+w8EAPFs+M/+GZK1wOZYBL1vo7x0gL9ZggmjC4B+viBJ",
"8Q60mqTrphYFsbXHuwKV0g9aIoZMucKyEE0QLR7imttiLEz1nD8bfEScbGy9ZG//",
"wRfyJmCVAjA0pQ6LtB93d70PSVzzJrMHgbLKrDuSd6RChl7n9BIEdVyk7LEph0Yg",
"9UsRBADm6DvpKL+P3lQ0eLTfAgcQTOqLZDYmI3PvqqSkHb1kHChqOXXs8hGOSSwK",
"Gjcd4CZeNOGWR42rZyRhVgtkt6iYviIaVAWUfme6K+sLQBCeyMlmEGtykAA+LmPB",
"f4zdyUNADfoxgZF3EKHf6I3nlVn5cdT+o/9vjdY2XAOwcls1RzaFwsB2BBgBCAAg",
"BQJdPOn4AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/",
"dXshJnoWqEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJ",
"ywJoupwXFNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJ",
"uiCQvR9mMjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6",
"RDXIeYJfqrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMl",
"ammDliPwsK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKOb",
"zPqgJCGwjTglkixw+aSTXw=="
),
KeyType::Private,
)
.unwrap();
let saved = key::dc_key_save_self_keypair(
&ctx,
&public,
&private,
"alice@example.org",
1,
&ctx.sql,
);
assert_eq!(saved, true, "Failed to save Alice's key");
}
#[test]
fn test_render_setup_file() {
let t = test_context(Some(logging_cb));
create_alice_keypair(&t.ctx); // Trick things to think we're configured.
let msg = dc_render_setup_file(&t.ctx, "hello").unwrap();
println!("{}", &msg);
// Check some substrings, indicating things got substituted.
// In particular note the mixing of `\r\n` and `\n` depending
// on who generated the stings.
assert!(msg.contains("<title>Autocrypt Setup Message</title"));
assert!(msg.contains("<h1>Autocrypt Setup Message</h1>"));
assert!(msg.contains("<p>This is the Autocrypt Setup Message used to"));
assert!(msg.contains("-----BEGIN PGP MESSAGE-----\r\n"));
assert!(msg.contains("Passphrase-Format: numeric9x4\r\n"));
assert!(msg.contains("Passphrase-Begin: he\n"));
assert!(msg.contains("==\n"));
assert!(msg.contains("-----END PGP MESSAGE-----\n"));
}
unsafe extern "C" fn ac_setup_msg_cb(
ctx: &Context,
evt: Event,
d1: uintptr_t,
d2: uintptr_t,
) -> uintptr_t {
if evt == Event::GET_STRING && d1 == StockMessage::AcSetupMsgBody.to_usize().unwrap() {
"hello\r\nthere".strdup() as usize
} else {
logging_cb(ctx, evt, d1, d2)
}
}
#[test]
fn test_render_setup_file_newline_replace() {
let t = test_context(Some(ac_setup_msg_cb));
create_alice_keypair(&t.ctx);
let msg = dc_render_setup_file(&t.ctx, "pw").unwrap();
println!("{}", &msg);
assert!(msg.contains("<p>hello<br>there</p>"));
}
#[test]
fn test_create_setup_code() {
let t = dummy_context();
let setupcode = dc_create_setup_code(&t.ctx);
assert_eq!(setupcode.len(), 44);
assert_eq!(setupcode.chars().nth(4).unwrap(), '-');
assert_eq!(setupcode.chars().nth(9).unwrap(), '-');
assert_eq!(setupcode.chars().nth(14).unwrap(), '-');
assert_eq!(setupcode.chars().nth(19).unwrap(), '-');
assert_eq!(setupcode.chars().nth(24).unwrap(), '-');
assert_eq!(setupcode.chars().nth(29).unwrap(), '-');
assert_eq!(setupcode.chars().nth(34).unwrap(), '-');
assert_eq!(setupcode.chars().nth(39).unwrap(), '-');
}
}

View File

@@ -17,12 +17,14 @@ use crate::dc_mimefactory::*;
use crate::dc_msg::*; use crate::dc_msg::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::imap::*; use crate::imap::*;
use crate::keyhistory::*;
use crate::param::*; use crate::param::*;
use crate::sql; use crate::sql;
use crate::types::*; use crate::types::*;
use crate::x::*; use crate::x::*;
const DC_IMAP_THREAD: libc::c_int = 100;
const DC_SMTP_THREAD: libc::c_int = 5000;
// thread IDs // thread IDs
// jobs in the INBOX-thread, range from DC_IMAP_THREAD..DC_IMAP_THREAD+999 // jobs in the INBOX-thread, range from DC_IMAP_THREAD..DC_IMAP_THREAD+999
// low priority ... // low priority ...
@@ -51,15 +53,15 @@ pub unsafe fn dc_perform_imap_jobs(context: &Context) {
info!(context, 0, "dc_perform_imap_jobs starting.",); info!(context, 0, "dc_perform_imap_jobs starting.",);
let probe_imap_network = *context.probe_imap_network.clone().read().unwrap(); let probe_imap_network = *context.probe_imap_network.clone().read().unwrap();
*context.probe_imap_network.write().unwrap() = 0; *context.probe_imap_network.write().unwrap() = false;
*context.perform_inbox_jobs_needed.write().unwrap() = 0; *context.perform_inbox_jobs_needed.write().unwrap() = false;
dc_job_perform(context, 100, probe_imap_network); dc_job_perform(context, DC_IMAP_THREAD, probe_imap_network);
info!(context, 0, "dc_perform_imap_jobs ended.",); info!(context, 0, "dc_perform_imap_jobs ended.",);
} }
unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: libc::c_int) { unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: bool) {
let query = if probe_network == 0 { let query = if !probe_network {
// processing for first-try and after backoff-timeouts: // processing for first-try and after backoff-timeouts:
// process jobs in the order they were added. // process jobs in the order they were added.
"SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \ "SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \
@@ -74,7 +76,7 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
let params_no_probe = params![thread as i64, time()]; let params_no_probe = params![thread as i64, time()];
let params_probe = params![thread as i64]; let params_probe = params![thread as i64];
let params: &[&dyn rusqlite::ToSql] = if probe_network == 0 { let params: &[&dyn rusqlite::ToSql] = if !probe_network {
params_no_probe params_no_probe
} else { } else {
params_probe params_probe
@@ -116,7 +118,11 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
context, context,
0, 0,
"{}-job #{}, action {} started...", "{}-job #{}, action {} started...",
if thread == 100 { "INBOX" } else { "SMTP" }, if thread == DC_IMAP_THREAD {
"INBOX"
} else {
"SMTP"
},
job.job_id, job.job_id,
job.action, job.action,
); );
@@ -129,7 +135,7 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
dc_job_kill_action(context, job.action); dc_job_kill_action(context, job.action);
dc_jobthread_suspend(context, &context.sentbox_thread.clone().read().unwrap(), 1); dc_jobthread_suspend(context, &context.sentbox_thread.clone().read().unwrap(), 1);
dc_jobthread_suspend(context, &context.mvbox_thread.clone().read().unwrap(), 1); dc_jobthread_suspend(context, &context.mvbox_thread.clone().read().unwrap(), 1);
dc_suspend_smtp_thread(context, 1); dc_suspend_smtp_thread(context, true);
} }
let mut tries = 0; let mut tries = 0;
@@ -167,7 +173,7 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
&mut context.mvbox_thread.clone().read().unwrap(), &mut context.mvbox_thread.clone().read().unwrap(),
0, 0,
); );
dc_suspend_smtp_thread(context, 0); dc_suspend_smtp_thread(context, false);
break; break;
} else if job.try_again == 2 { } else if job.try_again == 2 {
// just try over next loop unconditionally, the ui typically interrupts idle when the file (video) is ready // just try over next loop unconditionally, the ui typically interrupts idle when the file (video) is ready
@@ -175,7 +181,11 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
context, context,
0, 0,
"{}-job #{} not yet ready and will be delayed.", "{}-job #{} not yet ready and will be delayed.",
if thread == 100 { "INBOX" } else { "SMTP" }, if thread == DC_IMAP_THREAD {
"INBOX"
} else {
"SMTP"
},
job.job_id job.job_id
); );
} else if job.try_again == -1 || job.try_again == 3 { } else if job.try_again == -1 || job.try_again == 3 {
@@ -189,13 +199,17 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
context, context,
0, 0,
"{}-job #{} not succeeded on try #{}, retry in ADD_TIME+{} (in {} seconds).", "{}-job #{} not succeeded on try #{}, retry in ADD_TIME+{} (in {} seconds).",
if thread == 100 { "INBOX" } else { "SMTP" }, if thread == DC_IMAP_THREAD {
"INBOX"
} else {
"SMTP"
},
job.job_id as libc::c_int, job.job_id as libc::c_int,
tries, tries,
time_offset, time_offset,
job.added_timestamp + time_offset - time() job.added_timestamp + time_offset - time()
); );
if thread == 5000 && tries < 17 - 1 { if thread == DC_SMTP_THREAD && tries < 17 - 1 {
context context
.smtp_state .smtp_state
.clone() .clone()
@@ -210,7 +224,7 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
} }
dc_job_delete(context, &mut job); dc_job_delete(context, &mut job);
} }
if 0 == probe_network { if !probe_network {
continue; continue;
} }
// on dc_maybe_network() we stop trying here; // on dc_maybe_network() we stop trying here;
@@ -236,7 +250,7 @@ fn dc_job_delete(context: &Context, job: &dc_job_t) -> bool {
* Tools * Tools
******************************************************************************/ ******************************************************************************/
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe fn get_backoff_time_offset(c_tries: libc::c_int) -> i64 { fn get_backoff_time_offset(c_tries: libc::c_int) -> i64 {
// results in ~3 weeks for the last backoff timespan // results in ~3 weeks for the last backoff timespan
let mut N = 2_i32.pow((c_tries - 1) as u32); let mut N = 2_i32.pow((c_tries - 1) as u32);
N = N * 60; N = N * 60;
@@ -264,11 +278,11 @@ fn dc_job_update(context: &Context, job: &dc_job_t) -> bool {
.is_ok() .is_ok()
} }
unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: libc::c_int) { unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: bool) {
context.smtp_state.0.lock().unwrap().suspended = suspend; context.smtp_state.0.lock().unwrap().suspended = suspend;
if 0 != suspend { if suspend {
loop { loop {
if context.smtp_state.0.lock().unwrap().doing_jobs == 0 { if !context.smtp_state.0.lock().unwrap().doing_jobs {
return; return;
} }
std::thread::sleep(std::time::Duration::from_micros(300 * 1000)); std::thread::sleep(std::time::Duration::from_micros(300 * 1000));
@@ -299,7 +313,7 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
} }
match current_block { match current_block {
13109137661213826276 => { 13109137661213826276 => {
filename = to_cstring(job.param.get(Param::File).unwrap_or_default()); filename = job.param.get(Param::File).unwrap_or_default().strdup();
if strlen(filename) == 0 { if strlen(filename) == 0 {
warn!(context, 0, "Missing file name for job {}", job.job_id,); warn!(context, 0, "Missing file name for job {}", job.job_id,);
} else if !(0 == dc_read_file(context, filename, &mut buf, &mut buf_bytes)) { } else if !(0 == dc_read_file(context, filename, &mut buf, &mut buf_bytes)) {
@@ -772,7 +786,7 @@ unsafe fn dc_add_smtp_job(
b"\x1e\x00" as *const u8 as *const libc::c_char, b"\x1e\x00" as *const u8 as *const libc::c_char,
); );
param.set(Param::File, as_str(pathNfilename)); param.set(Param::File, as_str(pathNfilename));
param.set(Param::File, as_str(recipients)); param.set(Param::Recipients, as_str(recipients));
dc_job_add( dc_job_add(
context, context,
action, action,
@@ -801,10 +815,10 @@ pub unsafe fn dc_job_add(
delay_seconds: libc::c_int, delay_seconds: libc::c_int,
) { ) {
let timestamp = time(); let timestamp = time();
let thread = if action >= 100 && action < 100 + 1000 { let thread = if action >= DC_IMAP_THREAD && action < DC_IMAP_THREAD + 1000 {
100 DC_IMAP_THREAD
} else if action >= 5000 && action < 5000 + 1000 { } else if action >= DC_SMTP_THREAD && action < DC_SMTP_THREAD + 1000 {
5000 DC_SMTP_THREAD
} else { } else {
return; return;
}; };
@@ -823,7 +837,7 @@ pub unsafe fn dc_job_add(
] ]
).ok(); ).ok();
if thread == 100 { if thread == DC_IMAP_THREAD {
dc_interrupt_imap_idle(context); dc_interrupt_imap_idle(context);
} else { } else {
dc_interrupt_smtp_idle(context); dc_interrupt_smtp_idle(context);
@@ -844,7 +858,7 @@ pub unsafe fn dc_interrupt_smtp_idle(context: &Context) {
pub unsafe fn dc_interrupt_imap_idle(context: &Context) { pub unsafe fn dc_interrupt_imap_idle(context: &Context) {
info!(context, 0, "Interrupting IMAP-IDLE...",); info!(context, 0, "Interrupting IMAP-IDLE...",);
*context.perform_inbox_jobs_needed.write().unwrap() = 1; *context.perform_inbox_jobs_needed.write().unwrap() = true;
context.inbox.read().unwrap().interrupt_idle(); context.inbox.read().unwrap().interrupt_idle();
} }
@@ -952,7 +966,7 @@ pub fn dc_perform_imap_idle(context: &Context) {
connect_to_inbox(context, &inbox); connect_to_inbox(context, &inbox);
if 0 != *context.perform_inbox_jobs_needed.clone().read().unwrap() { if *context.perform_inbox_jobs_needed.clone().read().unwrap() {
info!( info!(
context, context,
0, "INBOX-IDLE will not be started because of waiting jobs." 0, "INBOX-IDLE will not be started because of waiting jobs."
@@ -1027,26 +1041,26 @@ pub unsafe fn dc_perform_smtp_jobs(context: &Context) {
let mut state = lock.lock().unwrap(); let mut state = lock.lock().unwrap();
let probe_smtp_network = state.probe_network; let probe_smtp_network = state.probe_network;
state.probe_network = 0; state.probe_network = false;
state.perform_jobs_needed = 0; state.perform_jobs_needed = 0;
if 0 != state.suspended { if state.suspended {
info!(context, 0, "SMTP-jobs suspended.",); info!(context, 0, "SMTP-jobs suspended.",);
return; return;
} }
state.doing_jobs = 1; state.doing_jobs = true;
probe_smtp_network probe_smtp_network
}; };
info!(context, 0, "SMTP-jobs started...",); info!(context, 0, "SMTP-jobs started...",);
dc_job_perform(context, 5000, probe_smtp_network); dc_job_perform(context, DC_SMTP_THREAD, probe_smtp_network);
info!(context, 0, "SMTP-jobs ended."); info!(context, 0, "SMTP-jobs ended.");
{ {
let &(ref lock, _) = &*context.smtp_state.clone(); let &(ref lock, _) = &*context.smtp_state.clone();
let mut state = lock.lock().unwrap(); let mut state = lock.lock().unwrap();
state.doing_jobs = 0; state.doing_jobs = false;
} }
} }
@@ -1062,7 +1076,7 @@ pub unsafe fn dc_perform_smtp_idle(context: &Context) {
0, "SMTP-idle will not be started because of waiting jobs.", 0, "SMTP-idle will not be started because of waiting jobs.",
); );
} else { } else {
let dur = get_next_wakeup_time(context, 5000); let dur = get_next_wakeup_time(context, DC_SMTP_THREAD);
loop { loop {
let res = cvar.wait_timeout(state, dur).unwrap(); let res = cvar.wait_timeout(state, dur).unwrap();
@@ -1108,9 +1122,9 @@ pub unsafe fn dc_maybe_network(context: &Context) {
{ {
let &(ref lock, _) = &*context.smtp_state.clone(); let &(ref lock, _) = &*context.smtp_state.clone();
let mut state = lock.lock().unwrap(); let mut state = lock.lock().unwrap();
state.probe_network = 1; state.probe_network = true;
*context.probe_imap_network.write().unwrap() = 1; *context.probe_imap_network.write().unwrap() = true;
} }
dc_interrupt_smtp_idle(context); dc_interrupt_smtp_idle(context);
@@ -1162,15 +1176,14 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in
} else { } else {
// no redo, no IMAP. moreover, as the data does not exist, there is no need in calling dc_set_msg_failed() // no redo, no IMAP. moreover, as the data does not exist, there is no need in calling dc_set_msg_failed()
if msgtype_has_file((*mimefactory.msg).type_0) { if msgtype_has_file((*mimefactory.msg).type_0) {
let pathNfilename = to_cstring( let pathNfilename = (*mimefactory.msg)
(*mimefactory.msg) .param
.param .get(Param::File)
.get(Param::File) .unwrap_or_default()
.unwrap_or_default(), .strdup();
);
if strlen(pathNfilename) > 0 { if strlen(pathNfilename) > 0 {
if ((*mimefactory.msg).type_0 == DC_MSG_IMAGE if ((*mimefactory.msg).type_0 == Viewtype::Image
|| (*mimefactory.msg).type_0 == DC_MSG_GIF) || (*mimefactory.msg).type_0 == Viewtype::Gif)
&& !(*mimefactory.msg).param.exists(Param::Width) && !(*mimefactory.msg).param.exists(Param::Width)
{ {
let mut buf = 0 as *mut libc::c_uchar; let mut buf = 0 as *mut libc::c_uchar;
@@ -1263,13 +1276,6 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in
(*mimefactory.msg).param.set_int(Param::GuranteeE2ee, 1); (*mimefactory.msg).param.set_int(Param::GuranteeE2ee, 1);
dc_msg_save_param_to_disk(mimefactory.msg); dc_msg_save_param_to_disk(mimefactory.msg);
} }
dc_add_to_keyhistory(
context,
0 as *const libc::c_char,
0,
0 as *const libc::c_char,
0 as *const libc::c_char,
);
success = dc_add_smtp_job(context, 5901i32, &mut mimefactory); success = dc_add_smtp_job(context, 5901i32, &mut mimefactory);
} }
} }

View File

@@ -1,6 +1,7 @@
use std::ffi::CString; use std::ffi::CString;
use crate::constants::Event; use crate::constants::Event;
use crate::constants::*;
use crate::context::*; use crate::context::*;
use crate::dc_array::*; use crate::dc_array::*;
use crate::dc_chat::*; use crate::dc_chat::*;
@@ -51,7 +52,7 @@ impl dc_location {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub struct dc_kml_t { pub struct dc_kml_t {
pub addr: *mut libc::c_char, pub addr: *mut libc::c_char,
pub locations: *mut dc_array_t, pub locations: Option<Vec<dc_location>>,
pub tag: libc::c_int, pub tag: libc::c_int,
pub curr: dc_location, pub curr: dc_location,
} }
@@ -60,7 +61,7 @@ impl dc_kml_t {
pub fn new() -> Self { pub fn new() -> Self {
dc_kml_t { dc_kml_t {
addr: std::ptr::null_mut(), addr: std::ptr::null_mut(),
locations: std::ptr::null_mut(), locations: None,
tag: 0, tag: 0,
curr: dc_location::new(), curr: dc_location::new(),
} }
@@ -98,13 +99,9 @@ pub unsafe fn dc_send_locations_to_chat(
.is_ok() .is_ok()
{ {
if 0 != seconds && !is_sending_locations_before { if 0 != seconds && !is_sending_locations_before {
msg = dc_msg_new(context, 10i32); msg = dc_msg_new(context, Viewtype::Text);
(*msg).text = to_cstring(context.stock_system_msg( (*msg).text =
StockMessage::MsgLocationEnabled, Some(context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0));
"",
"",
0,
));
(*msg).param.set_int(Param::Cmd, 8); (*msg).param.set_int(Param::Cmd, 8);
dc_send_msg(context, chat_id, msg); dc_send_msg(context, chat_id, msg);
} else if 0 == seconds && is_sending_locations_before { } else if 0 == seconds && is_sending_locations_before {
@@ -250,12 +247,12 @@ pub fn dc_get_locations(
Ok(loc) Ok(loc)
}, },
|locations| { |locations| {
let mut ret = dc_array_t::new_locations(500); let mut ret = Vec::new();
for location in locations { for location in locations {
ret.add_location(location?); ret.push(location?);
} }
Ok(ret.into_raw()) Ok(dc_array_t::from(ret).into_raw())
}, },
) )
.unwrap_or_else(|_| std::ptr::null_mut()) .unwrap_or_else(|_| std::ptr::null_mut())
@@ -350,7 +347,7 @@ pub fn dc_get_location_kml(
} }
if 0 != success { if 0 != success {
unsafe { to_cstring(ret) } unsafe { ret.strdup() }
} else { } else {
std::ptr::null_mut() std::ptr::null_mut()
} }
@@ -364,7 +361,7 @@ unsafe fn get_kml_timestamp(utc: i64) -> *mut libc::c_char {
let res = chrono::NaiveDateTime::from_timestamp(utc, 0) let res = chrono::NaiveDateTime::from_timestamp(utc, 0)
.format("%Y-%m-%dT%H:%M:%SZ") .format("%Y-%m-%dT%H:%M:%SZ")
.to_string(); .to_string();
to_cstring(res) res.strdup()
} }
pub unsafe fn dc_get_message_kml( pub unsafe fn dc_get_message_kml(
@@ -422,13 +419,14 @@ pub unsafe fn dc_save_locations(
context: &Context, context: &Context,
chat_id: u32, chat_id: u32,
contact_id: u32, contact_id: u32,
locations: *const dc_array_t, locations_opt: &Option<Vec<dc_location>>,
independent: libc::c_int, independent: libc::c_int,
) -> u32 { ) -> u32 {
if chat_id <= 9 || locations.is_null() { if chat_id <= 9 || locations_opt.is_none() {
return 0; return 0;
} }
let locations = locations_opt.as_ref().unwrap();
context context
.sql .sql
.prepare2( .prepare2(
@@ -440,31 +438,29 @@ pub unsafe fn dc_save_locations(
let mut newest_timestamp = 0; let mut newest_timestamp = 0;
let mut newest_location_id = 0; let mut newest_location_id = 0;
for i in 0..dc_array_get_cnt(locations) { for location in locations {
let location = dc_array_get_ptr(locations, i as size_t) as *mut dc_location;
let exists = let exists =
stmt_test.exists(params![(*location).timestamp, contact_id as i32])?; stmt_test.exists(params![location.timestamp, contact_id as i32])?;
if 0 != independent || !exists { if 0 != independent || !exists {
stmt_insert.execute(params![ stmt_insert.execute(params![
(*location).timestamp, location.timestamp,
contact_id as i32, contact_id as i32,
chat_id as i32, chat_id as i32,
(*location).latitude, location.latitude,
(*location).longitude, location.longitude,
(*location).accuracy, location.accuracy,
independent, independent,
])?; ])?;
if (*location).timestamp > newest_timestamp { if location.timestamp > newest_timestamp {
newest_timestamp = (*location).timestamp; newest_timestamp = location.timestamp;
newest_location_id = sql::get_rowid2_with_conn( newest_location_id = sql::get_rowid2_with_conn(
context, context,
conn, conn,
"locations", "locations",
"timestamp", "timestamp",
(*location).timestamp, location.timestamp,
"from_id", "from_id",
contact_id as i32, contact_id as i32,
); );
@@ -499,7 +495,7 @@ pub unsafe fn dc_kml_parse(
} else { } else {
content_nullterminated = dc_null_terminate(content, content_bytes as libc::c_int); content_nullterminated = dc_null_terminate(content, content_bytes as libc::c_int);
if !content_nullterminated.is_null() { if !content_nullterminated.is_null() {
kml.locations = dc_array_new_locations(100); kml.locations = Some(Vec::with_capacity(100));
dc_saxparser_init( dc_saxparser_init(
&mut saxparser, &mut saxparser,
&mut kml as *mut dc_kml_t as *mut libc::c_void, &mut kml as *mut dc_kml_t as *mut libc::c_void,
@@ -585,7 +581,7 @@ unsafe fn kml_endtag_cb(userdata: *mut libc::c_void, tag: *const libc::c_char) {
&& 0. != (*kml).curr.longitude && 0. != (*kml).curr.longitude
{ {
let location = (*kml).curr.clone(); let location = (*kml).curr.clone();
(*(*kml).locations).add_location(location); ((*kml).locations.as_mut().unwrap()).push(location);
} }
(*kml).tag = 0 (*kml).tag = 0
}; };
@@ -636,11 +632,7 @@ unsafe fn kml_starttag_cb(
}; };
} }
pub unsafe fn dc_kml_unref(kml: *mut dc_kml_t) { pub unsafe fn dc_kml_unref(kml: &mut dc_kml_t) {
if kml.is_null() {
return;
}
dc_array_unref((*kml).locations);
free((*kml).addr as *mut libc::c_void); free((*kml).addr as *mut libc::c_void);
} }
@@ -707,7 +699,7 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: *mu
// the easiest way to determine this, is to check for an empty message queue. // 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 // (might not be 100%, however, as positions are sent combined later
// and dc_set_location() is typically called periodically, this is ok) // and dc_set_location() is typically called periodically, this is ok)
let mut msg = dc_msg_new(context, 10); let mut msg = dc_msg_new(context, Viewtype::Text);
(*msg).hidden = 1; (*msg).hidden = 1;
(*msg).param.set_int(Param::Cmd, 9); (*msg).param.set_int(Param::Cmd, 9);
dc_send_msg(context, chat_id as u32, msg); dc_send_msg(context, chat_id as u32, msg);

View File

@@ -1,6 +1,6 @@
use crate::contact::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_msg::*; use crate::dc_msg::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::stock::StockMessage; use crate::stock::StockMessage;
@@ -127,41 +127,58 @@ pub unsafe fn dc_lot_fill(
mut lot: *mut dc_lot_t, mut lot: *mut dc_lot_t,
msg: *mut dc_msg_t, msg: *mut dc_msg_t,
chat: *const Chat, chat: *const Chat,
contact: *const dc_contact_t, contact: Option<&Contact>,
context: &Context, context: &Context,
) { ) {
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint || msg.is_null() { if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint || msg.is_null() {
return; return;
} }
if (*msg).state == 19i32 { if (*msg).state == 19i32 {
(*lot).text1 = to_cstring(context.stock_str(StockMessage::Draft)); (*lot).text1 = context.stock_str(StockMessage::Draft).strdup();
(*lot).text1_meaning = 1i32 (*lot).text1_meaning = 1i32
} else if (*msg).from_id == 1i32 as libc::c_uint { } else if (*msg).from_id == 1i32 as libc::c_uint {
if 0 != dc_msg_is_info(msg) || 0 != dc_chat_is_self_talk(chat) { if 0 != dc_msg_is_info(msg) || 0 != dc_chat_is_self_talk(chat) {
(*lot).text1 = 0 as *mut libc::c_char; (*lot).text1 = 0 as *mut libc::c_char;
(*lot).text1_meaning = 0i32 (*lot).text1_meaning = 0i32
} else { } else {
(*lot).text1 = to_cstring(context.stock_str(StockMessage::SelfMsg)); (*lot).text1 = context.stock_str(StockMessage::SelfMsg).strdup();
(*lot).text1_meaning = 3i32 (*lot).text1_meaning = 3i32
} }
} else if chat.is_null() { } else if chat.is_null() {
(*lot).text1 = 0 as *mut libc::c_char; (*lot).text1 = 0 as *mut libc::c_char;
(*lot).text1_meaning = 0i32 (*lot).text1_meaning = 0i32
} else if (*chat).type_0 == 120i32 || (*chat).type_0 == 130i32 { } else if (*chat).type_0 == 120i32 || (*chat).type_0 == 130i32 {
if 0 != dc_msg_is_info(msg) || contact.is_null() { if 0 != dc_msg_is_info(msg) || contact.is_none() {
(*lot).text1 = 0 as *mut libc::c_char; (*lot).text1 = 0 as *mut libc::c_char;
(*lot).text1_meaning = 0i32 (*lot).text1_meaning = 0i32
} else { } else {
if !chat.is_null() && (*chat).id == 1i32 as libc::c_uint { if !chat.is_null() && (*chat).id == 1i32 as libc::c_uint {
(*lot).text1 = dc_contact_get_display_name(contact) if let Some(contact) = contact {
(*lot).text1 = contact.get_display_name().strdup();
} else {
(*lot).text1 = std::ptr::null_mut();
}
} else { } else {
(*lot).text1 = dc_contact_get_first_name(contact) if let Some(contact) = contact {
(*lot).text1 = contact.get_first_name().strdup();
} else {
(*lot).text1 = std::ptr::null_mut();
}
} }
(*lot).text1_meaning = 2i32 (*lot).text1_meaning = 2i32;
} }
} }
(*lot).text2 =
dc_msg_get_summarytext_by_raw((*msg).type_0, (*msg).text, &mut (*msg).param, 160, context); let message_text = (*msg).text.as_ref().unwrap();
(*lot).text2 = dc_msg_get_summarytext_by_raw(
(*msg).type_0,
message_text.strdup(),
&mut (*msg).param,
160,
context,
);
(*lot).timestamp = dc_msg_get_timestamp(msg); (*lot).timestamp = dc_msg_get_timestamp(msg);
(*lot).state = (*msg).state; (*lot).state = (*msg).state;
} }

View File

@@ -9,11 +9,12 @@ use mmime::mailmime_types_helper::*;
use mmime::mailmime_write_mem::*; use mmime::mailmime_write_mem::*;
use mmime::mmapstring::*; use mmime::mmapstring::*;
use mmime::other::*; use mmime::other::*;
use std::ptr;
use crate::constants::*; use crate::constants::*;
use crate::contact::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_e2ee::*; use crate::dc_e2ee::*;
use crate::dc_location::*; use crate::dc_location::*;
use crate::dc_msg::*; use crate::dc_msg::*;
@@ -158,13 +159,13 @@ pub unsafe fn dc_mimefactory_load_msg(
|rows| { |rows| {
for row in rows { for row in rows {
let (authname, addr) = row?; let (authname, addr) = row?;
let addr_c = to_cstring(addr); let addr_c = addr.strdup();
if clist_search_string_nocase((*factory).recipients_addr, addr_c) == 0 { if clist_search_string_nocase((*factory).recipients_addr, addr_c) == 0 {
clist_insert_after( clist_insert_after(
(*factory).recipients_names, (*factory).recipients_names,
(*(*factory).recipients_names).last, (*(*factory).recipients_names).last,
if !authname.is_empty() { if !authname.is_empty() {
to_cstring(authname) authname.strdup()
} else { } else {
std::ptr::null_mut() std::ptr::null_mut()
} as *mut libc::c_void, } as *mut libc::c_void,
@@ -188,7 +189,7 @@ pub unsafe fn dc_mimefactory_load_msg(
if command == 5 { if command == 5 {
let email_to_remove = (*(*factory).msg).param.get(Param::Arg).unwrap_or_default(); let email_to_remove = (*(*factory).msg).param.get(Param::Arg).unwrap_or_default();
let email_to_remove_c = to_cstring(email_to_remove); let email_to_remove_c = email_to_remove.strdup();
let self_addr = context let self_addr = context
.sql .sql
@@ -234,8 +235,8 @@ pub unsafe fn dc_mimefactory_load_msg(
); );
match row { match row {
Ok((in_reply_to, references)) => { Ok((in_reply_to, references)) => {
(*factory).in_reply_to = to_cstring(in_reply_to); (*factory).in_reply_to = in_reply_to.strdup();
(*factory).references = to_cstring(references); (*factory).references = references.strdup();
} }
Err(err) => { Err(err) => {
error!( error!(
@@ -259,27 +260,28 @@ pub unsafe fn dc_mimefactory_load_msg(
unsafe fn load_from(mut factory: *mut dc_mimefactory_t) { unsafe fn load_from(mut factory: *mut dc_mimefactory_t) {
let context = (*factory).context; let context = (*factory).context;
(*factory).from_addr = to_cstring( (*factory).from_addr = context
context .sql
.sql .get_config(context, "configured_addr")
.get_config(context, "configured_addr") .unwrap_or_default()
.unwrap_or_default(), .strdup();
);
(*factory).from_displayname = to_cstring( (*factory).from_displayname = context
context .sql
.sql .get_config(context, "displayname")
.get_config(context, "displayname") .unwrap_or_default()
.unwrap_or_default(), .strdup();
);
(*factory).selfstatus = to_cstring( (*factory).selfstatus = context
context .sql
.sql .get_config(context, "selfstatus")
.get_config(context, "selfstatus") .unwrap_or_default()
.unwrap_or_default(), .strdup();
);
if (*factory).selfstatus.is_null() { if (*factory).selfstatus.is_null() {
(*factory).selfstatus = to_cstring((*factory).context.stock_str(StockMessage::StatusLine)); (*factory).selfstatus = (*factory)
.context
.stock_str(StockMessage::StatusLine)
.strdup();
}; };
} }
@@ -292,7 +294,6 @@ pub unsafe fn dc_mimefactory_load_mdn(
} }
let mut success = 0; let mut success = 0;
let mut contact = 0 as *mut dc_contact_t;
(*factory).recipients_names = clist_new(); (*factory).recipients_names = clist_new();
(*factory).recipients_addr = clist_new(); (*factory).recipients_addr = clist_new();
@@ -304,24 +305,19 @@ pub unsafe fn dc_mimefactory_load_mdn(
.unwrap_or_else(|| 1) .unwrap_or_else(|| 1)
{ {
// MDNs not enabled - check this is late, in the job. the use may have changed its choice while offline ... // MDNs not enabled - check this is late, in the job. the use may have changed its choice while offline ...
contact = dc_contact_new((*factory).context); if !dc_msg_load_from_db((*factory).msg, (*factory).context, msg_id) {
if !(!dc_msg_load_from_db((*factory).msg, (*factory).context, msg_id) return success;
|| !dc_contact_load_from_db( }
contact,
&(*factory).context.sql, if let Ok(contact) = Contact::load_from_db((*factory).context, (*(*factory).msg).from_id) {
(*(*factory).msg).from_id, if !(contact.is_blocked() || (*(*factory).msg).chat_id <= 9 as libc::c_uint) {
))
{
if !(0 != (*contact).blocked || (*(*factory).msg).chat_id <= 9 as libc::c_uint) {
// Do not send MDNs trash etc.; chats.blocked is already checked by the caller in dc_markseen_msgs() // Do not send MDNs trash etc.; chats.blocked is already checked by the caller in dc_markseen_msgs()
if !((*(*factory).msg).from_id <= 9 as libc::c_uint) { if !((*(*factory).msg).from_id <= 9 as libc::c_uint) {
clist_insert_after( clist_insert_after(
(*factory).recipients_names, (*factory).recipients_names,
(*(*factory).recipients_names).last, (*(*factory).recipients_names).last,
(if !(*contact).authname.is_null() (if !contact.get_authname().is_empty() {
&& 0 != *(*contact).authname.offset(0isize) as libc::c_int contact.get_authname().strdup()
{
dc_strdup((*contact).authname)
} else { } else {
0 as *mut libc::c_char 0 as *mut libc::c_char
}) as *mut libc::c_void, }) as *mut libc::c_void,
@@ -329,7 +325,7 @@ pub unsafe fn dc_mimefactory_load_mdn(
clist_insert_after( clist_insert_after(
(*factory).recipients_addr, (*factory).recipients_addr,
(*(*factory).recipients_addr).last, (*(*factory).recipients_addr).last,
dc_strdup((*contact).addr) as *mut libc::c_void, contact.get_addr().strdup() as *mut libc::c_void,
); );
load_from(factory); load_from(factory);
(*factory).timestamp = dc_create_smeared_timestamp((*factory).context); (*factory).timestamp = dc_create_smeared_timestamp((*factory).context);
@@ -344,15 +340,13 @@ pub unsafe fn dc_mimefactory_load_mdn(
} }
} }
dc_contact_unref(contact);
success success
} }
// TODO should return bool /rtn // TODO should return bool /rtn
pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc::c_int { pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc::c_int {
let subject: *mut mailimf_subject; let subject: *mut mailimf_subject;
let mut current_block: u64; let mut ok_to_continue = true;
let imf_fields: *mut mailimf_fields; let imf_fields: *mut mailimf_fields;
let mut message: *mut mailmime = 0 as *mut mailmime; let mut message: *mut mailmime = 0 as *mut mailmime;
let mut message_text: *mut libc::c_char = 0 as *mut libc::c_char; let mut message_text: *mut libc::c_char = 0 as *mut libc::c_char;
@@ -477,26 +471,26 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
references_list, references_list,
0 as *mut libc::c_char, 0 as *mut libc::c_char,
); );
let os_name = &(*factory).context.os_name;
let os_part = os_name
.as_ref()
.map(|s| format!("/{}", s))
.unwrap_or_default();
let os_part = CString::new(os_part).expect("String -> CString conversion failed");
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( mailimf_field_new_custom(
strdup(b"X-Mailer\x00" as *const u8 as *const libc::c_char), strdup(b"X-Mailer\x00" as *const u8 as *const libc::c_char),
dc_mprintf( dc_mprintf(
b"Delta Chat Core %s%s%s\x00" as *const u8 as *const libc::c_char, b"Delta Chat Core %s%s\x00" as *const u8 as *const libc::c_char,
DC_VERSION_STR as *const u8 as *const libc::c_char, DC_VERSION_STR as *const u8 as *const libc::c_char,
if !(*(*factory).context).os_name.is_null() { os_part.as_ptr(),
b"/\x00" as *const u8 as *const libc::c_char
} else {
b"\x00" as *const u8 as *const libc::c_char
},
if !(*(*factory).context).os_name.is_null() {
(*(*factory).context).os_name
} else {
b"\x00" as *const u8 as *const libc::c_char
},
), ),
), ),
); );
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( mailimf_field_new_custom(
@@ -573,8 +567,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
), ),
); );
if command == 5 { if command == 5 {
let email_to_remove = let email_to_remove = (*msg).param.get(Param::Arg).unwrap_or_default().strdup();
to_cstring((*msg).param.get(Param::Arg).unwrap_or_default());
if strlen(email_to_remove) > 0 { if strlen(email_to_remove) > 0 {
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
@@ -589,7 +582,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
} }
} else if command == 4 { } else if command == 4 {
do_gossip = 1; do_gossip = 1;
let email_to_add = to_cstring((*msg).param.get(Param::Arg).unwrap_or_default()); let email_to_add = (*msg).param.get(Param::Arg).unwrap_or_default().strdup();
if strlen(email_to_add) > 0 { if strlen(email_to_add) > 0 {
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
@@ -619,7 +612,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
); );
} }
} else if command == 2 { } else if command == 2 {
let value_to_add = to_cstring((*msg).param.get(Param::Arg).unwrap_or_default()); let value_to_add = (*msg).param.get(Param::Arg).unwrap_or_default().strdup();
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( mailimf_field_new_custom(
@@ -661,11 +654,13 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
strdup(b"v1\x00" as *const u8 as *const libc::c_char), strdup(b"v1\x00" as *const u8 as *const libc::c_char),
), ),
); );
placeholdertext = placeholdertext = (*factory)
to_cstring((*factory).context.stock_str(StockMessage::AcSetupMsgBody)); .context
.stock_str(StockMessage::AcSetupMsgBody)
.strdup();
} }
if command == 7 { if command == 7 {
let step = to_cstring((*msg).param.get(Param::Arg).unwrap_or_default()); let step = (*msg).param.get(Param::Arg).unwrap_or_default().strdup();
if strlen(step) > 0 { if strlen(step) > 0 {
info!( info!(
(*msg).context, (*msg).context,
@@ -680,7 +675,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
step, step,
), ),
); );
let param2 = to_cstring((*msg).param.get(Param::Arg2).unwrap_or_default()); let param2 = (*msg).param.get(Param::Arg2).unwrap_or_default().strdup();
if strlen(param2) > 0 { if strlen(param2) > 0 {
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
@@ -708,7 +703,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
), ),
); );
} }
let fingerprint = to_cstring((*msg).param.get(Param::Arg3).unwrap_or_default()); let fingerprint = (*msg).param.get(Param::Arg3).unwrap_or_default().strdup();
if strlen(fingerprint) > 0 { if strlen(fingerprint) > 0 {
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
@@ -722,7 +717,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
); );
} }
let grpid = match (*msg).param.get(Param::Arg4) { let grpid = match (*msg).param.get(Param::Arg4) {
Some(id) => to_cstring(id), Some(id) => id.strdup(),
None => std::ptr::null_mut(), None => std::ptr::null_mut(),
}; };
if !grpid.is_null() { if !grpid.is_null() {
@@ -738,10 +733,9 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
} }
} }
} }
if let Some(grpimage) = grpimage { if let Some(grpimage) = grpimage {
let mut meta = dc_msg_new_untyped((*factory).context); let mut meta = dc_msg_new_untyped((*factory).context);
(*meta).type_0 = DC_MSG_IMAGE as libc::c_int; (*meta).type_0 = Viewtype::Image;
(*meta).param.set(Param::File, grpimage); (*meta).param.set(Param::File, grpimage);
let mut filename_as_sent = 0 as *mut libc::c_char; let mut filename_as_sent = 0 as *mut libc::c_char;
@@ -762,11 +756,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
dc_msg_unref(meta); dc_msg_unref(meta);
} }
if (*msg).type_0 == DC_MSG_VOICE if (*msg).type_0 == Viewtype::Voice
|| (*msg).type_0 == DC_MSG_AUDIO || (*msg).type_0 == Viewtype::Audio
|| (*msg).type_0 == DC_MSG_VIDEO || (*msg).type_0 == Viewtype::Video
{ {
if (*msg).type_0 == DC_MSG_VOICE { if (*msg).type_0 == Viewtype::Voice {
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( mailimf_field_new_custom(
@@ -798,12 +792,17 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
) )
} }
let mut final_text: *const libc::c_char = 0 as *const libc::c_char; let final_text = {
if !placeholdertext.is_null() { if !placeholdertext.is_null() {
final_text = placeholdertext to_string(placeholdertext)
} else if !(*msg).text.is_null() && 0 != *(*msg).text.offset(0isize) as libc::c_int { } else if let Some(ref text) = (*msg).text {
final_text = (*msg).text text.clone()
} } else {
"".into()
}
};
let final_text = CString::yolo(final_text);
let footer: *mut libc::c_char = (*factory).selfstatus; let footer: *mut libc::c_char = (*factory).selfstatus;
message_text = dc_mprintf( message_text = dc_mprintf(
b"%s%s%s%s%s\x00" as *const u8 as *const libc::c_char, b"%s%s%s%s%s\x00" as *const u8 as *const libc::c_char,
@@ -812,12 +811,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
} else { } else {
b"\x00" as *const u8 as *const libc::c_char b"\x00" as *const u8 as *const libc::c_char
}, },
if !final_text.is_null() { final_text.as_ptr(),
final_text if final_text != CString::yolo("")
} else {
b"\x00" as *const u8 as *const libc::c_char
},
if !final_text.is_null()
&& !footer.is_null() && !footer.is_null()
&& 0 != *footer.offset(0isize) as libc::c_int && 0 != *footer.offset(0isize) as libc::c_int
{ {
@@ -844,7 +839,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
/* add attachment part */ /* add attachment part */
if msgtype_has_file((*msg).type_0) { if msgtype_has_file((*msg).type_0) {
if 0 == is_file_size_okay(msg) { if !is_file_size_okay(msg) {
let error: *mut libc::c_char = dc_mprintf( let error: *mut libc::c_char = dc_mprintf(
b"Message exceeds the recommended %i MB.\x00" as *const u8 b"Message exceeds the recommended %i MB.\x00" as *const u8
as *const libc::c_char, as *const libc::c_char,
@@ -852,7 +847,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
); );
set_error(factory, error); set_error(factory, error);
free(error as *mut libc::c_void); free(error as *mut libc::c_void);
current_block = 11328123142868406523; ok_to_continue = false;
} else { } else {
let file_part: *mut mailmime = let file_part: *mut mailmime =
build_body_file(msg, 0 as *const libc::c_char, 0 as *mut *mut libc::c_char); build_body_file(msg, 0 as *const libc::c_char, 0 as *mut *mut libc::c_char);
@@ -860,86 +855,73 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
mailmime_smart_add_part(message, file_part); mailmime_smart_add_part(message, file_part);
parts += 1 parts += 1
} }
current_block = 13000670339742628194;
} }
} else {
current_block = 13000670339742628194;
} }
match current_block { if ok_to_continue {
11328123142868406523 => {} if parts == 0 {
_ => { set_error(
if parts == 0 { factory,
set_error( b"Empty message.\x00" as *const u8 as *const libc::c_char,
factory, );
b"Empty message.\x00" as *const u8 as *const libc::c_char, ok_to_continue = false;
); } else {
current_block = 11328123142868406523; if !meta_part.is_null() {
} else { mailmime_smart_add_part(message, meta_part);
if !meta_part.is_null() { }
mailmime_smart_add_part(message, meta_part); if (*msg).param.exists(Param::SetLatitude) {
} let latitude = (*msg)
if (*msg).param.exists(Param::SetLatitude) { .param
let latitude = (*msg) .get_float(Param::SetLatitude)
.param .unwrap_or_default();
.get_float(Param::SetLatitude) let longitude = (*msg)
.unwrap_or_default(); .param
let longitude = (*msg) .get_float(Param::SetLongitude)
.param .unwrap_or_default();
.get_float(Param::SetLongitude) let kml_file =
.unwrap_or_default(); dc_get_message_kml((*msg).timestamp_sort, latitude, longitude);
let kml_file = if !kml_file.is_null() {
dc_get_message_kml((*msg).timestamp_sort, latitude, longitude); let content_type = mailmime_content_new_with_str(
if !kml_file.is_null() { b"application/vnd.google-earth.kml+xml\x00" as *const u8
let content_type = mailmime_content_new_with_str( as *const libc::c_char,
b"application/vnd.google-earth.kml+xml\x00" as *const u8
as *const libc::c_char,
);
let mime_fields = mailmime_fields_new_filename(
MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int,
dc_strdup(
b"message.kml\x00" as *const u8 as *const libc::c_char,
),
MAILMIME_MECHANISM_8BIT as libc::c_int,
);
let kml_mime_part = mailmime_new_empty(content_type, mime_fields);
mailmime_set_body_text(kml_mime_part, kml_file, strlen(kml_file));
mailmime_smart_add_part(message, kml_mime_part);
}
}
if dc_is_sending_locations_to_chat((*msg).context, (*msg).chat_id) {
let mut last_added_location_id: uint32_t = 0 as uint32_t;
let kml_file: *mut libc::c_char = dc_get_location_kml(
(*msg).context,
(*msg).chat_id,
&mut last_added_location_id,
); );
if !kml_file.is_null() { let mime_fields = mailmime_fields_new_filename(
let content_type: *mut mailmime_content = MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int,
mailmime_content_new_with_str( dc_strdup(b"message.kml\x00" as *const u8 as *const libc::c_char),
b"application/vnd.google-earth.kml+xml\x00" as *const u8 MAILMIME_MECHANISM_8BIT as libc::c_int,
as *const libc::c_char, );
); let kml_mime_part = mailmime_new_empty(content_type, mime_fields);
let mime_fields: *mut mailmime_fields = mailmime_set_body_text(kml_mime_part, kml_file, strlen(kml_file));
mailmime_fields_new_filename(
MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int, mailmime_smart_add_part(message, kml_mime_part);
dc_strdup( }
b"location.kml\x00" as *const u8 as *const libc::c_char, }
),
MAILMIME_MECHANISM_8BIT as libc::c_int, if dc_is_sending_locations_to_chat((*msg).context, (*msg).chat_id) {
); let mut last_added_location_id: uint32_t = 0 as uint32_t;
let kml_mime_part: *mut mailmime = let kml_file: *mut libc::c_char = dc_get_location_kml(
mailmime_new_empty(content_type, mime_fields); (*msg).context,
mailmime_set_body_text(kml_mime_part, kml_file, strlen(kml_file)); (*msg).chat_id,
mailmime_smart_add_part(message, kml_mime_part); &mut last_added_location_id,
if !(*msg).param.exists(Param::SetLatitude) { );
// otherwise, the independent location is already filed if !kml_file.is_null() {
(*factory).out_last_added_location_id = last_added_location_id; let content_type: *mut mailmime_content = mailmime_content_new_with_str(
} b"application/vnd.google-earth.kml+xml\x00" as *const u8
as *const libc::c_char,
);
let mime_fields: *mut mailmime_fields = mailmime_fields_new_filename(
MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int,
dc_strdup(b"location.kml\x00" as *const u8 as *const libc::c_char),
MAILMIME_MECHANISM_8BIT as libc::c_int,
);
let kml_mime_part: *mut mailmime =
mailmime_new_empty(content_type, mime_fields);
mailmime_set_body_text(kml_mime_part, kml_file, strlen(kml_file));
mailmime_smart_add_part(message, kml_mime_part);
if !(*msg).param.exists(Param::SetLatitude) {
// otherwise, the independent location is already filed
(*factory).out_last_added_location_id = last_added_location_id;
} }
} }
current_block = 9952640327414195044;
} }
} }
} }
@@ -959,25 +941,23 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
) as *mut libc::c_void, ) as *mut libc::c_void,
); );
mailmime_add_part(message, multipart); mailmime_add_part(message, multipart);
let p1: *mut libc::c_char; let p1 = if 0
let p2: *mut libc::c_char; != (*(*factory).msg)
if 0 != (*(*factory).msg) .param
.param .get_int(Param::GuranteeE2ee)
.get_int(Param::GuranteeE2ee) .unwrap_or_default()
.unwrap_or_default()
{ {
p1 = to_cstring((*factory).context.stock_str(StockMessage::EncryptedMsg));
} else {
p1 = dc_msg_get_summarytext((*factory).msg, 32)
}
p2 = to_cstring(
(*factory) (*factory)
.context .context
.stock_string_repl_str(StockMessage::ReadRcptMailBody, as_str(p1)), .stock_str(StockMessage::EncryptedMsg)
); .into_owned()
message_text = dc_mprintf(b"%s\r\n\x00" as *const u8 as *const libc::c_char, p2); } else {
free(p1 as *mut libc::c_void); to_string(dc_msg_get_summarytext((*factory).msg, 32))
free(p2 as *mut libc::c_void); };
let p2 = (*factory)
.context
.stock_string_repl_str(StockMessage::ReadRcptMailBody, p1);
message_text = format!("{}\r\n", p2).strdup();
let human_mime_part: *mut mailmime = build_body_text(message_text); let human_mime_part: *mut mailmime = build_body_text(message_text);
mailmime_add_part(multipart, human_mime_part); mailmime_add_part(multipart, human_mime_part);
message_text2 = message_text2 =
@@ -995,86 +975,81 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
mailmime_set_body_text(mach_mime_part, message_text2, strlen(message_text2)); mailmime_set_body_text(mach_mime_part, message_text2, strlen(message_text2));
mailmime_add_part(multipart, mach_mime_part); mailmime_add_part(multipart, mach_mime_part);
force_plaintext = 2; force_plaintext = 2;
current_block = 9952640327414195044;
} else { } else {
set_error( set_error(
factory, factory,
b"No message loaded.\x00" as *const u8 as *const libc::c_char, b"No message loaded.\x00" as *const u8 as *const libc::c_char,
); );
current_block = 11328123142868406523; ok_to_continue = false;
} }
match current_block { if ok_to_continue {
11328123142868406523 => {} if (*factory).loaded as libc::c_uint == DC_MF_MDN_LOADED as libc::c_int as libc::c_uint
_ => { {
if (*factory).loaded as libc::c_uint let e = CString::new(
== DC_MF_MDN_LOADED as libc::c_int as libc::c_uint (*factory)
{ .context
let e = CString::new( .stock_str(StockMessage::ReadRcpt)
(*factory) .as_ref(),
.context )
.stock_str(StockMessage::ReadRcpt) .unwrap();
.as_ref(), subject_str = dc_mprintf(
) b"Chat: %s\x00" as *const u8 as *const libc::c_char,
.unwrap(); e.as_ptr(),
subject_str = dc_mprintf(
b"Chat: %s\x00" as *const u8 as *const libc::c_char,
e.as_ptr(),
);
} else {
subject_str = get_subject((*factory).chat, (*factory).msg, afwd_email)
}
subject = mailimf_subject_new(dc_encode_header_words(subject_str));
mailimf_fields_add(
imf_fields,
mailimf_field_new(
MAILIMF_FIELD_SUBJECT as libc::c_int,
0 as *mut mailimf_return,
0 as *mut mailimf_orig_date,
0 as *mut mailimf_from,
0 as *mut mailimf_sender,
0 as *mut mailimf_to,
0 as *mut mailimf_cc,
0 as *mut mailimf_bcc,
0 as *mut mailimf_message_id,
0 as *mut mailimf_orig_date,
0 as *mut mailimf_from,
0 as *mut mailimf_sender,
0 as *mut mailimf_reply_to,
0 as *mut mailimf_to,
0 as *mut mailimf_cc,
0 as *mut mailimf_bcc,
0 as *mut mailimf_message_id,
0 as *mut mailimf_in_reply_to,
0 as *mut mailimf_references,
subject,
0 as *mut mailimf_comments,
0 as *mut mailimf_keywords,
0 as *mut mailimf_optional_field,
),
); );
if force_plaintext != 2 { } else {
dc_e2ee_encrypt( subject_str = get_subject((*factory).chat, (*factory).msg, afwd_email)
(*factory).context,
(*factory).recipients_addr,
force_plaintext,
e2ee_guaranteed,
min_verified,
do_gossip,
message,
&mut e2ee_helper,
);
}
if 0 != e2ee_helper.encryption_successfull {
(*factory).out_encrypted = 1;
if 0 != do_gossip {
(*factory).out_gossiped = 1
}
}
(*factory).out = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
mailmime_write_mem((*factory).out, &mut col, message);
success = 1
} }
subject = mailimf_subject_new(dc_encode_header_words(subject_str));
mailimf_fields_add(
imf_fields,
mailimf_field_new(
MAILIMF_FIELD_SUBJECT as libc::c_int,
0 as *mut mailimf_return,
0 as *mut mailimf_orig_date,
0 as *mut mailimf_from,
0 as *mut mailimf_sender,
0 as *mut mailimf_to,
0 as *mut mailimf_cc,
0 as *mut mailimf_bcc,
0 as *mut mailimf_message_id,
0 as *mut mailimf_orig_date,
0 as *mut mailimf_from,
0 as *mut mailimf_sender,
0 as *mut mailimf_reply_to,
0 as *mut mailimf_to,
0 as *mut mailimf_cc,
0 as *mut mailimf_bcc,
0 as *mut mailimf_message_id,
0 as *mut mailimf_in_reply_to,
0 as *mut mailimf_references,
subject,
0 as *mut mailimf_comments,
0 as *mut mailimf_keywords,
0 as *mut mailimf_optional_field,
),
);
if force_plaintext != 2 {
dc_e2ee_encrypt(
(*factory).context,
(*factory).recipients_addr,
force_plaintext,
e2ee_guaranteed,
min_verified,
do_gossip,
message,
&mut e2ee_helper,
);
}
if 0 != e2ee_helper.encryption_successfull {
(*factory).out_encrypted = 1;
if 0 != do_gossip {
(*factory).out_gossiped = 1
}
}
(*factory).out = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
mailmime_write_mem((*factory).out, &mut col, message);
success = 1
} }
} }
if !message.is_null() { if !message.is_null() {
@@ -1095,15 +1070,24 @@ unsafe fn get_subject(
) -> *mut libc::c_char { ) -> *mut libc::c_char {
let context = (*chat).context; let context = (*chat).context;
let ret: *mut libc::c_char; let ret: *mut libc::c_char;
let raw_subject =
dc_msg_get_summarytext_by_raw((*msg).type_0, (*msg).text, &mut (*msg).param, 32, context); let raw_subject = {
let msgtext_c = (*msg)
.text
.as_ref()
.map(|s| CString::yolo(String::as_str(s)));
let msgtext_ptr = msgtext_c.map_or(ptr::null(), |s| s.as_ptr());
dc_msg_get_summarytext_by_raw((*msg).type_0, msgtext_ptr, &mut (*msg).param, 32, context)
};
let fwd = if 0 != afwd_email { let fwd = if 0 != afwd_email {
b"Fwd: \x00" as *const u8 as *const libc::c_char b"Fwd: \x00" as *const u8 as *const libc::c_char
} else { } else {
b"\x00" as *const u8 as *const libc::c_char b"\x00" as *const u8 as *const libc::c_char
}; };
if (*msg).param.get_int(Param::Cmd).unwrap_or_default() == 6 { if (*msg).param.get_int(Param::Cmd).unwrap_or_default() == 6 {
ret = to_cstring(context.stock_str(StockMessage::AcSetupMsgSubject)) ret = context.stock_str(StockMessage::AcSetupMsgSubject).strdup()
} else if (*chat).type_0 == DC_CHAT_TYPE_GROUP as libc::c_int } else if (*chat).type_0 == DC_CHAT_TYPE_GROUP as libc::c_int
|| (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP as libc::c_int || (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP as libc::c_int
{ {
@@ -1166,12 +1150,12 @@ unsafe fn build_body_file(
let pathNfilename = (*msg) let pathNfilename = (*msg)
.param .param
.get(Param::File) .get(Param::File)
.map(|s| to_cstring(s)) .map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut()); .unwrap_or_else(|| std::ptr::null_mut());
let mut mimetype = (*msg) let mut mimetype = (*msg)
.param .param
.get(Param::MimeType) .get(Param::MimeType)
.map(|s| to_cstring(s)) .map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut()); .unwrap_or_else(|| std::ptr::null_mut());
let suffix = dc_get_filesuffix_lc(pathNfilename); let suffix = dc_get_filesuffix_lc(pathNfilename);
@@ -1179,7 +1163,7 @@ unsafe fn build_body_file(
let mut filename_encoded = 0 as *mut libc::c_char; let mut filename_encoded = 0 as *mut libc::c_char;
if !pathNfilename.is_null() { if !pathNfilename.is_null() {
if (*msg).type_0 == DC_MSG_VOICE { if (*msg).type_0 == Viewtype::Voice {
let ts = chrono::Utc.timestamp((*msg).timestamp_sort as i64, 0); let ts = chrono::Utc.timestamp((*msg).timestamp_sort as i64, 0);
let suffix = if !suffix.is_null() { let suffix = if !suffix.is_null() {
@@ -1190,10 +1174,10 @@ unsafe fn build_body_file(
let res = ts let res = ts
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix)) .format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
.to_string(); .to_string();
filename_to_send = to_cstring(res); filename_to_send = res.strdup();
} else if (*msg).type_0 == DC_MSG_AUDIO { } else if (*msg).type_0 == Viewtype::Audio {
filename_to_send = dc_get_filename(pathNfilename) filename_to_send = dc_get_filename(pathNfilename)
} else if (*msg).type_0 == DC_MSG_IMAGE || (*msg).type_0 == DC_MSG_GIF { } else if (*msg).type_0 == Viewtype::Image || (*msg).type_0 == Viewtype::Gif {
if base_name.is_null() { if base_name.is_null() {
base_name = b"image\x00" as *const u8 as *const libc::c_char base_name = b"image\x00" as *const u8 as *const libc::c_char
} }
@@ -1206,7 +1190,7 @@ unsafe fn build_body_file(
b"dat\x00" as *const u8 as *const libc::c_char b"dat\x00" as *const u8 as *const libc::c_char
}, },
) )
} else if (*msg).type_0 == DC_MSG_VIDEO { } else if (*msg).type_0 == Viewtype::Video {
filename_to_send = dc_mprintf( filename_to_send = dc_mprintf(
b"video.%s\x00" as *const u8 as *const libc::c_char, b"video.%s\x00" as *const u8 as *const libc::c_char,
if !suffix.is_null() { if !suffix.is_null() {
@@ -1328,13 +1312,13 @@ unsafe fn build_body_file(
* Render * Render
******************************************************************************/ ******************************************************************************/
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> libc::c_int { unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> bool {
let mut file_size_okay = 1; let mut file_size_okay = true;
let pathNfilename = to_cstring((*msg).param.get(Param::File).unwrap_or_default()); let pathNfilename = (*msg).param.get(Param::File).unwrap_or_default().strdup();
let bytes = dc_get_filebytes((*msg).context, pathNfilename); let bytes = dc_get_filebytes((*msg).context, pathNfilename);
if bytes > (49 * 1024 * 1024 / 4 * 3) { if bytes > (49 * 1024 * 1024 / 4 * 3) {
file_size_okay = 0; file_size_okay = false;
} }
free(pathNfilename as *mut _); free(pathNfilename as *mut _);

View File

@@ -11,8 +11,8 @@ use mmime::mailmime_types::*;
use mmime::mmapstring::*; use mmime::mmapstring::*;
use mmime::other::*; use mmime::other::*;
use crate::contact::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_contact::*;
use crate::dc_e2ee::*; use crate::dc_e2ee::*;
use crate::dc_location::*; use crate::dc_location::*;
use crate::dc_simplify::*; use crate::dc_simplify::*;
@@ -44,7 +44,7 @@ pub struct dc_mimepart_t {
#[derive(Clone)] #[derive(Clone)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub struct dc_mimeparser_t<'a> { pub struct dc_mimeparser_t<'a> {
pub parts: *mut carray, pub parts: Vec<dc_mimepart_t>,
pub mimeroot: *mut mailmime, pub mimeroot: *mut mailmime,
pub header: HashMap<String, *mut mailimf_field>, pub header: HashMap<String, *mut mailimf_field>,
pub header_root: *mut mailimf_fields, pub header_root: *mut mailimf_fields,
@@ -55,7 +55,7 @@ pub struct dc_mimeparser_t<'a> {
pub e2ee_helper: dc_e2ee_helper_t, pub e2ee_helper: dc_e2ee_helper_t,
pub is_forwarded: libc::c_int, pub is_forwarded: libc::c_int,
pub context: &'a Context, pub context: &'a Context,
pub reports: *mut carray, pub reports: Vec<*mut mailmime>,
pub is_system_message: libc::c_int, pub is_system_message: libc::c_int,
pub location_kml: Option<dc_kml_t>, pub location_kml: Option<dc_kml_t>,
pub message_kml: Option<dc_kml_t>, pub message_kml: Option<dc_kml_t>,
@@ -71,7 +71,7 @@ static mut S_GENERATE_COMPOUND_MSGS: libc::c_int = 1i32;
pub unsafe fn dc_mimeparser_new(context: &Context) -> dc_mimeparser_t { pub unsafe fn dc_mimeparser_new(context: &Context) -> dc_mimeparser_t {
dc_mimeparser_t { dc_mimeparser_t {
parts: carray_new(16i32 as libc::c_uint), parts: Vec::new(),
mimeroot: std::ptr::null_mut(), mimeroot: std::ptr::null_mut(),
header: Default::default(), header: Default::default(),
header_root: std::ptr::null_mut(), header_root: std::ptr::null_mut(),
@@ -82,7 +82,7 @@ pub unsafe fn dc_mimeparser_new(context: &Context) -> dc_mimeparser_t {
e2ee_helper: Default::default(), e2ee_helper: Default::default(),
is_forwarded: 0, is_forwarded: 0,
context, context,
reports: carray_new(16i32 as libc::c_uint), reports: Vec::new(),
is_system_message: 0, is_system_message: 0,
location_kml: None, location_kml: None,
message_kml: None, message_kml: None,
@@ -91,58 +91,41 @@ pub unsafe fn dc_mimeparser_new(context: &Context) -> dc_mimeparser_t {
pub unsafe fn dc_mimeparser_unref(mimeparser: &mut dc_mimeparser_t) { pub unsafe fn dc_mimeparser_unref(mimeparser: &mut dc_mimeparser_t) {
dc_mimeparser_empty(mimeparser); dc_mimeparser_empty(mimeparser);
if !(*mimeparser).parts.is_null() {
carray_free((*mimeparser).parts);
}
if !(*mimeparser).reports.is_null() {
carray_free((*mimeparser).reports);
}
} }
pub unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) { pub unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) {
if !(*mimeparser).parts.is_null() { for part in mimeparser.parts.drain(..) {
let mut i: libc::c_int; dc_mimepart_unref(part);
let cnt: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int;
i = 0i32;
while i < cnt {
let part = carray_get((*mimeparser).parts, i as libc::c_uint) as *mut dc_mimepart_t;
if !part.is_null() {
dc_mimepart_unref(*Box::from_raw(part));
}
i += 1
}
carray_set_size((*mimeparser).parts, 0i32 as libc::c_uint);
} }
(*mimeparser).header_root = 0 as *mut mailimf_fields; assert!(mimeparser.parts.is_empty());
(*mimeparser).header.clear(); mimeparser.header_root = 0 as *mut mailimf_fields;
if !(*mimeparser).header_protected.is_null() { mimeparser.header.clear();
mailimf_fields_free((*mimeparser).header_protected); if !mimeparser.header_protected.is_null() {
(*mimeparser).header_protected = 0 as *mut mailimf_fields mailimf_fields_free(mimeparser.header_protected);
mimeparser.header_protected = 0 as *mut mailimf_fields
} }
(*mimeparser).is_send_by_messenger = 0i32; mimeparser.is_send_by_messenger = 0i32;
(*mimeparser).is_system_message = 0i32; mimeparser.is_system_message = 0i32;
free((*mimeparser).subject as *mut libc::c_void); free(mimeparser.subject as *mut libc::c_void);
(*mimeparser).subject = 0 as *mut libc::c_char; mimeparser.subject = 0 as *mut libc::c_char;
if !(*mimeparser).mimeroot.is_null() { if !mimeparser.mimeroot.is_null() {
mailmime_free((*mimeparser).mimeroot); mailmime_free(mimeparser.mimeroot);
(*mimeparser).mimeroot = 0 as *mut mailmime mimeparser.mimeroot = 0 as *mut mailmime
} }
(*mimeparser).is_forwarded = 0i32; mimeparser.is_forwarded = 0i32;
if !(*mimeparser).reports.is_null() { mimeparser.reports.clear();
carray_set_size((*mimeparser).reports, 0i32 as libc::c_uint); mimeparser.decrypting_failed = 0i32;
} dc_e2ee_thanks(&mut mimeparser.e2ee_helper);
(*mimeparser).decrypting_failed = 0i32;
dc_e2ee_thanks(&mut (*mimeparser).e2ee_helper);
if let Some(location_kml) = (*mimeparser).location_kml.as_mut() { if let Some(location_kml) = mimeparser.location_kml.as_mut() {
dc_kml_unref(location_kml as *mut dc_kml_t); dc_kml_unref(location_kml);
} }
(*mimeparser).location_kml = None; mimeparser.location_kml = None;
if let Some(message_kml) = (*mimeparser).message_kml.as_mut() { if let Some(message_kml) = mimeparser.message_kml.as_mut() {
dc_kml_unref(message_kml as *mut dc_kml_t); dc_kml_unref(message_kml);
} }
(*mimeparser).message_kml = None; mimeparser.message_kml = None;
} }
unsafe fn dc_mimepart_unref(mut mimepart: dc_mimepart_t) { unsafe fn dc_mimepart_unref(mut mimepart: dc_mimepart_t) {
@@ -165,19 +148,18 @@ pub unsafe fn dc_mimeparser_parse(
body_not_terminated, body_not_terminated,
body_bytes, body_bytes,
&mut index, &mut index,
&mut (*mimeparser).mimeroot, &mut mimeparser.mimeroot,
); );
if !(r != MAILIMF_NO_ERROR as libc::c_int || (*mimeparser).mimeroot.is_null()) { if !(r != MAILIMF_NO_ERROR as libc::c_int || mimeparser.mimeroot.is_null()) {
dc_e2ee_decrypt( dc_e2ee_decrypt(
(*mimeparser).context, mimeparser.context,
(*mimeparser).mimeroot, mimeparser.mimeroot,
&mut (*mimeparser).e2ee_helper, &mut mimeparser.e2ee_helper,
); );
dc_mimeparser_parse_mime_recursive(mimeparser, (*mimeparser).mimeroot); dc_mimeparser_parse_mime_recursive(mimeparser, mimeparser.mimeroot);
let field: *mut mailimf_field = dc_mimeparser_lookup_field(mimeparser, "Subject"); let field: *mut mailimf_field = dc_mimeparser_lookup_field(mimeparser, "Subject");
if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int { if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
(*mimeparser).subject = mimeparser.subject = dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value)
dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value)
} }
if !dc_mimeparser_lookup_optional_field( if !dc_mimeparser_lookup_optional_field(
mimeparser, mimeparser,
@@ -185,32 +167,37 @@ pub unsafe fn dc_mimeparser_parse(
) )
.is_null() .is_null()
{ {
(*mimeparser).is_send_by_messenger = 1i32 mimeparser.is_send_by_messenger = 1i32
} }
if !dc_mimeparser_lookup_field(mimeparser, "Autocrypt-Setup-Message").is_null() { if !dc_mimeparser_lookup_field(mimeparser, "Autocrypt-Setup-Message").is_null() {
let mut i: libc::c_int;
let mut has_setup_file: libc::c_int = 0i32; let mut has_setup_file: libc::c_int = 0i32;
i = 0i32; for part in &mimeparser.parts {
while (i as libc::c_uint) < carray_count((*mimeparser).parts) { if part.int_mimetype == 111i32 {
let part: *mut dc_mimepart_t =
carray_get((*mimeparser).parts, i as libc::c_uint) as *mut dc_mimepart_t;
if (*part).int_mimetype == 111i32 {
has_setup_file = 1i32 has_setup_file = 1i32
} }
i += 1
} }
if 0 != has_setup_file { if 0 != has_setup_file {
(*mimeparser).is_system_message = 6i32; mimeparser.is_system_message = 6i32;
i = 0i32;
while (i as libc::c_uint) < carray_count((*mimeparser).parts) { // TODO: replace the following code with this
let part_0 = // once drain_filter stabilizes.
carray_get((*mimeparser).parts, i as libc::c_uint) as *mut dc_mimepart_t; //
if (*part_0).int_mimetype != 111i32 { // See https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter
dc_mimepart_unref(*Box::from_raw(part_0)); // and https://github.com/rust-lang/rust/issues/43244
carray_delete_slow((*mimeparser).parts, i as libc::c_uint); //
i -= 1 // mimeparser
// .parts
// .drain_filter(|part| part.int_mimetype != 111)
// .for_each(|part| dc_mimepart_unref(part));
let mut i = 0;
while i != mimeparser.parts.len() {
if mimeparser.parts[i].int_mimetype != 111 {
let part = mimeparser.parts.remove(i);
dc_mimepart_unref(part);
} else {
i += 1;
} }
i += 1
} }
} }
} else { } else {
@@ -224,56 +211,69 @@ pub unsafe fn dc_mimeparser_parse(
b"location-streaming-enabled\x00" as *const u8 as *const libc::c_char, b"location-streaming-enabled\x00" as *const u8 as *const libc::c_char,
) == 0i32 ) == 0i32
{ {
(*mimeparser).is_system_message = 8i32 mimeparser.is_system_message = 8i32
} }
} }
} }
if !dc_mimeparser_lookup_field(mimeparser, "Chat-Group-Image").is_null() if !dc_mimeparser_lookup_field(mimeparser, "Chat-Group-Image").is_null()
&& carray_count((*mimeparser).parts) >= 1i32 as libc::c_uint && !mimeparser.parts.is_empty()
{ {
let textpart: *mut dc_mimepart_t = let textpart = &mimeparser.parts[0];
carray_get((*mimeparser).parts, 0i32 as libc::c_uint) as *mut dc_mimepart_t; if textpart.type_0 == 10i32 {
if (*textpart).type_0 == 10i32 { if mimeparser.parts.len() >= 2 {
if carray_count((*mimeparser).parts) >= 2i32 as libc::c_uint { let imgpart = &mut mimeparser.parts[1];
let mut imgpart: *mut dc_mimepart_t = if imgpart.type_0 == 20i32 {
carray_get((*mimeparser).parts, 1i32 as libc::c_uint) as *mut dc_mimepart_t; imgpart.is_meta = 1i32
if (*imgpart).type_0 == 20i32 {
(*imgpart).is_meta = 1i32
} }
} }
} }
} }
if 0 != (*mimeparser).is_send_by_messenger if 0 != mimeparser.is_send_by_messenger
&& 0 != S_GENERATE_COMPOUND_MSGS && 0 != S_GENERATE_COMPOUND_MSGS
&& carray_count((*mimeparser).parts) == 2i32 as libc::c_uint && mimeparser.parts.len() == 2
{ {
let mut textpart_0 = carray_get((*mimeparser).parts, 0) as *mut dc_mimepart_t; let need_drop: bool;
let mut filepart = carray_get((*mimeparser).parts, 1) as *mut dc_mimepart_t;
if (*textpart_0).type_0 == 10i32
&& ((*filepart).type_0 == 20i32
|| (*filepart).type_0 == 21i32
|| (*filepart).type_0 == 40i32
|| (*filepart).type_0 == 41i32
|| (*filepart).type_0 == 50i32
|| (*filepart).type_0 == 60i32)
&& 0 == (*filepart).is_meta
{ {
free((*filepart).msg as *mut libc::c_void); let textpart = &mimeparser.parts[0];
(*filepart).msg = (*textpart_0).msg; let filepart = &mimeparser.parts[1];
(*textpart_0).msg = 0 as *mut libc::c_char; need_drop = textpart.type_0 == 10i32
dc_mimepart_unref(*Box::from_raw(textpart_0)); && (filepart.type_0 == 20i32
carray_delete_slow((*mimeparser).parts, 0i32 as libc::c_uint); || filepart.type_0 == 21i32
|| filepart.type_0 == 40i32
|| filepart.type_0 == 41i32
|| filepart.type_0 == 50i32
|| filepart.type_0 == 60i32)
&& 0 == filepart.is_meta;
}
if need_drop {
let mut filepart = mimeparser.parts.swap_remove(1);
// clear old one
free(filepart.msg as *mut libc::c_void);
// insert new one
filepart.msg = mimeparser.parts[0].msg;
// forget the one we use now
mimeparser.parts[0].msg = std::ptr::null_mut();
// swap new with old
let old = std::mem::replace(&mut mimeparser.parts[0], filepart);
// unref old one
dc_mimepart_unref(old);
} }
} }
if !(*mimeparser).subject.is_null() { if !mimeparser.subject.is_null() {
let mut prepend_subject: libc::c_int = 1i32; let mut prepend_subject: libc::c_int = 1i32;
if 0 == (*mimeparser).decrypting_failed { if 0 == mimeparser.decrypting_failed {
let p: *mut libc::c_char = strchr((*mimeparser).subject, ':' as i32); let p: *mut libc::c_char = strchr(mimeparser.subject, ':' as i32);
if p.wrapping_offset_from((*mimeparser).subject) == 2 if p.wrapping_offset_from(mimeparser.subject) == 2
|| p.wrapping_offset_from((*mimeparser).subject) == 3 || p.wrapping_offset_from(mimeparser.subject) == 3
|| 0 != (*mimeparser).is_send_by_messenger || 0 != mimeparser.is_send_by_messenger
|| !strstr( || !strstr(
(*mimeparser).subject, mimeparser.subject,
b"Chat:\x00" as *const u8 as *const libc::c_char, b"Chat:\x00" as *const u8 as *const libc::c_char,
) )
.is_null() .is_null()
@@ -282,62 +282,48 @@ pub unsafe fn dc_mimeparser_parse(
} }
} }
if 0 != prepend_subject { if 0 != prepend_subject {
let subj: *mut libc::c_char = dc_strdup((*mimeparser).subject); let subj: *mut libc::c_char = dc_strdup(mimeparser.subject);
let p_0: *mut libc::c_char = strchr(subj, '[' as i32); let p_0: *mut libc::c_char = strchr(subj, '[' as i32);
if !p_0.is_null() { if !p_0.is_null() {
*p_0 = 0i32 as libc::c_char *p_0 = 0i32 as libc::c_char
} }
dc_trim(subj); dc_trim(subj);
if 0 != *subj.offset(0isize) { if 0 != *subj.offset(0isize) {
let mut i_0: libc::c_int; for part in mimeparser.parts.iter_mut() {
let icnt: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int; if part.type_0 == 10i32 {
i_0 = 0i32;
while i_0 < icnt {
let mut part_1: *mut dc_mimepart_t =
carray_get((*mimeparser).parts, i_0 as libc::c_uint)
as *mut dc_mimepart_t;
if (*part_1).type_0 == 10i32 {
let new_txt: *mut libc::c_char = dc_mprintf( let new_txt: *mut libc::c_char = dc_mprintf(
b"%s \xe2\x80\x93 %s\x00" as *const u8 as *const libc::c_char, b"%s \xe2\x80\x93 %s\x00" as *const u8 as *const libc::c_char,
subj, subj,
(*part_1).msg, part.msg,
); );
free((*part_1).msg as *mut libc::c_void); free(part.msg as *mut libc::c_void);
(*part_1).msg = new_txt; part.msg = new_txt;
break; break;
} else {
i_0 += 1
} }
} }
} }
free(subj as *mut libc::c_void); free(subj as *mut libc::c_void);
} }
} }
if 0 != (*mimeparser).is_forwarded { if 0 != mimeparser.is_forwarded {
let mut i_1: libc::c_int; for part in mimeparser.parts.iter_mut() {
let icnt_0: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int; part.param.set_int(Param::Forwarded, 1);
i_1 = 0i32;
while i_1 < icnt_0 {
let part_2 =
carray_get((*mimeparser).parts, i_1 as libc::c_uint) as *mut dc_mimepart_t;
(*part_2).param.set_int(Param::Forwarded, 1);
i_1 += 1
} }
} }
if carray_count((*mimeparser).parts) == 1i32 as libc::c_uint { if mimeparser.parts.len() == 1 {
let mut part_3: *mut dc_mimepart_t = if mimeparser.parts[0].type_0 == 40i32 {
carray_get((*mimeparser).parts, 0i32 as libc::c_uint) as *mut dc_mimepart_t;
if (*part_3).type_0 == 40i32 {
if !dc_mimeparser_lookup_optional_field( if !dc_mimeparser_lookup_optional_field(
mimeparser, mimeparser,
b"Chat-Voice-Message\x00" as *const u8 as *const libc::c_char, b"Chat-Voice-Message\x00" as *const u8 as *const libc::c_char,
) )
.is_null() .is_null()
{ {
(*part_3).type_0 = 41i32 let part_mut = &mut mimeparser.parts[0];
part_mut.type_0 = 41i32
} }
} }
if (*part_3).type_0 == 40i32 || (*part_3).type_0 == 41i32 || (*part_3).type_0 == 50i32 { let part = &mimeparser.parts[0];
if part.type_0 == 40i32 || part.type_0 == 41i32 || part.type_0 == 50i32 {
let field_0 = dc_mimeparser_lookup_optional_field( let field_0 = dc_mimeparser_lookup_optional_field(
mimeparser, mimeparser,
b"Chat-Duration\x00" as *const u8 as *const libc::c_char, b"Chat-Duration\x00" as *const u8 as *const libc::c_char,
@@ -345,17 +331,18 @@ pub unsafe fn dc_mimeparser_parse(
if !field_0.is_null() { if !field_0.is_null() {
let duration_ms: libc::c_int = dc_atoi_null_is_0((*field_0).fld_value); let duration_ms: libc::c_int = dc_atoi_null_is_0((*field_0).fld_value);
if duration_ms > 0i32 && duration_ms < 24i32 * 60i32 * 60i32 * 1000i32 { if duration_ms > 0i32 && duration_ms < 24i32 * 60i32 * 60i32 * 1000i32 {
(*part_3).param.set_int(Param::Duration, duration_ms); let part_mut = &mut mimeparser.parts[0];
part_mut.param.set_int(Param::Duration, duration_ms);
} }
} }
} }
} }
if 0 == (*mimeparser).decrypting_failed { if 0 == mimeparser.decrypting_failed {
let dn_field: *const mailimf_optional_field = dc_mimeparser_lookup_optional_field( let dn_field: *const mailimf_optional_field = dc_mimeparser_lookup_optional_field(
mimeparser, mimeparser,
b"Chat-Disposition-Notification-To\x00" as *const u8 as *const libc::c_char, b"Chat-Disposition-Notification-To\x00" as *const u8 as *const libc::c_char,
); );
if !dn_field.is_null() && !dc_mimeparser_get_last_nonmeta(mimeparser).is_null() { if !dn_field.is_null() && dc_mimeparser_get_last_nonmeta(mimeparser).is_some() {
let mut mb_list: *mut mailimf_mailbox_list = 0 as *mut mailimf_mailbox_list; let mut mb_list: *mut mailimf_mailbox_list = 0 as *mut mailimf_mailbox_list;
let mut index_0: size_t = 0i32 as size_t; let mut index_0: size_t = 0i32 as size_t;
if mailimf_mailbox_list_parse( if mailimf_mailbox_list_parse(
@@ -379,10 +366,9 @@ pub unsafe fn dc_mimeparser_parse(
); );
if !from_addr.is_null() { if !from_addr.is_null() {
if strcmp(from_addr, dn_to_addr) == 0i32 { if strcmp(from_addr, dn_to_addr) == 0i32 {
let part_4: *mut dc_mimepart_t = if let Some(part_4) = dc_mimeparser_get_last_nonmeta(mimeparser)
dc_mimeparser_get_last_nonmeta(mimeparser); {
if !part_4.is_null() { part_4.param.set_int(Param::WantsMdn, 1);
(*part_4).param.set_int(Param::WantsMdn, 1);
} }
} }
free(from_addr as *mut libc::c_void); free(from_addr as *mut libc::c_void);
@@ -396,21 +382,15 @@ pub unsafe fn dc_mimeparser_parse(
} }
} }
/* Cleanup - and try to create at least an empty part if there are no parts yet */ /* Cleanup - and try to create at least an empty part if there are no parts yet */
if dc_mimeparser_get_last_nonmeta(mimeparser).is_null() if dc_mimeparser_get_last_nonmeta(mimeparser).is_none() && mimeparser.reports.is_empty() {
&& carray_count((*mimeparser).reports) == 0i32 as libc::c_uint
{
let mut part_5 = dc_mimepart_new(); let mut part_5 = dc_mimepart_new();
part_5.type_0 = 10i32; part_5.type_0 = 10i32;
if !(*mimeparser).subject.is_null() && 0 == (*mimeparser).is_send_by_messenger { if !mimeparser.subject.is_null() && 0 == mimeparser.is_send_by_messenger {
part_5.msg = dc_strdup((*mimeparser).subject) part_5.msg = dc_strdup(mimeparser.subject)
} else { } else {
part_5.msg = dc_strdup(b"\x00" as *const u8 as *const libc::c_char) part_5.msg = dc_strdup(b"\x00" as *const u8 as *const libc::c_char)
} }
carray_add( mimeparser.parts.push(part_5);
(*mimeparser).parts,
Box::into_raw(Box::new(part_5)) as *mut libc::c_void,
0 as *mut libc::c_uint,
);
}; };
} }
@@ -429,22 +409,14 @@ unsafe fn dc_mimepart_new() -> dc_mimepart_t {
} }
} }
pub unsafe fn dc_mimeparser_get_last_nonmeta(mimeparser: &dc_mimeparser_t) -> *mut dc_mimepart_t { pub fn dc_mimeparser_get_last_nonmeta<'a>(
if !(*mimeparser).parts.is_null() { mimeparser: &'a mut dc_mimeparser_t,
let mut i: libc::c_int; ) -> Option<&'a mut dc_mimepart_t> {
let icnt: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int; mimeparser
i = icnt - 1i32; .parts
while i >= 0i32 { .iter_mut()
let part: *mut dc_mimepart_t = .rev()
carray_get(mimeparser.parts, i as libc::c_uint) as *mut dc_mimepart_t; .find(|part| part.is_meta == 0)
if !part.is_null() && 0 == (*part).is_meta {
return part;
}
i -= 1
}
}
0 as *mut dc_mimepart_t
} }
/*the result must be freed*/ /*the result must be freed*/
@@ -460,7 +432,7 @@ pub unsafe fn mailimf_find_first_addr(mb_list: *const mailimf_mailbox_list) -> *
0 as *mut libc::c_void 0 as *mut libc::c_void
}) as *mut mailimf_mailbox; }) as *mut mailimf_mailbox;
if !mb.is_null() && !(*mb).mb_addr_spec.is_null() { if !mb.is_null() && !(*mb).mb_addr_spec.is_null() {
return dc_addr_normalize((*mb).mb_addr_spec); return addr_normalize(as_str((*mb).mb_addr_spec)).strdup();
} }
cur = if !cur.is_null() { cur = if !cur.is_null() {
(*cur).next (*cur).next
@@ -531,32 +503,32 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
) == 0i32 ) == 0i32
{ {
info!( info!(
(*mimeparser).context, mimeparser.context,
0, "Protected headers found in text/rfc822-headers attachment: Will be ignored.", 0, "Protected headers found in text/rfc822-headers attachment: Will be ignored.",
); );
return 0i32; return 0i32;
} }
if (*mimeparser).header_protected.is_null() { if mimeparser.header_protected.is_null() {
let mut dummy: size_t = 0i32 as size_t; let mut dummy: size_t = 0i32 as size_t;
if mailimf_envelope_and_optional_fields_parse( if mailimf_envelope_and_optional_fields_parse(
(*mime).mm_mime_start, (*mime).mm_mime_start,
(*mime).mm_length, (*mime).mm_length,
&mut dummy, &mut dummy,
&mut (*mimeparser).header_protected, &mut mimeparser.header_protected,
) != MAILIMF_NO_ERROR as libc::c_int ) != MAILIMF_NO_ERROR as libc::c_int
|| (*mimeparser).header_protected.is_null() || mimeparser.header_protected.is_null()
{ {
warn!((*mimeparser).context, 0, "Protected headers parsing error.",); warn!(mimeparser.context, 0, "Protected headers parsing error.",);
} else { } else {
hash_header( hash_header(
&mut (*mimeparser).header, &mut mimeparser.header,
(*mimeparser).header_protected, mimeparser.header_protected,
(*mimeparser).context, mimeparser.context,
); );
} }
} else { } else {
info!( info!(
(*mimeparser).context, mimeparser.context,
0, 0,
"Protected headers found in MIME header: Will be ignored as we already found an outer one." "Protected headers found in MIME header: Will be ignored as we already found an outer one."
); );
@@ -660,7 +632,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
let mut part = dc_mimepart_new(); let mut part = dc_mimepart_new();
part.type_0 = 10i32; part.type_0 = 10i32;
let msg_body = CString::new( let msg_body = CString::new(
(*mimeparser) mimeparser
.context .context
.stock_str(StockMessage::CantDecryptMsgBody) .stock_str(StockMessage::CantDecryptMsgBody)
.as_ref(), .as_ref(),
@@ -671,13 +643,9 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
msg_body.as_ptr(), msg_body.as_ptr(),
); );
part.msg_raw = dc_strdup(part.msg); part.msg_raw = dc_strdup(part.msg);
carray_add( mimeparser.parts.push(part);
(*mimeparser).parts,
Box::into_raw(Box::new(part)) as *mut libc::c_void,
0 as *mut libc::c_uint,
);
any_part_added = 1i32; any_part_added = 1i32;
(*mimeparser).decrypting_failed = 1i32 mimeparser.decrypting_failed = 1i32
} }
46 => { 46 => {
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
@@ -705,11 +673,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
b"disposition-notification\x00" as *const u8 as *const libc::c_char, b"disposition-notification\x00" as *const u8 as *const libc::c_char,
) == 0i32 ) == 0i32
{ {
carray_add( mimeparser.reports.push(mime);
(*mimeparser).reports,
mime as *mut libc::c_void,
0 as *mut libc::c_uint,
);
} else { } else {
any_part_added = dc_mimeparser_parse_mime_recursive( any_part_added = dc_mimeparser_parse_mime_recursive(
mimeparser, mimeparser,
@@ -759,7 +723,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
} }
if plain_cnt == 1i32 && html_cnt == 1i32 { if plain_cnt == 1i32 && html_cnt == 1i32 {
warn!( warn!(
(*mimeparser).context, mimeparser.context,
0i32, 0i32,
"HACK: multipart/mixed message found with PLAIN and HTML, we\'ll skip the HTML part as this seems to be unwanted." "HACK: multipart/mixed message found with PLAIN and HTML, we\'ll skip the HTML part as this seems to be unwanted."
); );
@@ -788,12 +752,12 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
} }
} }
3 => { 3 => {
if (*mimeparser).header_root.is_null() { if mimeparser.header_root.is_null() {
(*mimeparser).header_root = (*mime).mm_data.mm_message.mm_fields; mimeparser.header_root = (*mime).mm_data.mm_message.mm_fields;
hash_header( hash_header(
&mut (*mimeparser).header, &mut mimeparser.header,
(*mimeparser).header_root, mimeparser.header_root,
(*mimeparser).context, mimeparser.context,
); );
} }
if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() { if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() {
@@ -1136,7 +1100,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
mime: *mut mailmime, mime: *mut mailmime,
) -> libc::c_int { ) -> libc::c_int {
let mut current_block: u64; let mut current_block: u64;
let old_part_count: libc::c_int = carray_count(mimeparser.parts) as libc::c_int; let old_part_count = mimeparser.parts.len();
let mime_type: libc::c_int; let mime_type: libc::c_int;
let mime_data: *mut mailmime_data; let mime_data: *mut mailmime_data;
let file_suffix: *mut libc::c_char = 0 as *mut libc::c_char; let file_suffix: *mut libc::c_char = 0 as *mut libc::c_char;
@@ -1173,8 +1137,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
simplifier = Some(dc_simplify_t::new()); simplifier = Some(dc_simplify_t::new());
} }
/* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */ /* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */
let charset: *const libc::c_char = let charset = mailmime_content_charset_get((*mime).mm_content_type);
mailmime_content_charset_get((*mime).mm_content_type);
if !charset.is_null() if !charset.is_null()
&& strcmp(charset, b"utf-8\x00" as *const u8 as *const libc::c_char) && strcmp(charset, b"utf-8\x00" as *const u8 as *const libc::c_char)
!= 0i32 != 0i32
@@ -1190,12 +1153,16 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
); );
let (res, _, _) = encoding.decode(data); let (res, _, _) = encoding.decode(data);
info!(mimeparser.context, 0, "decoded message: '{}'", res);
if res.is_empty() { if res.is_empty() {
/* no error - but nothing to add */ /* no error - but nothing to add */
current_block = 8795901732489102124; current_block = 8795901732489102124;
} else { } else {
decoded_data_bytes = res.len(); let b = res.as_bytes();
decoded_data = res.as_ptr() as *const libc::c_char; decoded_data = b.as_ptr() as *const libc::c_char;
decoded_data_bytes = b.len();
std::mem::forget(res);
current_block = 17788412896529399552; current_block = 17788412896529399552;
} }
} else { } else {
@@ -1215,19 +1182,19 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
8795901732489102124 => {} 8795901732489102124 => {}
_ => { _ => {
/* check header directly as is_send_by_messenger is not yet set up */ /* check header directly as is_send_by_messenger is not yet set up */
let is_msgrmsg: libc::c_int = (dc_mimeparser_lookup_optional_field( let is_msgrmsg = (!dc_mimeparser_lookup_optional_field(
&mimeparser, &mimeparser,
b"Chat-Version\x00" as *const u8 as *const libc::c_char, b"Chat-Version\x00" as *const u8 as *const libc::c_char,
) != 0 as *mut libc::c_void )
as *mut mailimf_optional_field) .is_null())
as libc::c_int; as libc::c_int;
let simplified_txt: *mut libc::c_char =
simplifier.unwrap().simplify( let simplified_txt = simplifier.unwrap().simplify(
decoded_data, decoded_data,
decoded_data_bytes as libc::c_int, decoded_data_bytes as libc::c_int,
if mime_type == 70i32 { 1i32 } else { 0i32 }, if mime_type == 70i32 { 1i32 } else { 0i32 },
is_msgrmsg, is_msgrmsg,
); );
if !simplified_txt.is_null() if !simplified_txt.is_null()
&& 0 != *simplified_txt.offset(0isize) as libc::c_int && 0 != *simplified_txt.offset(0isize) as libc::c_int
{ {
@@ -1242,7 +1209,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
free(simplified_txt as *mut libc::c_void); free(simplified_txt as *mut libc::c_void);
} }
if 0 != simplifier.unwrap().is_forwarded { if 0 != simplifier.unwrap().is_forwarded {
(*mimeparser).is_forwarded = 1i32 mimeparser.is_forwarded = 1i32
} }
current_block = 10261677128829721533; current_block = 10261677128829721533;
} }
@@ -1323,9 +1290,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
} }
if !filename_parts.is_empty() { if !filename_parts.is_empty() {
free(desired_filename as *mut libc::c_void); free(desired_filename as *mut libc::c_void);
let parts_c = to_cstring(filename_parts); let parts_c = CString::yolo(filename_parts);
desired_filename = dc_decode_ext_header(parts_c); desired_filename = dc_decode_ext_header(parts_c.as_ptr());
free(parts_c as *mut _);
} }
if desired_filename.is_null() { if desired_filename.is_null() {
let param = mailmime_find_ct_parameter( let param = mailmime_find_ct_parameter(
@@ -1371,8 +1337,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
4, 4,
) == 0i32 ) == 0i32
{ {
(*mimeparser).location_kml = Some(dc_kml_parse( mimeparser.location_kml = Some(dc_kml_parse(
(*mimeparser).context, mimeparser.context,
decoded_data, decoded_data,
decoded_data_bytes, decoded_data_bytes,
)); ));
@@ -1390,8 +1356,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
4, 4,
) == 0i32 ) == 0i32
{ {
(*mimeparser).message_kml = Some(dc_kml_parse( mimeparser.message_kml = Some(dc_kml_parse(
(*mimeparser).context, mimeparser.context,
decoded_data, decoded_data,
decoded_data_bytes, decoded_data_bytes,
)); ));
@@ -1430,16 +1396,16 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
free(file_suffix as *mut libc::c_void); free(file_suffix as *mut libc::c_void);
free(desired_filename as *mut libc::c_void); free(desired_filename as *mut libc::c_void);
free(raw_mime as *mut libc::c_void); free(raw_mime as *mut libc::c_void);
return if carray_count((*mimeparser).parts) > old_part_count as libc::c_uint { return if mimeparser.parts.len() > old_part_count {
1i32 1
} else { } else {
0i32 0
}; };
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe fn do_add_single_file_part( unsafe fn do_add_single_file_part(
parser: &dc_mimeparser_t, parser: &mut dc_mimeparser_t,
msg_type: libc::c_int, msg_type: libc::c_int,
mime_type: libc::c_int, mime_type: libc::c_int,
raw_mime: *const libc::c_char, raw_mime: *const libc::c_char,
@@ -1488,17 +1454,13 @@ unsafe fn do_add_single_file_part(
free(pathNfilename as *mut libc::c_void); free(pathNfilename as *mut libc::c_void);
} }
unsafe fn do_add_single_part(parser: &dc_mimeparser_t, mut part: dc_mimepart_t) { unsafe fn do_add_single_part(parser: &mut dc_mimeparser_t, mut part: dc_mimepart_t) {
if 0 != (*parser).e2ee_helper.encrypted && (*parser).e2ee_helper.signatures.len() > 0 { if 0 != (*parser).e2ee_helper.encrypted && (*parser).e2ee_helper.signatures.len() > 0 {
part.param.set_int(Param::GuranteeE2ee, 1); part.param.set_int(Param::GuranteeE2ee, 1);
} else if 0 != (*parser).e2ee_helper.encrypted { } else if 0 != (*parser).e2ee_helper.encrypted {
part.param.set_int(Param::ErroneousE2ee, 0x2); part.param.set_int(Param::ErroneousE2ee, 0x2);
} }
carray_add( parser.parts.push(part);
(*parser).parts,
Box::into_raw(Box::new(part)) as *mut libc::c_void,
0 as *mut libc::c_uint,
);
} }
// TODO should return bool /rtn // TODO should return bool /rtn
@@ -1616,8 +1578,8 @@ pub unsafe fn dc_mimeparser_sender_equals_recipient(mimeparser: &dc_mimeparser_t
let fld: *const mailimf_field; let fld: *const mailimf_field;
let mut fld_from: *const mailimf_from = 0 as *const mailimf_from; let mut fld_from: *const mailimf_from = 0 as *const mailimf_from;
let mb: *mut mailimf_mailbox; let mb: *mut mailimf_mailbox;
let mut from_addr_norm: *mut libc::c_char = 0 as *mut libc::c_char;
if !(*mimeparser).header_root.is_null() { if !mimeparser.header_root.is_null() {
/* get From: and check there is exactly one sender */ /* get From: and check there is exactly one sender */
fld = mailimf_find_field(mimeparser.header_root, MAILIMF_FIELD_FROM as libc::c_int); fld = mailimf_find_field(mimeparser.header_root, MAILIMF_FIELD_FROM as libc::c_int);
if !(fld.is_null() if !(fld.is_null()
@@ -1635,17 +1597,16 @@ pub unsafe fn dc_mimeparser_sender_equals_recipient(mimeparser: &dc_mimeparser_t
0 as *mut libc::c_void 0 as *mut libc::c_void
}) as *mut mailimf_mailbox; }) as *mut mailimf_mailbox;
if !mb.is_null() { if !mb.is_null() {
from_addr_norm = dc_addr_normalize((*mb).mb_addr_spec); let from_addr_norm = addr_normalize(as_str((*mb).mb_addr_spec));
let recipients = mailimf_get_recipients(mimeparser.header_root); let recipients = mailimf_get_recipients(mimeparser.header_root);
if recipients.len() == 1 { if recipients.len() == 1 {
if recipients.contains(as_str(from_addr_norm)) { if recipients.contains(from_addr_norm) {
sender_equals_recipient = 1i32; sender_equals_recipient = 1i32;
} }
} }
} }
} }
} }
free(from_addr_norm as *mut libc::c_void);
sender_equals_recipient sender_equals_recipient
} }
@@ -1742,15 +1703,15 @@ pub unsafe fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet<
/* ****************************************************************************** /* ******************************************************************************
* low-level-tools for getting a list of all recipients * low-level-tools for getting a list of all recipients
******************************************************************************/ ******************************************************************************/
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe fn mailimf_get_recipients__add_addr( unsafe fn mailimf_get_recipients__add_addr(
recipients: &mut HashSet<String>, recipients: &mut HashSet<String>,
mb: *mut mailimf_mailbox, mb: *mut mailimf_mailbox,
) { ) {
if !mb.is_null() { if !mb.is_null() {
let addr_norm: *mut libc::c_char = dc_addr_normalize((*mb).mb_addr_spec); let addr_norm = addr_normalize(as_str((*mb).mb_addr_spec));
recipients.insert(to_string(addr_norm)); recipients.insert(addr_norm.into());
free(addr_norm as *mut libc::c_void);
}; };
} }
@@ -1785,27 +1746,20 @@ pub unsafe fn mailimf_find_field(
} }
pub unsafe fn dc_mimeparser_repl_msg_by_error( pub unsafe fn dc_mimeparser_repl_msg_by_error(
mimeparser: &dc_mimeparser_t, mimeparser: &mut dc_mimeparser_t,
error_msg: *const libc::c_char, error_msg: *const libc::c_char,
) { ) {
let mut part: *mut dc_mimepart_t; if mimeparser.parts.is_empty() {
let mut i: libc::c_int;
if (*mimeparser).parts.is_null() || carray_count((*mimeparser).parts) <= 0i32 as libc::c_uint {
return; return;
} }
part = carray_get((*mimeparser).parts, 0i32 as libc::c_uint) as *mut dc_mimepart_t; let part = &mut mimeparser.parts[0];
(*part).type_0 = 10i32; part.type_0 = 10i32;
free((*part).msg as *mut libc::c_void); free(part.msg as *mut libc::c_void);
(*part).msg = dc_mprintf(b"[%s]\x00" as *const u8 as *const libc::c_char, error_msg); part.msg = dc_mprintf(b"[%s]\x00" as *const u8 as *const libc::c_char, error_msg);
i = 1i32; for part in mimeparser.parts.drain(1..) {
while (i as libc::c_uint) < carray_count((*mimeparser).parts) { dc_mimepart_unref(part);
part = carray_get((*mimeparser).parts, i as libc::c_uint) as *mut dc_mimepart_t;
if !part.is_null() {
dc_mimepart_unref(*Box::from_raw(part));
}
i += 1
} }
carray_set_size((*mimeparser).parts, 1i32 as libc::c_uint); assert_eq!(mimeparser.parts.len(), 1);
} }
/*the result is a pointer to mime, must not be freed*/ /*the result is a pointer to mime, must not be freed*/

View File

@@ -1,9 +1,9 @@
use std::ffi::CString; use std::ffi::CString;
use crate::constants::*; use crate::constants::*;
use crate::contact::*;
use crate::context::*; use crate::context::*;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_job::*; use crate::dc_job::*;
use crate::dc_lot::dc_lot_t; use crate::dc_lot::dc_lot_t;
use crate::dc_lot::*; use crate::dc_lot::*;
@@ -14,6 +14,7 @@ use crate::sql;
use crate::stock::StockMessage; use crate::stock::StockMessage;
use crate::types::*; use crate::types::*;
use crate::x::*; use crate::x::*;
use std::ptr;
/* * the structure behind dc_msg_t */ /* * the structure behind dc_msg_t */
#[derive(Clone)] #[derive(Clone)]
@@ -25,13 +26,13 @@ pub struct dc_msg_t<'a> {
pub to_id: uint32_t, pub to_id: uint32_t,
pub chat_id: uint32_t, pub chat_id: uint32_t,
pub move_state: dc_move_state_t, pub move_state: dc_move_state_t,
pub type_0: libc::c_int, pub type_0: Viewtype,
pub state: libc::c_int, pub state: libc::c_int,
pub hidden: libc::c_int, pub hidden: libc::c_int,
pub timestamp_sort: i64, pub timestamp_sort: i64,
pub timestamp_sent: i64, pub timestamp_sent: i64,
pub timestamp_rcvd: i64, pub timestamp_rcvd: i64,
pub text: *mut libc::c_char, pub text: Option<String>,
pub context: &'a Context, pub context: &'a Context,
pub rfc724_mid: *mut libc::c_char, pub rfc724_mid: *mut libc::c_char,
pub in_reply_to: *mut libc::c_char, pub in_reply_to: *mut libc::c_char,
@@ -47,12 +48,10 @@ pub struct dc_msg_t<'a> {
// handle messages // handle messages
pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_char { pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_char {
let msg = dc_msg_new_untyped(context); let msg = dc_msg_new_untyped(context);
let contact_from = dc_contact_new(context);
let mut p: *mut libc::c_char; let mut p: *mut libc::c_char;
let mut ret = String::new(); let mut ret = String::new();
dc_msg_load_from_db(msg, context, msg_id); dc_msg_load_from_db(msg, context, msg_id);
dc_contact_load_from_db(contact_from, &context.sql, (*msg).from_id);
let rawtxt: Option<String> = context.sql.query_row_col( let rawtxt: Option<String> = context.sql.query_row_col(
context, context,
@@ -64,36 +63,35 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
if rawtxt.is_none() { if rawtxt.is_none() {
ret += &format!("Cannot load message #{}.", msg_id as usize); ret += &format!("Cannot load message #{}.", msg_id as usize);
dc_msg_unref(msg); dc_msg_unref(msg);
dc_contact_unref(contact_from); return ret.strdup();
return to_cstring(ret);
} }
let rawtxt = rawtxt.unwrap(); let rawtxt = rawtxt.unwrap();
let rawtxt = dc_truncate_str(rawtxt.trim(), 100000); let rawtxt = dc_truncate_str(rawtxt.trim(), 100000);
let fts = dc_timestamp_to_str_safe(dc_msg_get_timestamp(msg)); let fts = dc_timestamp_to_str(dc_msg_get_timestamp(msg));
ret += &format!("Sent: {}", fts); ret += &format!("Sent: {}", fts);
p = dc_contact_get_name_n_addr(contact_from); let name = Contact::load_from_db(context, (*msg).from_id)
ret += &format!(" by {}", to_string(p)); .map(|contact| contact.get_name_n_addr())
free(p as *mut libc::c_void); .unwrap_or_default();
ret += &format!(" by {}", name);
ret += "\n"; ret += "\n";
if (*msg).from_id != 1 as libc::c_uint { if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint {
p = dc_timestamp_to_str(if 0 != (*msg).timestamp_rcvd { let s = dc_timestamp_to_str(if 0 != (*msg).timestamp_rcvd {
(*msg).timestamp_rcvd (*msg).timestamp_rcvd
} else { } else {
(*msg).timestamp_sort (*msg).timestamp_sort
}); });
ret += &format!("Received: {}", as_str(p)); ret += &format!("Received: {}", &s);
free(p as *mut libc::c_void);
ret += "\n"; ret += "\n";
} }
if (*msg).from_id == 2 || (*msg).to_id == 2 { if (*msg).from_id == 2 || (*msg).to_id == 2 {
// device-internal message, no further details needed // device-internal message, no further details needed
dc_msg_unref(msg); dc_msg_unref(msg);
dc_contact_unref(contact_from); return ret.strdup();
return to_cstring(ret);
} }
context context
@@ -109,17 +107,14 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|rows| { |rows| {
for row in rows { for row in rows {
let (contact_id, ts) = row?; let (contact_id, ts) = row?;
let fts = dc_timestamp_to_str_safe(ts); let fts = dc_timestamp_to_str(ts);
ret += &format!("Read: {}", fts); ret += &format!("Read: {}", fts);
let contact = dc_contact_new(context); let name = Contact::load_from_db(context, contact_id as u32)
dc_contact_load_from_db(contact, &context.sql, contact_id as u32); .map(|contact| contact.get_name_n_addr())
.unwrap_or_default();
p = dc_contact_get_name_n_addr(contact);
ret += &format!(" by {}", as_str(p));
free(p as *mut libc::c_void);
dc_contact_unref(contact);
ret += &format!(" by {}", name);
ret += "\n"; ret += "\n";
} }
Ok(()) Ok(())
@@ -178,17 +173,9 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
} }
free(p as *mut libc::c_void); free(p as *mut libc::c_void);
if (*msg).type_0 != DC_MSG_TEXT { if (*msg).type_0 != Viewtype::Text {
ret += "Type: "; ret += "Type: ";
match (*msg).type_0 { ret += &format!("{}", (*msg).type_0);
DC_MSG_AUDIO => ret += "Audio",
DC_MSG_FILE => ret += "File",
DC_MSG_GIF => ret += "GIF",
DC_MSG_IMAGE => ret += "Image",
DC_MSG_VIDEO => ret += "Video",
DC_MSG_VOICE => ret += "Voice",
_ => ret += &format!("{}", (*msg).type_0),
}
ret += "\n"; ret += "\n";
p = dc_msg_get_filemime(msg); p = dc_msg_get_filemime(msg);
ret += &format!("Mimetype: {}\n", as_str(p)); ret += &format!("Mimetype: {}\n", as_str(p));
@@ -218,12 +205,11 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
} }
dc_msg_unref(msg); dc_msg_unref(msg);
dc_contact_unref(contact_from); ret.strdup()
to_cstring(ret)
} }
pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a> { pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a> {
dc_msg_new(context, 0i32) dc_msg_new(context, Viewtype::Unknown)
} }
/* * /* *
@@ -236,7 +222,7 @@ pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a>
// to check if a mail was sent, use dc_msg_is_sent() // 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_msg_get_text()
// approx. max. length returned by dc_get_msg_info() // approx. max. length returned by dc_get_msg_info()
pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: libc::c_int) -> *mut dc_msg_t<'a> { pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut dc_msg_t<'a> {
let msg = dc_msg_t { let msg = dc_msg_t {
magic: 0x11561156, magic: 0x11561156,
id: 0, id: 0,
@@ -250,7 +236,7 @@ pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: libc::c_int) -> *mu
timestamp_sort: 0, timestamp_sort: 0,
timestamp_sent: 0, timestamp_sent: 0,
timestamp_rcvd: 0, timestamp_rcvd: 0,
text: std::ptr::null_mut(), text: None,
context, context,
rfc724_mid: std::ptr::null_mut(), rfc724_mid: std::ptr::null_mut(),
in_reply_to: std::ptr::null_mut(), in_reply_to: std::ptr::null_mut(),
@@ -279,8 +265,6 @@ pub unsafe fn dc_msg_empty(mut msg: *mut dc_msg_t) {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return; return;
} }
free((*msg).text as *mut libc::c_void);
(*msg).text = 0 as *mut libc::c_char;
free((*msg).rfc724_mid as *mut libc::c_void); free((*msg).rfc724_mid as *mut libc::c_void);
(*msg).rfc724_mid = 0 as *mut libc::c_char; (*msg).rfc724_mid = 0 as *mut libc::c_char;
free((*msg).in_reply_to as *mut libc::c_void); free((*msg).in_reply_to as *mut libc::c_void);
@@ -297,18 +281,17 @@ pub unsafe fn dc_msg_get_filemime(msg: *const dc_msg_t) -> *mut libc::c_char {
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) { if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
match (*msg).param.get(Param::MimeType) { match (*msg).param.get(Param::MimeType) {
Some(m) => { Some(m) => {
ret = to_cstring(m); ret = m.strdup();
} }
None => { None => {
if let Some(file) = (*msg).param.get(Param::File) { if let Some(file) = (*msg).param.get(Param::File) {
let file_c = to_cstring(file); let file_c = CString::yolo(file);
dc_msg_guess_msgtype_from_suffix(file_c, 0 as *mut libc::c_int, &mut ret); dc_msg_guess_msgtype_from_suffix(file_c.as_ptr(), 0 as *mut Viewtype, &mut ret);
if ret.is_null() { if ret.is_null() {
ret = dc_strdup( ret = dc_strdup(
b"application/octet-stream\x00" as *const u8 as *const libc::c_char, b"application/octet-stream\x00" as *const u8 as *const libc::c_char,
) )
} }
free(file_c as *mut _);
} }
} }
} }
@@ -324,11 +307,11 @@ pub unsafe fn dc_msg_get_filemime(msg: *const dc_msg_t) -> *mut libc::c_char {
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub unsafe fn dc_msg_guess_msgtype_from_suffix( pub unsafe fn dc_msg_guess_msgtype_from_suffix(
pathNfilename: *const libc::c_char, pathNfilename: *const libc::c_char,
mut ret_msgtype: *mut libc::c_int, mut ret_msgtype: *mut Viewtype,
mut ret_mime: *mut *mut libc::c_char, mut ret_mime: *mut *mut libc::c_char,
) { ) {
let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char; let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char;
let mut dummy_msgtype: libc::c_int = 0; let mut dummy_msgtype = Viewtype::Unknown;
let mut dummy_buf: *mut libc::c_char = 0 as *mut libc::c_char; let mut dummy_buf: *mut libc::c_char = 0 as *mut libc::c_char;
if !pathNfilename.is_null() { if !pathNfilename.is_null() {
if ret_msgtype.is_null() { if ret_msgtype.is_null() {
@@ -337,37 +320,37 @@ pub unsafe fn dc_msg_guess_msgtype_from_suffix(
if ret_mime.is_null() { if ret_mime.is_null() {
ret_mime = &mut dummy_buf ret_mime = &mut dummy_buf
} }
*ret_msgtype = 0; *ret_msgtype = Viewtype::Unknown;
*ret_mime = 0 as *mut libc::c_char; *ret_mime = 0 as *mut libc::c_char;
suffix = dc_get_filesuffix_lc(pathNfilename); suffix = dc_get_filesuffix_lc(pathNfilename);
if !suffix.is_null() { if !suffix.is_null() {
if strcmp(suffix, b"mp3\x00" as *const u8 as *const libc::c_char) == 0i32 { if strcmp(suffix, b"mp3\x00" as *const u8 as *const libc::c_char) == 0i32 {
*ret_msgtype = DC_MSG_AUDIO; *ret_msgtype = Viewtype::Audio;
*ret_mime = dc_strdup(b"audio/mpeg\x00" as *const u8 as *const libc::c_char) *ret_mime = dc_strdup(b"audio/mpeg\x00" as *const u8 as *const libc::c_char)
} else if strcmp(suffix, b"aac\x00" as *const u8 as *const libc::c_char) == 0i32 { } else if strcmp(suffix, b"aac\x00" as *const u8 as *const libc::c_char) == 0i32 {
*ret_msgtype = DC_MSG_AUDIO; *ret_msgtype = Viewtype::Audio;
*ret_mime = dc_strdup(b"audio/aac\x00" as *const u8 as *const libc::c_char) *ret_mime = dc_strdup(b"audio/aac\x00" as *const u8 as *const libc::c_char)
} else if strcmp(suffix, b"mp4\x00" as *const u8 as *const libc::c_char) == 0i32 { } else if strcmp(suffix, b"mp4\x00" as *const u8 as *const libc::c_char) == 0i32 {
*ret_msgtype = DC_MSG_VIDEO; *ret_msgtype = Viewtype::Video;
*ret_mime = dc_strdup(b"video/mp4\x00" as *const u8 as *const libc::c_char) *ret_mime = dc_strdup(b"video/mp4\x00" as *const u8 as *const libc::c_char)
} else if strcmp(suffix, b"jpg\x00" as *const u8 as *const libc::c_char) == 0i32 } else if strcmp(suffix, b"jpg\x00" as *const u8 as *const libc::c_char) == 0i32
|| strcmp(suffix, b"jpeg\x00" as *const u8 as *const libc::c_char) == 0i32 || strcmp(suffix, b"jpeg\x00" as *const u8 as *const libc::c_char) == 0i32
{ {
*ret_msgtype = DC_MSG_IMAGE; *ret_msgtype = Viewtype::Image;
*ret_mime = dc_strdup(b"image/jpeg\x00" as *const u8 as *const libc::c_char) *ret_mime = dc_strdup(b"image/jpeg\x00" as *const u8 as *const libc::c_char)
} else if strcmp(suffix, b"png\x00" as *const u8 as *const libc::c_char) == 0i32 { } else if strcmp(suffix, b"png\x00" as *const u8 as *const libc::c_char) == 0i32 {
*ret_msgtype = DC_MSG_IMAGE; *ret_msgtype = Viewtype::Image;
*ret_mime = dc_strdup(b"image/png\x00" as *const u8 as *const libc::c_char) *ret_mime = dc_strdup(b"image/png\x00" as *const u8 as *const libc::c_char)
} else if strcmp(suffix, b"webp\x00" as *const u8 as *const libc::c_char) == 0i32 { } else if strcmp(suffix, b"webp\x00" as *const u8 as *const libc::c_char) == 0i32 {
*ret_msgtype = DC_MSG_IMAGE; *ret_msgtype = Viewtype::Image;
*ret_mime = dc_strdup(b"image/webp\x00" as *const u8 as *const libc::c_char) *ret_mime = dc_strdup(b"image/webp\x00" as *const u8 as *const libc::c_char)
} else if strcmp(suffix, b"gif\x00" as *const u8 as *const libc::c_char) == 0i32 { } else if strcmp(suffix, b"gif\x00" as *const u8 as *const libc::c_char) == 0i32 {
*ret_msgtype = DC_MSG_GIF; *ret_msgtype = Viewtype::Gif;
*ret_mime = dc_strdup(b"image/gif\x00" as *const u8 as *const libc::c_char) *ret_mime = dc_strdup(b"image/gif\x00" as *const u8 as *const libc::c_char)
} else if strcmp(suffix, b"vcf\x00" as *const u8 as *const libc::c_char) == 0i32 } else if strcmp(suffix, b"vcf\x00" as *const u8 as *const libc::c_char) == 0i32
|| strcmp(suffix, b"vcard\x00" as *const u8 as *const libc::c_char) == 0i32 || strcmp(suffix, b"vcard\x00" as *const u8 as *const libc::c_char) == 0i32
{ {
*ret_msgtype = DC_MSG_FILE; *ret_msgtype = Viewtype::File;
*ret_mime = dc_strdup(b"text/vcard\x00" as *const u8 as *const libc::c_char) *ret_mime = dc_strdup(b"text/vcard\x00" as *const u8 as *const libc::c_char)
} }
} }
@@ -381,9 +364,8 @@ pub unsafe fn dc_msg_get_file(msg: *const dc_msg_t) -> *mut libc::c_char {
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) { if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
if let Some(file_rel) = (*msg).param.get(Param::File) { if let Some(file_rel) = (*msg).param.get(Param::File) {
let file_rel_c = to_cstring(file_rel); let file_rel_c = CString::yolo(file_rel);
file_abs = dc_get_abs_path((*msg).context, file_rel_c); file_abs = dc_get_abs_path((*msg).context, file_rel_c.as_ptr());
free(file_rel_c as *mut _);
} }
} }
if !file_abs.is_null() { if !file_abs.is_null() {
@@ -473,12 +455,12 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
dc_msg_empty(msg); dc_msg_empty(msg);
(*msg).id = row.get::<_, i32>(0)? as u32; (*msg).id = row.get::<_, i32>(0)? as u32;
(*msg).rfc724_mid = to_cstring(row.get::<_, String>(1)?); (*msg).rfc724_mid = row.get::<_, String>(1)?.strdup();
(*msg).in_reply_to = match row.get::<_, Option<String>>(2)? { (*msg).in_reply_to = match row.get::<_, Option<String>>(2)? {
Some(s) => to_cstring(s), Some(s) => s.strdup(),
None => std::ptr::null_mut(), None => std::ptr::null_mut(),
}; };
(*msg).server_folder = to_cstring(row.get::<_, String>(3)?); (*msg).server_folder = row.get::<_, String>(3)?.strdup();
(*msg).server_uid = row.get(4)?; (*msg).server_uid = row.get(4)?;
(*msg).move_state = row.get(5)?; (*msg).move_state = row.get(5)?;
(*msg).chat_id = row.get(6)?; (*msg).chat_id = row.get(6)?;
@@ -490,19 +472,25 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
(*msg).type_0 = row.get(12)?; (*msg).type_0 = row.get(12)?;
(*msg).state = row.get(13)?; (*msg).state = row.get(13)?;
(*msg).is_dc_message = row.get(14)?; (*msg).is_dc_message = row.get(14)?;
(*msg).text = to_cstring(row.get::<_, String>(15).unwrap_or_default()); (*msg).text = row.get::<_, Option<String>>(15)?;
(*msg).param = row.get::<_, String>(16)?.parse().unwrap_or_default(); (*msg).param = row.get::<_, String>(16)?.parse().unwrap_or_default();
(*msg).starred = row.get(17)?; (*msg).starred = row.get(17)?;
(*msg).hidden = row.get(18)?; (*msg).hidden = row.get(18)?;
(*msg).location_id = row.get(19)?; (*msg).location_id = row.get(19)?;
(*msg).chat_blocked = row.get::<_, Option<i32>>(20)?.unwrap_or_default(); (*msg).chat_blocked = row.get::<_, Option<i32>>(20)?.unwrap_or_default();
if (*msg).chat_blocked == 2 { if (*msg).chat_blocked == 2 {
dc_truncate_n_unwrap_str((*msg).text, 256, 0); if let Some(ref text) = (*msg).text {
} let ptr = text.strdup();
}
dc_truncate_n_unwrap_str(ptr, 256, 0);
(*msg).text = Some(to_string(ptr));
free(ptr.cast());
}
};
Ok(()) Ok(())
} }
); });
res.is_ok() res.is_ok()
} }
@@ -516,10 +504,8 @@ pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: uint32_t) -> *mut l
); );
if let Some(headers) = headers { if let Some(headers) = headers {
let h = to_cstring(headers); let h = CString::yolo(headers);
let res = dc_strdup_keep_null(h); dc_strdup_keep_null(h.as_ptr())
free(h as *mut _);
res
} else { } else {
std::ptr::null_mut() std::ptr::null_mut()
} }
@@ -682,9 +668,9 @@ pub unsafe fn dc_msg_get_chat_id(msg: *const dc_msg_t) -> uint32_t {
}; };
} }
pub unsafe fn dc_msg_get_viewtype(msg: *const dc_msg_t) -> libc::c_int { pub unsafe fn dc_msg_get_viewtype(msg: *const dc_msg_t) -> Viewtype {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0i32; return Viewtype::Unknown;
} }
(*msg).type_0 (*msg).type_0
@@ -718,9 +704,11 @@ pub unsafe fn dc_msg_get_text(msg: *const dc_msg_t) -> *mut libc::c_char {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return dc_strdup(0 as *const libc::c_char); return dc_strdup(0 as *const libc::c_char);
} }
if let Some(ref text) = (*msg).text {
let res = dc_truncate_str(as_str((*msg).text), 30000); dc_truncate_str(text, 30000).strdup()
to_cstring(res) } else {
ptr::null_mut()
}
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@@ -729,9 +717,8 @@ pub unsafe fn dc_msg_get_filename(msg: *const dc_msg_t) -> *mut libc::c_char {
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) { if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
if let Some(file) = (*msg).param.get(Param::File) { if let Some(file) = (*msg).param.get(Param::File) {
let file_c = to_cstring(file); let file_c = CString::yolo(file);
ret = dc_get_filename(file_c); ret = dc_get_filename(file_c.as_ptr());
free(file_c as *mut _);
} }
} }
if !ret.is_null() { if !ret.is_null() {
@@ -746,9 +733,8 @@ pub unsafe fn dc_msg_get_filebytes(msg: *const dc_msg_t) -> uint64_t {
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) { if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
if let Some(file) = (*msg).param.get(Param::File) { if let Some(file) = (*msg).param.get(Param::File) {
let file_c = to_cstring(file); let file_c = CString::yolo(file);
ret = dc_get_filebytes((*msg).context, file_c); ret = dc_get_filebytes((*msg).context, file_c.as_ptr());
free(file_c as *mut _);
} }
} }
@@ -802,8 +788,8 @@ pub unsafe fn dc_msg_get_summary<'a>(
) -> *mut dc_lot_t { ) -> *mut dc_lot_t {
let mut success = true; let mut success = true;
let ret: *mut dc_lot_t = dc_lot_new(); let ret: *mut dc_lot_t = dc_lot_new();
let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t;
let mut chat_to_delete: *mut Chat = 0 as *mut Chat; let mut chat_to_delete: *mut Chat = 0 as *mut Chat;
if !(msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint) { if !(msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint) {
if chat.is_null() { if chat.is_null() {
chat_to_delete = dc_get_chat((*msg).context, (*msg).chat_id); chat_to_delete = dc_get_chat((*msg).context, (*msg).chat_id);
@@ -816,15 +802,18 @@ pub unsafe fn dc_msg_get_summary<'a>(
success = false; success = false;
} }
if success == false { if success == false {
if (*msg).from_id != 1 as libc::c_uint let contact = if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint
&& ((*chat).type_0 == 120 || (*chat).type_0 == 130) && ((*chat).type_0 == 120 || (*chat).type_0 == 130)
{ {
contact = dc_get_contact((*chat).context, (*msg).from_id) Contact::get_by_id((*chat).context, (*msg).from_id).ok()
} } else {
dc_lot_fill(ret, msg, chat, contact, (*msg).context); None
};
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
} }
} }
dc_contact_unref(contact);
dc_chat_unref(chat_to_delete); dc_chat_unref(chat_to_delete);
ret ret
@@ -838,9 +827,15 @@ pub unsafe fn dc_msg_get_summarytext(
return dc_strdup(0 as *const libc::c_char); return dc_strdup(0 as *const libc::c_char);
} }
let msgtext_c = (*msg)
.text
.as_ref()
.map(|s| CString::yolo(String::as_str(s)));
let msgtext_ptr = msgtext_c.map_or(ptr::null(), |s| s.as_ptr());
dc_msg_get_summarytext_by_raw( dc_msg_get_summarytext_by_raw(
(*msg).type_0, (*msg).type_0,
(*msg).text, msgtext_ptr,
&mut (*msg).param, &mut (*msg).param,
approx_characters, approx_characters,
(*msg).context, (*msg).context,
@@ -850,7 +845,7 @@ pub unsafe fn dc_msg_get_summarytext(
/* the returned value must be free()'d */ /* the returned value must be free()'d */
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub unsafe fn dc_msg_get_summarytext_by_raw( pub unsafe fn dc_msg_get_summarytext_by_raw(
type_0: libc::c_int, type_0: Viewtype,
text: *const libc::c_char, text: *const libc::c_char,
param: &mut Params, param: &mut Params,
approx_characters: libc::c_int, approx_characters: libc::c_int,
@@ -863,20 +858,23 @@ pub unsafe fn dc_msg_get_summarytext_by_raw(
let mut value: *mut libc::c_char = 0 as *mut libc::c_char; let mut value: *mut libc::c_char = 0 as *mut libc::c_char;
let mut append_text: libc::c_int = 1i32; let mut append_text: libc::c_int = 1i32;
match type_0 { match type_0 {
20 => prefix = to_cstring(context.stock_str(StockMessage::Image)), Viewtype::Image => prefix = context.stock_str(StockMessage::Image).strdup(),
21 => prefix = to_cstring(context.stock_str(StockMessage::Gif)), Viewtype::Gif => prefix = context.stock_str(StockMessage::Gif).strdup(),
50 => prefix = to_cstring(context.stock_str(StockMessage::Video)), Viewtype::Video => prefix = context.stock_str(StockMessage::Video).strdup(),
41 => prefix = to_cstring(context.stock_str(StockMessage::VoiceMessage)), Viewtype::Voice => prefix = context.stock_str(StockMessage::VoiceMessage).strdup(),
40 | 60 => { Viewtype::Audio | Viewtype::File => {
if param.get_int(Param::Cmd) == Some(6) { if param.get_int(Param::Cmd) == Some(6) {
prefix = to_cstring(context.stock_str(StockMessage::AcSetupMsgSubject)); prefix = context.stock_str(StockMessage::AcSetupMsgSubject).strdup();
append_text = 0i32 append_text = 0i32
} else { } else {
pathNfilename = to_cstring(param.get(Param::File).unwrap_or_else(|| "ErrFilename")); pathNfilename = param
.get(Param::File)
.unwrap_or_else(|| "ErrFilename")
.strdup();
value = dc_get_filename(pathNfilename); value = dc_get_filename(pathNfilename);
let label = CString::new( let label = CString::new(
context context
.stock_str(if type_0 == DC_MSG_AUDIO { .stock_str(if type_0 == Viewtype::Audio {
StockMessage::Audio StockMessage::Audio
} else { } else {
StockMessage::File StockMessage::File
@@ -893,7 +891,7 @@ pub unsafe fn dc_msg_get_summarytext_by_raw(
} }
_ => { _ => {
if param.get_int(Param::Cmd) == Some(9) { if param.get_int(Param::Cmd) == Some(9) {
prefix = to_cstring(context.stock_str(StockMessage::Location)); prefix = context.stock_str(StockMessage::Location).strdup();
append_text = 0; append_text = 0;
} }
} }
@@ -946,12 +944,11 @@ pub unsafe fn dc_msg_is_sent(msg: *const dc_msg_t) -> libc::c_int {
} }
} }
// TODO should return bool /rtn pub unsafe fn dc_msg_is_starred(msg: *const dc_msg_t) -> bool {
pub unsafe fn dc_msg_is_starred(msg: *const dc_msg_t) -> libc::c_int {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0i32; return false;
} }
return if 0 != (*msg).starred { 1i32 } else { 0i32 }; 0 != (*msg).starred
} }
// TODO should return bool /rtn // TODO should return bool /rtn
@@ -998,7 +995,7 @@ pub unsafe fn dc_msg_is_increation(msg: *const dc_msg_t) -> libc::c_int {
pub unsafe fn dc_msg_is_setupmessage(msg: *const dc_msg_t) -> bool { pub unsafe fn dc_msg_is_setupmessage(msg: *const dc_msg_t) -> bool {
if msg.is_null() if msg.is_null()
|| (*msg).magic != 0x11561156i32 as libc::c_uint || (*msg).magic != 0x11561156i32 as libc::c_uint
|| (*msg).type_0 != DC_MSG_FILE as libc::c_int || (*msg).type_0 != Viewtype::File
{ {
return false; return false;
} }
@@ -1028,19 +1025,17 @@ pub unsafe fn dc_msg_get_setupcodebegin(msg: *const dc_msg_t) -> *mut libc::c_ch
|| buf.is_null() || buf.is_null()
|| buf_bytes <= 0) || buf_bytes <= 0)
{ {
if !(0 if dc_split_armored_data(
== dc_split_armored_data( buf,
buf, &mut buf_headerline,
&mut buf_headerline, &mut buf_setupcodebegin,
&mut buf_setupcodebegin, 0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char, 0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char, ) && strcmp(
) buf_headerline,
|| strcmp( b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
buf_headerline, ) == 0
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, && !buf_setupcodebegin.is_null()
) != 0i32
|| buf_setupcodebegin.is_null())
{ {
ret = dc_strdup(buf_setupcodebegin) ret = dc_strdup(buf_setupcodebegin)
} }
@@ -1060,8 +1055,11 @@ pub unsafe fn dc_msg_set_text(mut msg: *mut dc_msg_t, text: *const libc::c_char)
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return; return;
} }
free((*msg).text as *mut libc::c_void); (*msg).text = if text.is_null() {
(*msg).text = dc_strdup(text); None
} else {
Some(to_string(text))
};
} }
pub unsafe fn dc_msg_set_file( pub unsafe fn dc_msg_set_file(
@@ -1395,7 +1393,7 @@ pub fn dc_rfc724_mid_exists(
&[as_str(rfc724_mid)], &[as_str(rfc724_mid)],
|row| { |row| {
if !ret_server_folder.is_null() { if !ret_server_folder.is_null() {
unsafe { *ret_server_folder = to_cstring(row.get::<_, String>(0)?) }; unsafe { *ret_server_folder = row.get::<_, String>(0)?.strdup() };
} }
if !ret_server_uid.is_null() { if !ret_server_uid.is_null() {
unsafe { *ret_server_uid = row.get(1)? }; unsafe { *ret_server_uid = row.get(1)? };
@@ -1437,12 +1435,13 @@ pub fn dc_update_server_uid(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::test_utils as test;
use std::ffi::CStr; use std::ffi::CStr;
#[test] #[test]
fn test_dc_msg_guess_msgtype_from_suffix() { fn test_dc_msg_guess_msgtype_from_suffix() {
unsafe { unsafe {
let mut type_0: libc::c_int = 0; let mut type_0 = Viewtype::Unknown;
let mut mime_0: *mut libc::c_char = 0 as *mut libc::c_char; let mut mime_0: *mut libc::c_char = 0 as *mut libc::c_char;
dc_msg_guess_msgtype_from_suffix( dc_msg_guess_msgtype_from_suffix(
@@ -1450,7 +1449,7 @@ mod tests {
&mut type_0, &mut type_0,
&mut mime_0, &mut mime_0,
); );
assert_eq!(type_0, DC_MSG_AUDIO as libc::c_int); assert_eq!(type_0, Viewtype::Audio);
assert_eq!(as_str(mime_0 as *const libc::c_char), "audio/mpeg"); assert_eq!(as_str(mime_0 as *const libc::c_char), "audio/mpeg");
free(mime_0 as *mut libc::c_void); free(mime_0 as *mut libc::c_void);
@@ -1459,7 +1458,7 @@ mod tests {
&mut type_0, &mut type_0,
&mut mime_0, &mut mime_0,
); );
assert_eq!(type_0, DC_MSG_AUDIO as libc::c_int); assert_eq!(type_0, Viewtype::Audio);
assert_eq!(as_str(mime_0 as *const libc::c_char), "audio/aac"); assert_eq!(as_str(mime_0 as *const libc::c_char), "audio/aac");
free(mime_0 as *mut libc::c_void); free(mime_0 as *mut libc::c_void);
@@ -1468,7 +1467,7 @@ mod tests {
&mut type_0, &mut type_0,
&mut mime_0, &mut mime_0,
); );
assert_eq!(type_0, DC_MSG_VIDEO as libc::c_int); assert_eq!(type_0, Viewtype::Video);
assert_eq!(as_str(mime_0 as *const libc::c_char), "video/mp4"); assert_eq!(as_str(mime_0 as *const libc::c_char), "video/mp4");
free(mime_0 as *mut libc::c_void); free(mime_0 as *mut libc::c_void);
@@ -1477,7 +1476,7 @@ mod tests {
&mut type_0, &mut type_0,
&mut mime_0, &mut mime_0,
); );
assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int); assert_eq!(type_0, Viewtype::Image);
assert_eq!( assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char) CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str() .to_str()
@@ -1491,7 +1490,7 @@ mod tests {
&mut type_0, &mut type_0,
&mut mime_0, &mut mime_0,
); );
assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int); assert_eq!(type_0, Viewtype::Image);
assert_eq!( assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char) CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str() .to_str()
@@ -1505,7 +1504,7 @@ mod tests {
&mut type_0, &mut type_0,
&mut mime_0, &mut mime_0,
); );
assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int); assert_eq!(type_0, Viewtype::Image);
assert_eq!( assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char) CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str() .to_str()
@@ -1519,7 +1518,7 @@ mod tests {
&mut type_0, &mut type_0,
&mut mime_0, &mut mime_0,
); );
assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int); assert_eq!(type_0, Viewtype::Image);
assert_eq!( assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char) CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str() .to_str()
@@ -1533,7 +1532,7 @@ mod tests {
&mut type_0, &mut type_0,
&mut mime_0, &mut mime_0,
); );
assert_eq!(type_0, DC_MSG_GIF as libc::c_int); assert_eq!(type_0, Viewtype::Gif);
assert_eq!( assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char) CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str() .to_str()
@@ -1547,7 +1546,7 @@ mod tests {
&mut type_0, &mut type_0,
&mut mime_0, &mut mime_0,
); );
assert_eq!(type_0, DC_MSG_FILE as libc::c_int); assert_eq!(type_0, Viewtype::File);
assert_eq!( assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char) CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str() .to_str()
@@ -1557,4 +1556,32 @@ mod tests {
free(mime_0 as *mut libc::c_void); free(mime_0 as *mut libc::c_void);
} }
} }
#[test]
pub fn test_prepare_message_and_send() {
use crate::config::Config;
unsafe {
let d = test::dummy_context();
let ctx = &d.ctx;
let contact =
Contact::create(ctx, "", "dest@example.com").expect("failed to create contact");
let res = ctx.set_config(Config::ConfiguredAddr, Some("self@example.com"));
assert!(res.is_ok());
let chat = dc_create_chat_by_contact_id(ctx, contact);
assert!(chat != 0);
let msg = dc_msg_new(ctx, Viewtype::Text);
assert!(!msg.is_null());
let msg_id = dc_prepare_msg(ctx, chat, msg);
assert!(msg_id != 0);
let msg2 = dc_get_msg(ctx, msg_id);
assert!(!msg2.is_null());
}
}
} }

View File

@@ -1,8 +1,8 @@
use percent_encoding::percent_decode_str; use percent_encoding::percent_decode_str;
use crate::contact::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_lot::*; use crate::dc_lot::*;
use crate::dc_strencode::*; use crate::dc_strencode::*;
use crate::dc_tools::*; use crate::dc_tools::*;
@@ -59,34 +59,33 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
let param: Params = as_str(fragment).parse().expect("invalid params"); let param: Params = as_str(fragment).parse().expect("invalid params");
addr = param addr = param
.get(Param::Forwarded) .get(Param::Forwarded)
.map(|s| to_cstring(s)) .map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut()); .unwrap_or_else(|| std::ptr::null_mut());
if !addr.is_null() { if !addr.is_null() {
if let Some(ref name_enc) = param.get(Param::SetLongitude) { if let Some(ref name_enc) = param.get(Param::SetLongitude) {
let name_r = percent_decode_str(name_enc) let name_r = percent_decode_str(name_enc)
.decode_utf8() .decode_utf8()
.expect("invalid name"); .expect("invalid name");
name = to_cstring(name_r); name = normalize_name(name_r).strdup();
dc_normalize_name(name);
} }
invitenumber = param invitenumber = param
.get(Param::ProfileImage) .get(Param::ProfileImage)
.map(|s| to_cstring(s)) .map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut()); .unwrap_or_else(|| std::ptr::null_mut());
auth = param auth = param
.get(Param::Auth) .get(Param::Auth)
.map(|s| to_cstring(s)) .map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut()); .unwrap_or_else(|| std::ptr::null_mut());
grpid = param grpid = param
.get(Param::GroupId) .get(Param::GroupId)
.map(|s| to_cstring(s)) .map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut()); .unwrap_or_else(|| std::ptr::null_mut());
if !grpid.is_null() { if !grpid.is_null() {
if let Some(grpname_enc) = param.get(Param::GroupName) { if let Some(grpname_enc) = param.get(Param::GroupName) {
let grpname_r = percent_decode_str(grpname_enc) let grpname_r = percent_decode_str(grpname_enc)
.decode_utf8() .decode_utf8()
.expect("invalid groupname"); .expect("invalid groupname");
grpname = to_cstring(grpname_r); grpname = grpname_r.strdup();
} }
} }
} }
@@ -152,11 +151,8 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
strlen(b"BEGIN:VCARD\x00" as *const u8 as *const libc::c_char), strlen(b"BEGIN:VCARD\x00" as *const u8 as *const libc::c_char),
) == 0i32 ) == 0i32
{ {
let lines: *mut carray = dc_split_into_lines(qr); let lines = dc_split_into_lines(qr);
let mut i: libc::c_int = 0i32; for &key in &lines {
while (i as libc::c_uint) < carray_count(lines) {
let key: *mut libc::c_char =
carray_get(lines, i as libc::c_uint) as *mut libc::c_char;
dc_trim(key); dc_trim(key);
let mut value: *mut libc::c_char = strchr(key, ':' as i32); let mut value: *mut libc::c_char = strchr(key, ':' as i32);
if !value.is_null() { if !value.is_null() {
@@ -189,10 +185,9 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
b";\x00" as *const u8 as *const libc::c_char, b";\x00" as *const u8 as *const libc::c_char,
b",\x00" as *const u8 as *const libc::c_char, b",\x00" as *const u8 as *const libc::c_char,
); );
dc_normalize_name(name); name = normalize_name(as_str(name)).strdup();
} }
} }
i += 1
} }
dc_free_splitted_lines(lines); dc_free_splitted_lines(lines);
} }
@@ -208,10 +203,10 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
let mut temp: *mut libc::c_char = dc_urldecode(addr); let mut temp: *mut libc::c_char = dc_urldecode(addr);
free(addr as *mut libc::c_void); free(addr as *mut libc::c_void);
addr = temp; addr = temp;
temp = dc_addr_normalize(addr); temp = addr_normalize(as_str(addr)).strdup();
free(addr as *mut libc::c_void); free(addr as *mut libc::c_void);
addr = temp; addr = temp;
if !dc_may_be_valid_addr(addr) { if !may_be_valid_addr(as_str(addr)) {
(*qr_parsed).state = 400i32; (*qr_parsed).state = 400i32;
(*qr_parsed).text1 = dc_strdup( (*qr_parsed).text1 = dc_strdup(
b"Bad e-mail address.\x00" as *const u8 as *const libc::c_char, b"Bad e-mail address.\x00" as *const u8 as *const libc::c_char,
@@ -252,19 +247,19 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
if addr.is_null() || invitenumber.is_null() || auth.is_null() { if addr.is_null() || invitenumber.is_null() || auth.is_null() {
if let Some(peerstate) = peerstate { if let Some(peerstate) = peerstate {
(*qr_parsed).state = 210i32; (*qr_parsed).state = 210i32;
let addr_ptr = if let Some(ref addr) = peerstate.addr { let addr = peerstate
to_cstring(addr) .addr
} else { .as_ref()
std::ptr::null() .map(|s| s.as_str())
}; .unwrap_or_else(|| "");
(*qr_parsed).id = dc_add_or_lookup_contact( (*qr_parsed).id = Contact::add_or_lookup(
context, context,
0 as *const libc::c_char, "",
addr_ptr, addr,
0x80i32, Origin::UnhandledQrScan,
0 as *mut libc::c_int, )
); .map(|(id, _)| id)
free(addr_ptr as *mut _); .unwrap_or_default();
dc_create_or_lookup_nchat_by_contact_id( dc_create_or_lookup_nchat_by_contact_id(
context, context,
(*qr_parsed).id, (*qr_parsed).id,
@@ -290,26 +285,28 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
} else { } else {
(*qr_parsed).state = 200i32 (*qr_parsed).state = 200i32
} }
(*qr_parsed).id = dc_add_or_lookup_contact( (*qr_parsed).id = Contact::add_or_lookup(
context, context,
name, as_str(name),
addr, as_str(addr),
0x80i32, Origin::UnhandledQrScan,
0 as *mut libc::c_int, )
); .map(|(id, _)| id)
.unwrap_or_default();
(*qr_parsed).fingerprint = dc_strdup(fingerprint); (*qr_parsed).fingerprint = dc_strdup(fingerprint);
(*qr_parsed).invitenumber = dc_strdup(invitenumber); (*qr_parsed).invitenumber = dc_strdup(invitenumber);
(*qr_parsed).auth = dc_strdup(auth) (*qr_parsed).auth = dc_strdup(auth)
} }
} else if !addr.is_null() { } else if !addr.is_null() {
(*qr_parsed).state = 320i32; (*qr_parsed).state = 320i32;
(*qr_parsed).id = dc_add_or_lookup_contact( (*qr_parsed).id = Contact::add_or_lookup(
context, context,
name, as_str(name),
addr, as_str(addr),
0x80i32, Origin::UnhandledQrScan,
0 as *mut libc::c_int,
) )
.map(|(id, _)| id)
.unwrap_or_default();
} else if strstr( } else if strstr(
qr, qr,
b"http://\x00" as *const u8 as *const libc::c_char, b"http://\x00" as *const u8 as *const libc::c_char,

View File

@@ -8,10 +8,10 @@ use mmime::other::*;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use crate::constants::*; use crate::constants::*;
use crate::contact::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_array::*; use crate::dc_array::*;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_job::*; use crate::dc_job::*;
use crate::dc_location::*; use crate::dc_location::*;
use crate::dc_mimeparser::*; use crate::dc_mimeparser::*;
@@ -38,7 +38,7 @@ pub unsafe fn dc_receive_imf(
let mut current_block: u64; let mut current_block: u64;
/* the function returns the number of created messages in the database */ /* the function returns the number of created messages in the database */
let mut incoming: libc::c_int = 1; let mut incoming: libc::c_int = 1;
let mut incoming_origin: libc::c_int = 0; let mut incoming_origin = Origin::Unknown;
let mut to_self: libc::c_int = 0; let mut to_self: libc::c_int = 0;
let mut from_id: uint32_t = 0 as uint32_t; let mut from_id: uint32_t = 0 as uint32_t;
let mut from_id_blocked: libc::c_int = 0; let mut from_id_blocked: libc::c_int = 0;
@@ -51,8 +51,6 @@ pub unsafe fn dc_receive_imf(
let mut add_delete_job: libc::c_int = 0; let mut add_delete_job: libc::c_int = 0;
let mut insert_msg_id: uint32_t = 0 as uint32_t; let mut insert_msg_id: uint32_t = 0 as uint32_t;
let mut i: size_t;
let mut icnt: size_t;
/* Message-ID from the header */ /* Message-ID from the header */
let mut rfc724_mid = 0 as *mut libc::c_char; let mut rfc724_mid = 0 as *mut libc::c_char;
let mut sort_timestamp = 0; let mut sort_timestamp = 0;
@@ -105,7 +103,7 @@ pub unsafe fn dc_receive_imf(
dc_add_or_lookup_contacts_by_mailbox_list( dc_add_or_lookup_contacts_by_mailbox_list(
context, context,
(*fld_from).frm_mb_list, (*fld_from).frm_mb_list,
0x10, Origin::IncomingUnknownFrom,
from_list, from_list,
&mut check_self, &mut check_self,
); );
@@ -116,7 +114,8 @@ pub unsafe fn dc_receive_imf(
} }
} else if dc_array_get_cnt(from_list) >= 1 { } else if dc_array_get_cnt(from_list) >= 1 {
from_id = dc_array_get_id(from_list, 0 as size_t); from_id = dc_array_get_id(from_list, 0 as size_t);
incoming_origin = dc_get_contact_origin(context, from_id, &mut from_id_blocked) incoming_origin =
Contact::get_origin_by_id(context, from_id, &mut from_id_blocked)
} }
dc_array_unref(from_list); dc_array_unref(from_list);
} }
@@ -129,18 +128,18 @@ pub unsafe fn dc_receive_imf(
context, context,
(*fld_to).to_addr_list, (*fld_to).to_addr_list,
if 0 == incoming { if 0 == incoming {
0x4000 Origin::OutgoingTo
} else if incoming_origin >= 0x100 { } else if incoming_origin.is_verified() {
0x400 Origin::IncomingTo
} else { } else {
0x40 Origin::IncomingUnknownTo
}, },
to_ids, to_ids,
&mut to_self, &mut to_self,
); );
} }
} }
if !dc_mimeparser_get_last_nonmeta(&mime_parser).is_null() { if dc_mimeparser_get_last_nonmeta(&mut mime_parser).is_some() {
field = dc_mimeparser_lookup_field(&mime_parser, "Cc"); field = dc_mimeparser_lookup_field(&mime_parser, "Cc");
if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_CC as libc::c_int { if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_CC as libc::c_int {
let fld_cc: *mut mailimf_cc = (*field).fld_data.fld_cc; let fld_cc: *mut mailimf_cc = (*field).fld_data.fld_cc;
@@ -149,11 +148,11 @@ pub unsafe fn dc_receive_imf(
context, context,
(*fld_cc).cc_addr_list, (*fld_cc).cc_addr_list,
if 0 == incoming { if 0 == incoming {
0x2000 Origin::OutgoingCc
} else if incoming_origin >= 0x100 { } else if incoming_origin.is_verified() {
0x200 Origin::IncomingCc
} else { } else {
0x20 Origin::IncomingUnknownCc
}, },
to_ids, to_ids,
0 as *mut libc::c_int, 0 as *mut libc::c_int,
@@ -255,7 +254,7 @@ pub unsafe fn dc_receive_imf(
if chat_id == 0 as libc::c_uint { if chat_id == 0 as libc::c_uint {
let create_blocked: libc::c_int = if 0 != test_normal_chat_id let create_blocked: libc::c_int = if 0 != test_normal_chat_id
&& test_normal_chat_id_blocked == 0 && test_normal_chat_id_blocked == 0
|| incoming_origin >= 0x7fffffff || incoming_origin.is_start_new_chat()
{ {
0 0
} else { } else {
@@ -287,7 +286,7 @@ pub unsafe fn dc_receive_imf(
} }
if chat_id == 0 as libc::c_uint { if chat_id == 0 as libc::c_uint {
let create_blocked_0: libc::c_int = let create_blocked_0: libc::c_int =
if incoming_origin >= 0x7fffffff || from_id == to_id { if incoming_origin.is_start_new_chat() || from_id == to_id {
0 0
} else { } else {
2 2
@@ -311,16 +310,20 @@ pub unsafe fn dc_receive_imf(
} else if 0 } else if 0
!= dc_is_reply_to_known_message(context, &mime_parser) != dc_is_reply_to_known_message(context, &mime_parser)
{ {
dc_scaleup_contact_origin(context, from_id, 0x100); Contact::scaleup_origin_by_id(
context,
from_id,
Origin::IncomingReplyTo,
);
info!( info!(
context, context,
0, 0,
"Message is a reply to a known message, mark sender as known.", "Message is a reply to a known message, mark sender as known.",
); );
incoming_origin = if incoming_origin > 0x100 { incoming_origin = if incoming_origin.is_verified() {
incoming_origin incoming_origin
} else { } else {
0x100 Origin::IncomingReplyTo
} }
} }
} }
@@ -329,8 +332,8 @@ pub unsafe fn dc_receive_imf(
chat_id = 3 as uint32_t chat_id = 3 as uint32_t
} }
if 0 != chat_id_blocked && state == 10 { if 0 != chat_id_blocked && state == 10 {
if incoming_origin < 0x100 && msgrmsg == 0 { if !incoming_origin.is_verified() && msgrmsg == 0 {
state = 13 state = 13;
} }
} }
} else { } else {
@@ -355,12 +358,13 @@ pub unsafe fn dc_receive_imf(
} }
} }
if chat_id == 0 as libc::c_uint && 0 != allow_creation { if chat_id == 0 as libc::c_uint && 0 != allow_creation {
let create_blocked_1: libc::c_int = let create_blocked_1: libc::c_int = if 0 != msgrmsg
if 0 != msgrmsg && !dc_is_contact_blocked(context, to_id) { && !Contact::is_blocked_load(context, to_id)
0 {
} else { 0
2 } else {
}; 2
};
dc_create_or_lookup_nchat_by_contact_id( dc_create_or_lookup_nchat_by_contact_id(
context, context,
to_id, to_id,
@@ -437,7 +441,7 @@ pub unsafe fn dc_receive_imf(
) )
} }
} }
icnt = carray_count(mime_parser.parts) as size_t; let icnt = mime_parser.parts.len();
context.sql.prepare( context.sql.prepare(
"INSERT INTO msgs \ "INSERT INTO msgs \
@@ -452,23 +456,23 @@ pub unsafe fn dc_receive_imf(
current_block = 2756754640271984560; current_block = 2756754640271984560;
break; break;
} }
let part = carray_get(mime_parser.parts, i as libc::c_uint) as *mut dc_mimepart_t; let part = &mut mime_parser.parts[i];
if !(0 != (*part).is_meta) { if part.is_meta == 0 {
if !mime_parser.location_kml.is_none() if !mime_parser.location_kml.is_none()
&& icnt == 1 && icnt == 1
&& !(*part).msg.is_null() && !part.msg.is_null()
&& (strcmp( && (strcmp(
(*part).msg, part.msg,
b"-location-\x00" as *const u8 as *const libc::c_char, b"-location-\x00" as *const u8 as *const libc::c_char,
) == 0 ) == 0
|| *(*part).msg.offset(0isize) as libc::c_int == 0) || *part.msg.offset(0isize) as libc::c_int == 0)
{ {
hidden = 1; hidden = 1;
if state == 10 { if state == 10 {
state = 13 state = 13
} }
} }
if (*part).type_0 == 10 { if part.type_0 == 10 {
txt_raw = dc_mprintf( txt_raw = dc_mprintf(
b"%s\n\n%s\x00" as *const u8 as *const libc::c_char, b"%s\n\n%s\x00" as *const u8 as *const libc::c_char,
if !mime_parser.subject.is_null() { if !mime_parser.subject.is_null() {
@@ -476,12 +480,12 @@ pub unsafe fn dc_receive_imf(
} else { } else {
b"\x00" as *const u8 as *const libc::c_char b"\x00" as *const u8 as *const libc::c_char
}, },
(*part).msg_raw, part.msg_raw,
) )
} }
if 0 != mime_parser.is_system_message { if 0 != mime_parser.is_system_message {
(*part).param.set_int( Param::Cmd, part.param.set_int( Param::Cmd,
mime_parser.is_system_message, mime_parser.is_system_message,
); );
} }
@@ -496,11 +500,11 @@ pub unsafe fn dc_receive_imf(
sort_timestamp, sort_timestamp,
sent_timestamp, sent_timestamp,
rcvd_timestamp, rcvd_timestamp,
(*part).type_0, part.type_0,
state, state,
msgrmsg, msgrmsg,
if !(*part).msg.is_null() { if !part.msg.is_null() {
as_str((*part).msg) as_str(part.msg)
} else { } else {
"" ""
}, },
@@ -510,8 +514,8 @@ pub unsafe fn dc_receive_imf(
} else { } else {
String::new() String::new()
}, },
(*part).param.to_string(), part.param.to_string(),
(*part).bytes, part.bytes,
hidden, hidden,
if 0 != save_mime_headers { if 0 != save_mime_headers {
let body_string = std::str::from_utf8(std::slice::from_raw_parts(imf_raw_not_terminated as *const u8, imf_raw_bytes)).unwrap(); let body_string = std::str::from_utf8(std::slice::from_raw_parts(imf_raw_not_terminated as *const u8, imf_raw_bytes)).unwrap();
@@ -588,17 +592,13 @@ pub unsafe fn dc_receive_imf(
match current_block { match current_block {
16282941964262048061 => {} 16282941964262048061 => {}
_ => { _ => {
if carray_count(mime_parser.reports) > 0 as libc::c_uint { if !mime_parser.reports.is_empty() {
let mdns_enabled = context let mdns_enabled = context
.sql .sql
.get_config_int(context, "mdns_enabled") .get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1); .unwrap_or_else(|| 1);
icnt = carray_count(mime_parser.reports) as size_t; for report_root in mime_parser.reports {
i = 0 as size_t;
while i < icnt {
let mut mdn_consumed: libc::c_int = 0; let mut mdn_consumed: libc::c_int = 0;
let report_root: *mut mailmime =
carray_get(mime_parser.reports, i as libc::c_uint) as *mut mailmime;
let report_type: *mut mailmime_parameter = mailmime_find_ct_parameter( let report_type: *mut mailmime_parameter = mailmime_find_ct_parameter(
report_root, report_root,
b"report-type\x00" as *const u8 as *const libc::c_char, b"report-type\x00" as *const u8 as *const libc::c_char,
@@ -723,8 +723,7 @@ pub unsafe fn dc_receive_imf(
&mut msg_id, &mut msg_id,
) { ) {
rr_event_to_send rr_event_to_send
.push((chat_id_0, 0)); .push((chat_id_0, msg_id));
rr_event_to_send.push((msg_id, 0));
} }
mdn_consumed = (msg_id mdn_consumed = (msg_id
!= 0 as libc::c_uint) != 0 as libc::c_uint)
@@ -757,7 +756,6 @@ pub unsafe fn dc_receive_imf(
} }
} }
} }
i = i.wrapping_add(1)
} }
} }
if !mime_parser.message_kml.is_none() && chat_id > 9 as libc::c_uint { if !mime_parser.message_kml.is_none() && chat_id > 9 as libc::c_uint {
@@ -771,7 +769,7 @@ pub unsafe fn dc_receive_imf(
context, context,
chat_id, chat_id,
from_id, from_id,
mime_parser.message_kml.unwrap().locations, &mime_parser.message_kml.unwrap().locations,
1, 1,
); );
if 0 != newest_location_id && 0 == hidden { if 0 != newest_location_id && 0 == hidden {
@@ -784,28 +782,34 @@ pub unsafe fn dc_receive_imf(
if !mime_parser.location_kml.is_none() if !mime_parser.location_kml.is_none()
&& chat_id > DC_CHAT_ID_LAST_SPECIAL as libc::c_uint && chat_id > DC_CHAT_ID_LAST_SPECIAL as libc::c_uint
{ {
let contact = dc_get_contact(context, from_id); if !mime_parser.location_kml.as_ref().unwrap().addr.is_null() {
if !mime_parser.location_kml.as_ref().unwrap().addr.is_null() if let Ok(contact) = Contact::get_by_id(context, from_id) {
&& !contact.is_null() if !contact.get_addr().is_empty()
&& !(*contact).addr.is_null() && contact.get_addr().to_lowercase()
&& strcasecmp( == as_str(mime_parser.location_kml.as_ref().unwrap().addr)
(*contact).addr, .to_lowercase()
mime_parser.location_kml.as_ref().unwrap().addr, {
) == 0 let newest_location_id = dc_save_locations(
{ context,
let newest_location_id = dc_save_locations( chat_id,
context, from_id,
chat_id, &mime_parser.location_kml.as_ref().unwrap().locations,
from_id, 0,
mime_parser.location_kml.as_ref().unwrap().locations, );
0, if newest_location_id != 0
); && hidden == 0
if newest_location_id != 0 && hidden == 0 && !location_id_written { && !location_id_written
dc_set_msg_location_id(context, insert_msg_id, newest_location_id); {
dc_set_msg_location_id(
context,
insert_msg_id,
newest_location_id,
);
}
send_event = true;
}
} }
send_event = true;
} }
dc_contact_unref(contact);
} }
if send_event { if send_event {
context.call_cb( context.call_cb(
@@ -955,7 +959,13 @@ unsafe fn create_or_lookup_group(
if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_MESSAGE_ID as libc::c_int { if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_MESSAGE_ID as libc::c_int {
let fld_message_id: *mut mailimf_message_id = (*field).fld_data.fld_message_id; let fld_message_id: *mut mailimf_message_id = (*field).fld_data.fld_message_id;
if !fld_message_id.is_null() { if !fld_message_id.is_null() {
grpid = dc_extract_grpid_from_rfc724_mid((*fld_message_id).mid_value) if let Some(extracted_grpid) =
dc_extract_grpid_from_rfc724_mid(as_str((*fld_message_id).mid_value))
{
grpid = extracted_grpid.strdup();
} else {
grpid = 0 as *mut libc::c_char;
}
} }
} }
if grpid.is_null() { if grpid.is_null() {
@@ -1015,9 +1025,8 @@ unsafe fn create_or_lookup_group(
if !optional_field.is_null() { if !optional_field.is_null() {
X_MrRemoveFromGrp = (*optional_field).fld_value; X_MrRemoveFromGrp = (*optional_field).fld_value;
mime_parser.is_system_message = 5; mime_parser.is_system_message = 5;
let left_group: libc::c_int = let left_group = (Contact::lookup_id_by_addr(context, as_str(X_MrRemoveFromGrp))
(dc_lookup_contact_id_by_addr(context, X_MrRemoveFromGrp) == from_id as u32) as libc::c_int;
== from_id as libc::c_uint) as libc::c_int;
better_msg = context.stock_system_msg( better_msg = context.stock_system_msg(
if 0 != left_group { if 0 != left_group {
StockMessage::MsgGroupLeft StockMessage::MsgGroupLeft
@@ -1126,7 +1135,7 @@ unsafe fn create_or_lookup_group(
&& !grpname.is_null() && !grpname.is_null()
&& X_MrRemoveFromGrp.is_null() && X_MrRemoveFromGrp.is_null()
&& (0 == group_explicitly_left && (0 == group_explicitly_left
|| !X_MrAddToGrp.is_null() && dc_addr_cmp(&self_addr, as_str(X_MrAddToGrp))) || !X_MrAddToGrp.is_null() && addr_cmp(&self_addr, as_str(X_MrAddToGrp)))
{ {
/*otherwise, a pending "quit" message may pop up*/ /*otherwise, a pending "quit" message may pop up*/
/*re-create explicitly left groups only if ourself is re-added*/ /*re-create explicitly left groups only if ourself is re-added*/
@@ -1208,20 +1217,15 @@ unsafe fn create_or_lookup_group(
{ {
ok = 1 ok = 1
} else { } else {
let mut i_0: libc::c_int = 0; for part in &mut mime_parser.parts {
while (i_0 as libc::c_uint) < carray_count(mime_parser.parts) { if part.type_0 == 20 {
let part: *mut dc_mimepart_t = grpimage = part
carray_get(mime_parser.parts, i_0 as libc::c_uint)
as *mut dc_mimepart_t;
if (*part).type_0 == 20 {
grpimage = (*part)
.param .param
.get(Param::File) .get(Param::File)
.map(|s| to_cstring(s)) .map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut()); .unwrap_or_else(|| std::ptr::null_mut());
ok = 1 ok = 1
} }
i_0 += 1
} }
} }
if 0 != ok { if 0 != ok {
@@ -1261,17 +1265,20 @@ unsafe fn create_or_lookup_group(
params![chat_id as i32], params![chat_id as i32],
) )
.ok(); .ok();
if skip.is_null() || !dc_addr_cmp(&self_addr, as_str(skip)) { if skip.is_null() || !addr_cmp(&self_addr, as_str(skip)) {
dc_add_to_chat_contacts_table(context, chat_id, 1); dc_add_to_chat_contacts_table(context, chat_id, 1);
} }
if from_id > 9 { if from_id > 9 {
if !dc_addr_equals_contact(context, &self_addr, from_id as u32) if !Contact::addr_equals_contact(
&& (skip.is_null() context,
|| !dc_addr_equals_contact( &self_addr,
context, from_id as u32,
to_string(skip), ) && (skip.is_null()
from_id as u32, || !Contact::addr_equals_contact(
)) context,
to_string(skip),
from_id as u32,
))
{ {
dc_add_to_chat_contacts_table( dc_add_to_chat_contacts_table(
context, context,
@@ -1283,9 +1290,13 @@ unsafe fn create_or_lookup_group(
i = 0; i = 0;
while i < to_ids_cnt { while i < to_ids_cnt {
let to_id = dc_array_get_id(to_ids, i as size_t); let to_id = dc_array_get_id(to_ids, i as size_t);
if !dc_addr_equals_contact(context, &self_addr, to_id) if !Contact::addr_equals_contact(context, &self_addr, to_id)
&& (skip.is_null() && (skip.is_null()
|| !dc_addr_equals_contact(context, to_string(skip), to_id)) || !Contact::addr_equals_contact(
context,
to_string(skip),
to_id,
))
{ {
dc_add_to_chat_contacts_table(context, chat_id, to_id); dc_add_to_chat_contacts_table(context, chat_id, to_id);
} }
@@ -1414,10 +1425,12 @@ unsafe fn create_or_lookup_adhoc_group(
{ {
grpname = dc_strdup(mime_parser.subject) grpname = dc_strdup(mime_parser.subject)
} else { } else {
grpname = to_cstring(context.stock_string_repl_int( grpname = context
StockMessage::Member, .stock_string_repl_int(
dc_array_get_cnt(member_ids) as libc::c_int, StockMessage::Member,
)); dc_array_get_cnt(member_ids) as libc::c_int,
)
.strdup();
} }
chat_id = chat_id =
create_group_record(context, grpid, grpname, create_blocked, 0); create_group_record(context, grpid, grpname, create_blocked, 0);
@@ -1526,7 +1539,7 @@ fn hex_hash(s: impl AsRef<str>) -> *const libc::c_char {
let bytes = s.as_ref().as_bytes(); let bytes = s.as_ref().as_bytes();
let result = Sha256::digest(bytes); let result = Sha256::digest(bytes);
let result_hex = hex::encode(&result[..8]); let result_hex = hex::encode(&result[..8]);
unsafe { to_cstring(result_hex) as *const _ } unsafe { result_hex.strdup() as *const _ }
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@@ -1554,7 +1567,7 @@ unsafe fn search_chat_ids_by_contact_ids(
i += 1 i += 1
} }
if !(dc_array_get_cnt(contact_ids) == 0) { if !(dc_array_get_cnt(contact_ids) == 0) {
dc_array_sort_ids(contact_ids); (*contact_ids).sort_ids();
contact_ids_str = contact_ids_str =
dc_array_get_string(contact_ids, b",\x00" as *const u8 as *const libc::c_char); dc_array_get_string(contact_ids, b",\x00" as *const u8 as *const libc::c_char);
@@ -1608,26 +1621,21 @@ unsafe fn check_verified_properties(
to_ids: *const dc_array_t, to_ids: *const dc_array_t,
failure_reason: *mut *mut libc::c_char, failure_reason: *mut *mut libc::c_char,
) -> libc::c_int { ) -> libc::c_int {
let contact = dc_contact_new(context);
let verify_fail = |reason: String| { let verify_fail = |reason: String| {
*failure_reason = to_cstring(format!("{}. See \"Info\" for details.", reason)); *failure_reason = format!("{}. See \"Info\" for details.", reason).strdup();
warn!(context, 0, "{}", reason); warn!(context, 0, "{}", reason);
}; };
let cleanup = || { let contact = match Contact::load_from_db(context, from_id) {
dc_contact_unref(contact); Ok(contact) => contact,
Err(_err) => {
verify_fail("Internal Error; cannot load contact".into());
return 0;
}
}; };
if !dc_contact_load_from_db(contact, &context.sql, from_id) {
verify_fail("Internal Error; cannot load contact".into());
cleanup();
return 0;
}
if 0 == mimeparser.e2ee_helper.encrypted { if 0 == mimeparser.e2ee_helper.encrypted {
verify_fail("This message is not encrypted".into()); verify_fail("This message is not encrypted".into());
cleanup();
return 0; return 0;
} }
@@ -1636,18 +1644,18 @@ unsafe fn check_verified_properties(
// this check is skipped for SELF as there is no proper SELF-peerstate // this check is skipped for SELF as there is no proper SELF-peerstate
// and results in group-splits otherwise. // and results in group-splits otherwise.
if from_id != 1 { if from_id != 1 {
let peerstate = Peerstate::from_addr(context, &context.sql, as_str((*contact).addr)); let peerstate = Peerstate::from_addr(context, &context.sql, contact.get_addr());
if peerstate.is_none() || dc_contact_is_verified_ex(contact, peerstate.as_ref()) != 2 { if peerstate.is_none()
|| contact.is_verified_ex(peerstate.as_ref()) != VerifiedStatus::BidirectVerified
{
verify_fail("The sender of this message is not verified.".into()); verify_fail("The sender of this message is not verified.".into());
cleanup();
return 0; return 0;
} }
if let Some(peerstate) = peerstate { if let Some(peerstate) = peerstate {
if !peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures) { if !peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures) {
verify_fail("The message was sent with non-verified encryption.".into()); verify_fail("The message was sent with non-verified encryption.".into());
cleanup();
return 0; return 0;
} }
} }
@@ -1669,7 +1677,6 @@ unsafe fn check_verified_properties(
); );
if rows.is_err() { if rows.is_err() {
cleanup();
return 0; return 0;
} }
for (to_addr, mut is_verified) in rows.unwrap().into_iter() { for (to_addr, mut is_verified) in rows.unwrap().into_iter() {
@@ -1690,7 +1697,7 @@ unsafe fn check_verified_properties(
context, context,
0, 0,
"{} has verfied {}.", "{} has verfied {}.",
as_str((*contact).addr), contact.get_addr(),
to_addr, to_addr,
); );
let fp = peerstate.gossip_key_fingerprint.clone(); let fp = peerstate.gossip_key_fingerprint.clone();
@@ -1706,7 +1713,6 @@ unsafe fn check_verified_properties(
"{} is not a member of this verified group", "{} is not a member of this verified group",
to_addr to_addr
)); ));
cleanup();
return 0; return 0;
} }
} }
@@ -1714,14 +1720,13 @@ unsafe fn check_verified_properties(
1 1
} }
unsafe fn set_better_msg<T: AsRef<str>>(mime_parser: &dc_mimeparser_t, better_msg: T) { unsafe fn set_better_msg<T: AsRef<str>>(mime_parser: &mut dc_mimeparser_t, better_msg: T) {
let msg = better_msg.as_ref(); let msg = better_msg.as_ref();
if !(msg.len() > 0) && carray_count((*mime_parser).parts) > 0 { if msg.len() > 0 && !mime_parser.parts.is_empty() {
let mut part: *mut dc_mimepart_t = let part = &mut mime_parser.parts[0];
carray_get(mime_parser.parts, 0 as libc::c_uint) as *mut dc_mimepart_t;
if (*part).type_0 == 10 { if (*part).type_0 == 10 {
free((*part).msg as *mut libc::c_void); free(part.msg as *mut libc::c_void);
(*part).msg = to_cstring(msg); part.msg = msg.strdup();
} }
}; };
} }
@@ -1888,7 +1893,7 @@ fn is_msgrmsg_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) ->
unsafe fn dc_add_or_lookup_contacts_by_address_list( unsafe fn dc_add_or_lookup_contacts_by_address_list(
context: &Context, context: &Context,
adr_list: *const mailimf_address_list, adr_list: *const mailimf_address_list,
origin: libc::c_int, origin: Origin,
ids: *mut dc_array_t, ids: *mut dc_array_t,
check_self: *mut libc::c_int, check_self: *mut libc::c_int,
) { ) {
@@ -1938,7 +1943,7 @@ unsafe fn dc_add_or_lookup_contacts_by_address_list(
unsafe fn dc_add_or_lookup_contacts_by_mailbox_list( unsafe fn dc_add_or_lookup_contacts_by_mailbox_list(
context: &Context, context: &Context,
mb_list: *const mailimf_mailbox_list, mb_list: *const mailimf_mailbox_list,
origin: libc::c_int, origin: Origin,
ids: *mut dc_array_t, ids: *mut dc_array_t,
check_self: *mut libc::c_int, check_self: *mut libc::c_int,
) { ) {
@@ -1976,7 +1981,7 @@ unsafe fn add_or_lookup_contact_by_addr(
context: &Context, context: &Context,
display_name_enc: *const libc::c_char, display_name_enc: *const libc::c_char,
addr_spec: *const libc::c_char, addr_spec: *const libc::c_char,
origin: libc::c_int, origin: Origin,
ids: *mut dc_array_t, ids: *mut dc_array_t,
mut check_self: *mut libc::c_int, mut check_self: *mut libc::c_int,
) { ) {
@@ -1994,7 +1999,7 @@ unsafe fn add_or_lookup_contact_by_addr(
.get_config(context, "configured_addr") .get_config(context, "configured_addr")
.unwrap_or_default(); .unwrap_or_default();
if dc_addr_cmp(self_addr, as_str(addr_spec)) { if addr_cmp(self_addr, as_str(addr_spec)) {
*check_self = 1; *check_self = 1;
} }
@@ -2002,20 +2007,15 @@ unsafe fn add_or_lookup_contact_by_addr(
return; return;
} }
/* add addr_spec if missing, update otherwise */ /* add addr_spec if missing, update otherwise */
let mut display_name_dec = 0 as *mut libc::c_char; let mut display_name_dec = "".to_string();
if !display_name_enc.is_null() { if !display_name_enc.is_null() {
display_name_dec = dc_decode_header_words(display_name_enc); let tmp = as_str(dc_decode_header_words(display_name_enc));
dc_normalize_name(display_name_dec); display_name_dec = normalize_name(&tmp);
} }
/*can be NULL*/ /*can be NULL*/
let row_id = dc_add_or_lookup_contact( let row_id = Contact::add_or_lookup(context, display_name_dec, as_str(addr_spec), origin)
context, .map(|(id, _)| id)
display_name_dec, .unwrap_or_default();
addr_spec,
origin,
0 as *mut libc::c_int,
);
free(display_name_dec as *mut libc::c_void);
if 0 != row_id { if 0 != row_id {
if !dc_array_search_id(ids, row_id, 0 as *mut size_t) { if !dc_array_search_id(ids, row_id, 0 as *mut size_t) {
dc_array_add_id(ids, row_id); dc_array_add_id(ids, row_id);

View File

@@ -80,7 +80,7 @@ pub unsafe fn dc_saxparser_set_text_handler(
} }
pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *const libc::c_char) { pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *const libc::c_char) {
let current_block: u64; let mut is_valid = false;
let mut bak: libc::c_char; let mut bak: libc::c_char;
let buf_start: *mut libc::c_char; let buf_start: *mut libc::c_char;
let mut last_text_start: *mut libc::c_char; let mut last_text_start: *mut libc::c_char;
@@ -99,7 +99,7 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c
p = buf_start; p = buf_start;
loop { loop {
if !(0 != *p) { if !(0 != *p) {
current_block = 13425230902034816933; is_valid = true;
break; break;
} }
if *p as libc::c_int == '<' as i32 { if *p as libc::c_int == '<' as i32 {
@@ -113,7 +113,6 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c
if strncmp(p, b"!--\x00" as *const u8 as *const libc::c_char, 3) == 0i32 { if strncmp(p, b"!--\x00" as *const u8 as *const libc::c_char, 3) == 0i32 {
p = strstr(p, b"-->\x00" as *const u8 as *const libc::c_char); p = strstr(p, b"-->\x00" as *const u8 as *const libc::c_char);
if p.is_null() { if p.is_null() {
current_block = 7627180618761592946;
break; break;
} }
p = p.offset(3isize) p = p.offset(3isize)
@@ -137,7 +136,6 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c
strlen(text_beg), strlen(text_beg),
'c' as i32 as libc::c_char, 'c' as i32 as libc::c_char,
); );
current_block = 7627180618761592946;
break; break;
} }
} else if strncmp(p, b"!DOCTYPE\x00" as *const u8 as *const libc::c_char, 8) == 0i32 { } else if strncmp(p, b"!DOCTYPE\x00" as *const u8 as *const libc::c_char, 8) == 0i32 {
@@ -149,13 +147,11 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c
} }
if *p as libc::c_int == 0i32 { if *p as libc::c_int == 0i32 {
/* unclosed doctype */ /* unclosed doctype */
current_block = 7627180618761592946;
break; break;
} else if *p as libc::c_int == '[' as i32 { } else if *p as libc::c_int == '[' as i32 {
p = strstr(p, b"]>\x00" as *const u8 as *const libc::c_char); p = strstr(p, b"]>\x00" as *const u8 as *const libc::c_char);
if p.is_null() { if p.is_null() {
/* unclosed inline doctype */ /* unclosed inline doctype */
current_block = 7627180618761592946;
break; break;
} else { } else {
p = p.offset(2isize) p = p.offset(2isize)
@@ -167,7 +163,6 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c
p = strstr(p, b"?>\x00" as *const u8 as *const libc::c_char); p = strstr(p, b"?>\x00" as *const u8 as *const libc::c_char);
if p.is_null() { if p.is_null() {
/* unclosed processing instruction */ /* unclosed processing instruction */
current_block = 7627180618761592946;
break; break;
} else { } else {
p = p.offset(2isize) p = p.offset(2isize)
@@ -328,7 +323,6 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c
p = strchr(p, '>' as i32); p = strchr(p, '>' as i32);
if p.is_null() { if p.is_null() {
/* unclosed start-tag or end-tag */ /* unclosed start-tag or end-tag */
current_block = 7627180618761592946;
break; break;
} else { } else {
p = p.offset(1isize) p = p.offset(1isize)
@@ -339,16 +333,13 @@ pub unsafe fn dc_saxparser_parse(saxparser: *mut dc_saxparser_t, buf_start__: *c
p = p.offset(1isize) p = p.offset(1isize)
} }
} }
match current_block { if is_valid {
13425230902034816933 => { call_text_cb(
call_text_cb( saxparser,
saxparser, last_text_start,
last_text_start, p.wrapping_offset_from(last_text_start) as size_t,
p.wrapping_offset_from(last_text_start) as size_t, '&' as i32 as libc::c_char,
'&' as i32 as libc::c_char, );
);
}
_ => {}
} }
do_free_attr(attr.as_mut_ptr(), free_attr.as_mut_ptr()); do_free_attr(attr.as_mut_ptr(), free_attr.as_mut_ptr());
free(buf_start as *mut libc::c_void); free(buf_start as *mut libc::c_void);

View File

@@ -5,11 +5,11 @@ use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use crate::aheader::EncryptPreference; use crate::aheader::EncryptPreference;
use crate::constants::*; use crate::constants::*;
use crate::contact::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_array::*; use crate::dc_array::*;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_configure::*; use crate::dc_configure::*;
use crate::dc_contact::*;
use crate::dc_e2ee::*; use crate::dc_e2ee::*;
use crate::dc_lot::*; use crate::dc_lot::*;
use crate::dc_mimeparser::*; use crate::dc_mimeparser::*;
@@ -40,17 +40,17 @@ pub unsafe fn dc_get_securejoin_qr(
let mut chat = 0 as *mut Chat; let mut chat = 0 as *mut Chat;
let mut group_name = 0 as *mut libc::c_char; let mut group_name = 0 as *mut libc::c_char;
let mut group_name_urlencoded = 0 as *mut libc::c_char; let mut group_name_urlencoded = 0 as *mut libc::c_char;
let mut qr = None; let mut qr: Option<String> = None;
dc_ensure_secret_key_exists(context); dc_ensure_secret_key_exists(context);
invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id); invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id);
if invitenumber.is_null() { if invitenumber.is_null() {
invitenumber = dc_create_id(); invitenumber = dc_create_id().strdup();
dc_token_save(context, DC_TOKEN_INVITENUMBER, group_chat_id, invitenumber); dc_token_save(context, DC_TOKEN_INVITENUMBER, group_chat_id, invitenumber);
} }
auth = dc_token_lookup(context, DC_TOKEN_AUTH, group_chat_id); auth = dc_token_lookup(context, DC_TOKEN_AUTH, group_chat_id);
if auth.is_null() { if auth.is_null() {
auth = dc_create_id(); auth = dc_create_id().strdup();
dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth); dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth);
} }
let self_addr = context.sql.get_config(context, "configured_addr"); let self_addr = context.sql.get_config(context, "configured_addr");
@@ -64,7 +64,7 @@ pub unsafe fn dc_get_securejoin_qr(
free(group_name_urlencoded as *mut libc::c_void); free(group_name_urlencoded as *mut libc::c_void);
if let Some(qr) = qr { if let Some(qr) = qr {
to_cstring(qr) qr.strdup()
} else { } else {
std::ptr::null_mut() std::ptr::null_mut()
} }
@@ -263,11 +263,8 @@ unsafe fn send_handshake_msg(
grpid: *const libc::c_char, grpid: *const libc::c_char,
) { ) {
let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context); let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context);
(*msg).type_0 = DC_MSG_TEXT; (*msg).type_0 = Viewtype::Text;
(*msg).text = dc_mprintf( (*msg).text = Some(format!("Secure-Join: {}", to_string(step)));
b"Secure-Join: %s\x00" as *const u8 as *const libc::c_char,
step,
);
(*msg).hidden = 1; (*msg).hidden = 1;
(*msg).param.set_int(Param::Cmd, 7); (*msg).param.set_int(Param::Cmd, 7);
if step.is_null() { if step.is_null() {
@@ -318,30 +315,23 @@ unsafe fn fingerprint_equals_sender(
return 0; return 0;
} }
let mut fingerprint_equal: libc::c_int = 0i32; let mut fingerprint_equal: libc::c_int = 0i32;
let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id); let contacts = dc_get_chat_contacts(context, contact_chat_id);
let contact: *mut dc_contact_t = dc_contact_new(context);
if !(dc_array_get_cnt(contacts) != 1) { if !(dc_array_get_cnt(contacts) != 1) {
if !dc_contact_load_from_db( if let Ok(contact) = Contact::load_from_db(context, dc_array_get_id(contacts, 0)) {
contact, if let Some(peerstate) = Peerstate::from_addr(context, &context.sql, contact.get_addr())
&context.sql, {
dc_array_get_id(contacts, 0i32 as size_t), let fingerprint_normalized = dc_normalize_fingerprint(as_str(fingerprint));
) { if peerstate.public_key_fingerprint.is_some()
&& &fingerprint_normalized == peerstate.public_key_fingerprint.as_ref().unwrap()
{
fingerprint_equal = 1;
}
}
} else {
return 0; return 0;
} }
if let Some(peerstate) =
Peerstate::from_addr(context, &context.sql, as_str((*contact).addr))
{
let fingerprint_normalized = dc_normalize_fingerprint(as_str(fingerprint));
if peerstate.public_key_fingerprint.is_some()
&& &fingerprint_normalized == peerstate.public_key_fingerprint.as_ref().unwrap()
{
fingerprint_equal = 1;
}
}
} }
dc_contact_unref(contact);
dc_array_unref(contacts); dc_array_unref(contacts);
fingerprint_equal fingerprint_equal
@@ -363,7 +353,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
let mut contact_chat_id_blocked: libc::c_int = 0i32; let mut contact_chat_id_blocked: libc::c_int = 0i32;
let mut grpid: *mut libc::c_char = 0 as *mut libc::c_char; let mut grpid: *mut libc::c_char = 0 as *mut libc::c_char;
let mut ret: libc::c_int = 0i32; let mut ret: libc::c_int = 0i32;
let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t;
if !(contact_id <= 9i32 as libc::c_uint) { if !(contact_id <= 9i32 as libc::c_uint) {
step = lookup_field(mimeparser, "Secure-Join"); step = lookup_field(mimeparser, "Secure-Join");
if !step.is_null() { if !step.is_null() {
@@ -575,7 +565,11 @@ pub unsafe fn dc_handle_securejoin_handshake(
); );
current_block = 4378276786830486580; current_block = 4378276786830486580;
} else { } else {
dc_scaleup_contact_origin(context, contact_id, 0x1000000i32); Contact::scaleup_origin_by_id(
context,
contact_id,
Origin::SecurejoinInvited,
);
info!(context, 0, "Auth verified.",); info!(context, 0, "Auth verified.",);
secure_connection_established(context, contact_chat_id); secure_connection_established(context, contact_chat_id);
context.call_cb( context.call_cb(
@@ -702,16 +696,23 @@ pub unsafe fn dc_handle_securejoin_handshake(
); );
current_block = 4378276786830486580; current_block = 4378276786830486580;
} else { } else {
dc_scaleup_contact_origin(context, contact_id, 0x2000000i32); Contact::scaleup_origin_by_id(
context,
contact_id,
Origin::SecurejoinJoined,
);
context.call_cb( context.call_cb(
Event::CONTACTS_CHANGED, Event::CONTACTS_CHANGED,
0i32 as uintptr_t, 0i32 as uintptr_t,
0i32 as uintptr_t, 0i32 as uintptr_t,
); );
if 0 != join_vg { if 0 != join_vg {
if 0 == dc_addr_equals_self( if !addr_equals_self(
context, context,
lookup_field(mimeparser, "Chat-Group-Member-Added"), as_str(lookup_field(
mimeparser,
"Chat-Group-Member-Added",
)),
) { ) {
info!( info!(
context, context,
@@ -759,22 +760,26 @@ pub unsafe fn dc_handle_securejoin_handshake(
==== Alice - the inviter side ==== ==== Alice - the inviter side ====
==== Step 8 in "Out-of-band verified groups" protocol ==== ==== Step 8 in "Out-of-band verified groups" protocol ====
============================================================ */ ============================================================ */
contact = dc_get_contact(context, contact_id); if let Ok(contact) = Contact::get_by_id(context, contact_id) {
if contact.is_null() || 0 == dc_contact_is_verified(contact) { if contact.is_verified() == VerifiedStatus::Unverified {
warn!(context, 0, "vg-member-added-received invalid.",);
current_block = 4378276786830486580;
} else {
context.call_cb(
Event::SECUREJOIN_INVITER_PROGRESS,
contact_id as uintptr_t,
800i32 as uintptr_t,
);
context.call_cb(
Event::SECUREJOIN_INVITER_PROGRESS,
contact_id as uintptr_t,
1000i32 as uintptr_t,
);
current_block = 10256747982273457880;
}
} else {
warn!(context, 0, "vg-member-added-received invalid.",); warn!(context, 0, "vg-member-added-received invalid.",);
current_block = 4378276786830486580; current_block = 4378276786830486580;
} else {
context.call_cb(
Event::SECUREJOIN_INVITER_PROGRESS,
contact_id as uintptr_t,
800i32 as uintptr_t,
);
context.call_cb(
Event::SECUREJOIN_INVITER_PROGRESS,
contact_id as uintptr_t,
1000i32 as uintptr_t,
);
current_block = 10256747982273457880;
} }
} else { } else {
current_block = 10256747982273457880; current_block = 10256747982273457880;
@@ -789,7 +794,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
} }
} }
} }
dc_contact_unref(contact);
free(scanned_fingerprint_of_alice as *mut libc::c_void); free(scanned_fingerprint_of_alice as *mut libc::c_void);
free(auth as *mut libc::c_void); free(auth as *mut libc::c_void);
free(own_fingerprint as *mut libc::c_void); free(own_fingerprint as *mut libc::c_void);
@@ -805,23 +810,20 @@ unsafe fn end_bobs_joining(context: &Context, status: libc::c_int) {
unsafe fn secure_connection_established(context: &Context, contact_chat_id: uint32_t) { unsafe fn secure_connection_established(context: &Context, contact_chat_id: uint32_t) {
let contact_id: uint32_t = chat_id_2_contact_id(context, contact_chat_id); let contact_id: uint32_t = chat_id_2_contact_id(context, contact_chat_id);
let contact: *mut dc_contact_t = dc_get_contact(context, contact_id); let contact = Contact::get_by_id(context, contact_id);
let msg = CString::new(context.stock_string_repl_str( let addr = if let Ok(ref contact) = contact {
StockMessage::ContactVerified, contact.get_addr()
if !contact.is_null() { } else {
as_str((*contact).addr) "?"
} else { };
"?" let msg =
}, CString::new(context.stock_string_repl_str(StockMessage::ContactVerified, addr)).unwrap();
))
.unwrap();
dc_add_device_msg(context, contact_chat_id, msg.as_ptr()); dc_add_device_msg(context, contact_chat_id, msg.as_ptr());
context.call_cb( context.call_cb(
Event::CHAT_MODIFIED, Event::CHAT_MODIFIED,
contact_chat_id as uintptr_t, contact_chat_id as uintptr_t,
0i32 as uintptr_t, 0i32 as uintptr_t,
); );
dc_contact_unref(contact);
} }
unsafe fn lookup_field(mimeparser: &dc_mimeparser_t, key: &str) -> *const libc::c_char { unsafe fn lookup_field(mimeparser: &dc_mimeparser_t, key: &str) -> *const libc::c_char {
@@ -847,11 +849,11 @@ unsafe fn could_not_establish_secure_connection(
details: *const libc::c_char, details: *const libc::c_char,
) { ) {
let contact_id: uint32_t = chat_id_2_contact_id(context, contact_chat_id); let contact_id: uint32_t = chat_id_2_contact_id(context, contact_chat_id);
let contact = dc_get_contact(context, contact_id); let contact = Contact::get_by_id(context, contact_id);
let msg = context.stock_string_repl_str( let msg = context.stock_string_repl_str(
StockMessage::ContactNotVerified, StockMessage::ContactNotVerified,
if !contact.is_null() { if let Ok(ref contact) = contact {
as_str((*contact).addr) contact.get_addr()
} else { } else {
"?" "?"
}, },
@@ -859,7 +861,6 @@ unsafe fn could_not_establish_secure_connection(
let msg_c = CString::new(msg.as_str()).unwrap(); let msg_c = CString::new(msg.as_str()).unwrap();
dc_add_device_msg(context, contact_chat_id, msg_c.as_ptr()); dc_add_device_msg(context, contact_chat_id, msg_c.as_ptr());
error!(context, 0, "{} ({})", msg, as_str(details)); error!(context, 0, "{} ({})", msg, as_str(details));
dc_contact_unref(contact);
} }
unsafe fn mark_peer_as_verified( unsafe fn mark_peer_as_verified(

View File

@@ -1,6 +1,5 @@
use crate::dc_dehtml::*; use crate::dc_dehtml::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::types::*;
use crate::x::*; use crate::x::*;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@@ -20,6 +19,9 @@ impl dc_simplify_t {
} }
} }
/// Simplify and normalise text: Remove quotes, signatures, unnecessary
/// lineends etc.
/// The data returned from simplify() must be free()'d when no longer used.
pub unsafe fn simplify( pub unsafe fn simplify(
&mut self, &mut self,
in_unterminated: *const libc::c_char, in_unterminated: *const libc::c_char,
@@ -27,6 +29,10 @@ impl dc_simplify_t {
is_html: libc::c_int, is_html: libc::c_int,
is_msgrmsg: libc::c_int, is_msgrmsg: libc::c_int,
) -> *mut libc::c_char { ) -> *mut libc::c_char {
if in_bytes <= 0 {
return "".strdup();
}
/* create a copy of the given buffer */ /* create a copy of the given buffer */
let mut out: *mut libc::c_char; let mut out: *mut libc::c_char;
let mut temp: *mut libc::c_char; let mut temp: *mut libc::c_char;
@@ -73,17 +79,13 @@ impl dc_simplify_t {
these are all lines starting with the character `>` these are all lines starting with the character `>`
... remove a non-empty line before the removed quote (contains sth. like "On 2.9.2016, Bjoern wrote:" in different formats and lanugages) */ ... remove a non-empty line before the removed quote (contains sth. like "On 2.9.2016, Bjoern wrote:" in different formats and lanugages) */
/* split the given buffer into lines */ /* split the given buffer into lines */
let lines: *mut carray = dc_split_into_lines(buf_terminated); let lines = dc_split_into_lines(buf_terminated);
let mut l: libc::c_int; let mut l_first: usize = 0;
let mut l_first: libc::c_int = 0i32; let mut l_last = lines.len();
/* if l_last is -1, there are no lines */
let mut l_last: libc::c_int =
carray_count(lines).wrapping_sub(1i32 as libc::c_uint) as libc::c_int;
let mut line: *mut libc::c_char; let mut line: *mut libc::c_char;
let mut footer_mark: libc::c_int = 0i32; let mut footer_mark: libc::c_int = 0i32;
l = l_first; for l in l_first..l_last {
while l <= l_last { line = lines[l];
line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char;
if strcmp(line, b"-- \x00" as *const u8 as *const libc::c_char) == 0i32 if strcmp(line, b"-- \x00" as *const u8 as *const libc::c_char) == 0i32
|| strcmp(line, b"-- \x00" as *const u8 as *const libc::c_char) == 0i32 || strcmp(line, b"-- \x00" as *const u8 as *const libc::c_char) == 0i32
{ {
@@ -97,20 +99,15 @@ impl dc_simplify_t {
self.is_cut_at_end = 1i32 self.is_cut_at_end = 1i32
} }
if 0 != footer_mark { if 0 != footer_mark {
l_last = l - 1i32; l_last = l;
/* done */ /* done */
break; break;
} else {
l += 1
} }
} }
if l_last - l_first + 1i32 >= 3i32 { if l_last > l_first + 2 {
let line0: *mut libc::c_char = let line0: *mut libc::c_char = lines[l_first];
carray_get(lines, l_first as libc::c_uint) as *mut libc::c_char; let line1: *mut libc::c_char = lines[l_first + 1];
let line1: *mut libc::c_char = let line2: *mut libc::c_char = lines[l_first + 2];
carray_get(lines, (l_first + 1i32) as libc::c_uint) as *mut libc::c_char;
let line2: *mut libc::c_char =
carray_get(lines, (l_first + 2i32) as libc::c_uint) as *mut libc::c_char;
if strcmp( if strcmp(
line0, line0,
b"---------- Forwarded message ----------\x00" as *const u8 as *const libc::c_char, b"---------- Forwarded message ----------\x00" as *const u8 as *const libc::c_char,
@@ -119,49 +116,43 @@ impl dc_simplify_t {
&& *line2.offset(0isize) as libc::c_int == 0i32 && *line2.offset(0isize) as libc::c_int == 0i32
{ {
self.is_forwarded = 1i32; self.is_forwarded = 1i32;
l_first += 3i32 l_first += 3
} }
} }
l = l_first; for l in l_first..l_last {
while l <= l_last { line = lines[l];
line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char;
if strncmp(line, b"-----\x00" as *const u8 as *const libc::c_char, 5) == 0i32 if strncmp(line, b"-----\x00" as *const u8 as *const libc::c_char, 5) == 0i32
|| strncmp(line, b"_____\x00" as *const u8 as *const libc::c_char, 5) == 0i32 || strncmp(line, b"_____\x00" as *const u8 as *const libc::c_char, 5) == 0i32
|| strncmp(line, b"=====\x00" as *const u8 as *const libc::c_char, 5) == 0i32 || strncmp(line, b"=====\x00" as *const u8 as *const libc::c_char, 5) == 0i32
|| strncmp(line, b"*****\x00" as *const u8 as *const libc::c_char, 5) == 0i32 || strncmp(line, b"*****\x00" as *const u8 as *const libc::c_char, 5) == 0i32
|| strncmp(line, b"~~~~~\x00" as *const u8 as *const libc::c_char, 5) == 0i32 || strncmp(line, b"~~~~~\x00" as *const u8 as *const libc::c_char, 5) == 0i32
{ {
l_last = l - 1i32; l_last = l;
self.is_cut_at_end = 1i32; self.is_cut_at_end = 1i32;
/* done */ /* done */
break; break;
} else {
l += 1
} }
} }
if 0 == is_msgrmsg { if 0 == is_msgrmsg {
let mut l_lastQuotedLine: libc::c_int = -1i32; let mut l_lastQuotedLine = None;
l = l_last; for l in (l_first..l_last).rev() {
while l >= l_first { line = lines[l];
line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char;
if is_plain_quote(line) { if is_plain_quote(line) {
l_lastQuotedLine = l l_lastQuotedLine = Some(l)
} else if !is_empty_line(line) { } else if !is_empty_line(line) {
break; break;
} }
l -= 1
} }
if l_lastQuotedLine != -1i32 { if l_lastQuotedLine.is_some() {
l_last = l_lastQuotedLine - 1i32; l_last = l_lastQuotedLine.unwrap();
self.is_cut_at_end = 1i32; self.is_cut_at_end = 1i32;
if l_last > 0i32 { if l_last > 1 {
if is_empty_line(carray_get(lines, l_last as libc::c_uint) as *mut libc::c_char) if is_empty_line(lines[l_last - 1]) {
{
l_last -= 1 l_last -= 1
} }
} }
if l_last > 0i32 { if l_last > 1 {
line = carray_get(lines, l_last as libc::c_uint) as *mut libc::c_char; line = lines[l_last - 1];
if is_quoted_headline(line) { if is_quoted_headline(line) {
l_last -= 1 l_last -= 1
} }
@@ -169,17 +160,16 @@ impl dc_simplify_t {
} }
} }
if 0 == is_msgrmsg { if 0 == is_msgrmsg {
let mut l_lastQuotedLine_0: libc::c_int = -1i32; let mut l_lastQuotedLine_0 = None;
let mut hasQuotedHeadline: libc::c_int = 0i32; let mut hasQuotedHeadline = 0;
l = l_first; for l in l_first..l_last {
while l <= l_last { line = lines[l];
line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char;
if is_plain_quote(line) { if is_plain_quote(line) {
l_lastQuotedLine_0 = l l_lastQuotedLine_0 = Some(l)
} else if !is_empty_line(line) { } else if !is_empty_line(line) {
if is_quoted_headline(line) if is_quoted_headline(line)
&& 0 == hasQuotedHeadline && 0 == hasQuotedHeadline
&& l_lastQuotedLine_0 == -1i32 && l_lastQuotedLine_0.is_none()
{ {
hasQuotedHeadline = 1i32 hasQuotedHeadline = 1i32
} else { } else {
@@ -187,10 +177,9 @@ impl dc_simplify_t {
break; break;
} }
} }
l += 1
} }
if l_lastQuotedLine_0 != -1i32 { if l_lastQuotedLine_0.is_some() {
l_first = l_lastQuotedLine_0 + 1i32; l_first = l_lastQuotedLine_0.unwrap() + 1;
self.is_cut_at_begin = 1i32 self.is_cut_at_begin = 1i32
} }
} }
@@ -202,9 +191,8 @@ impl dc_simplify_t {
/* we write empty lines only in case and non-empty line follows */ /* we write empty lines only in case and non-empty line follows */
let mut pending_linebreaks: libc::c_int = 0i32; let mut pending_linebreaks: libc::c_int = 0i32;
let mut content_lines_added: libc::c_int = 0i32; let mut content_lines_added: libc::c_int = 0i32;
l = l_first; for l in l_first..l_last {
while l <= l_last { line = lines[l];
line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char;
if is_empty_line(line) { if is_empty_line(line) {
pending_linebreaks += 1 pending_linebreaks += 1
} else { } else {
@@ -222,33 +210,16 @@ impl dc_simplify_t {
content_lines_added += 1; content_lines_added += 1;
pending_linebreaks = 1i32 pending_linebreaks = 1i32
} }
l += 1
} }
if 0 != self.is_cut_at_end && (0 == self.is_cut_at_begin || 0 != content_lines_added) { if 0 != self.is_cut_at_end && (0 == self.is_cut_at_begin || 0 != content_lines_added) {
ret += " [...]"; ret += " [...]";
} }
dc_free_splitted_lines(lines); dc_free_splitted_lines(lines);
to_cstring(ret) ret.strdup()
} }
} }
/* Simplify and normalise text: Remove quotes, signatures, unnecessary
lineends etc.
The data returned from Simplify() must be free()'d when no longer used, private */
pub unsafe fn dc_simplify_simplify(
simplify: *mut dc_simplify_t,
in_unterminated: *const libc::c_char,
in_bytes: libc::c_int,
is_html: libc::c_int,
is_msgrmsg: libc::c_int,
) -> *mut libc::c_char {
if simplify.is_null() || in_unterminated.is_null() || in_bytes <= 0i32 {
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
}
(*simplify).simplify(in_unterminated, in_bytes, is_html, is_msgrmsg)
}
/** /**
* Tools * Tools
*/ */

View File

@@ -1,4 +1,4 @@
use std::ffi::CStr; use std::ffi::{CStr, CString};
use charset::Charset; use charset::Charset;
use mmime::mailmime_decode::*; use mmime::mailmime_decode::*;
@@ -120,97 +120,90 @@ fn hex_2_int(ch: libc::c_char) -> libc::c_char {
} }
pub unsafe fn dc_encode_header_words(to_encode: *const libc::c_char) -> *mut libc::c_char { pub unsafe fn dc_encode_header_words(to_encode: *const libc::c_char) -> *mut libc::c_char {
let mut current_block: u64; let mut ok_to_continue = true;
let mut ret_str: *mut libc::c_char = 0 as *mut libc::c_char; let mut ret_str: *mut libc::c_char = 0 as *mut libc::c_char;
let mut cur: *const libc::c_char = to_encode; let mut cur: *const libc::c_char = to_encode;
let mmapstr: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char); let mmapstr: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
if to_encode.is_null() || mmapstr.is_null() { if to_encode.is_null() || mmapstr.is_null() {
current_block = 8550051112593613029; ok_to_continue = false;
} else {
current_block = 4644295000439058019;
} }
loop { loop {
match current_block { if !ok_to_continue {
8550051112593613029 => { if !mmapstr.is_null() {
if !mmapstr.is_null() { mmap_string_free(mmapstr);
mmap_string_free(mmapstr);
}
break;
} }
_ => { break;
if *cur as libc::c_int != '\u{0}' as i32 { } else {
let begin: *const libc::c_char; if *cur as libc::c_int != '\u{0}' as i32 {
let mut end: *const libc::c_char; let begin: *const libc::c_char;
let mut do_quote: bool; let mut end: *const libc::c_char;
let mut quote_words: libc::c_int; let mut do_quote: bool;
begin = cur; let mut quote_words: libc::c_int;
end = begin; begin = cur;
quote_words = 0i32; end = begin;
do_quote = true; quote_words = 0i32;
while *cur as libc::c_int != '\u{0}' as i32 { do_quote = true;
get_word(cur, &mut cur, &mut do_quote); while *cur as libc::c_int != '\u{0}' as i32 {
if !do_quote { get_word(cur, &mut cur, &mut do_quote);
break; if !do_quote {
} break;
quote_words = 1i32;
end = cur;
if *cur as libc::c_int != '\u{0}' as i32 {
cur = cur.offset(1isize)
}
} }
if 0 != quote_words { quote_words = 1i32;
if !quote_word( end = cur;
b"utf-8\x00" as *const u8 as *const libc::c_char, if *cur as libc::c_int != '\u{0}' as i32 {
mmapstr, cur = cur.offset(1isize)
begin, }
end.wrapping_offset_from(begin) as size_t, }
) { if 0 != quote_words {
current_block = 8550051112593613029; if !quote_word(
continue; b"utf-8\x00" as *const u8 as *const libc::c_char,
}
if *end as libc::c_int == ' ' as i32 || *end as libc::c_int == '\t' as i32 {
if mmap_string_append_c(mmapstr, *end).is_null() {
current_block = 8550051112593613029;
continue;
}
end = end.offset(1isize)
}
if *end as libc::c_int != '\u{0}' as i32 {
if mmap_string_append_len(
mmapstr,
end,
cur.wrapping_offset_from(end) as size_t,
)
.is_null()
{
current_block = 8550051112593613029;
continue;
}
}
} else if mmap_string_append_len(
mmapstr, mmapstr,
begin, begin,
cur.wrapping_offset_from(begin) as size_t, end.wrapping_offset_from(begin) as size_t,
) ) {
.is_null() ok_to_continue = false;
{
current_block = 8550051112593613029;
continue; continue;
} }
if !(*cur as libc::c_int == ' ' as i32 || *cur as libc::c_int == '\t' as i32) { if *end as libc::c_int == ' ' as i32 || *end as libc::c_int == '\t' as i32 {
current_block = 4644295000439058019; if mmap_string_append_c(mmapstr, *end).is_null() {
continue; ok_to_continue = false;
continue;
}
end = end.offset(1isize)
} }
if mmap_string_append_c(mmapstr, *cur).is_null() { if *end as libc::c_int != '\u{0}' as i32 {
current_block = 8550051112593613029; if mmap_string_append_len(
continue; mmapstr,
end,
cur.wrapping_offset_from(end) as size_t,
)
.is_null()
{
ok_to_continue = false;
continue;
}
} }
cur = cur.offset(1isize); } else if mmap_string_append_len(
current_block = 4644295000439058019; mmapstr,
} else { begin,
ret_str = strdup((*mmapstr).str_0); cur.wrapping_offset_from(begin) as size_t,
current_block = 8550051112593613029; )
.is_null()
{
ok_to_continue = false;
continue;
} }
if !(*cur as libc::c_int == ' ' as i32 || *cur as libc::c_int == '\t' as i32) {
continue;
}
if mmap_string_append_c(mmapstr, *cur).is_null() {
ok_to_continue = false;
continue;
}
cur = cur.offset(1isize);
} else {
ret_str = strdup((*mmapstr).str_0);
ok_to_continue = false;
} }
} }
} }
@@ -710,9 +703,8 @@ unsafe fn print_hex(target: *mut libc::c_char, cur: *const libc::c_char) {
assert!(!cur.is_null()); assert!(!cur.is_null());
let bytes = std::slice::from_raw_parts(cur as *const _, strlen(cur)); let bytes = std::slice::from_raw_parts(cur as *const _, strlen(cur));
let raw = to_cstring(format!("={}", &hex::encode_upper(bytes)[..2])); let raw = CString::yolo(format!("={}", &hex::encode_upper(bytes)[..2]));
libc::memcpy(target as *mut _, raw as *const _, 4); libc::memcpy(target as *mut _, raw.as_ptr() as *const _, 4);
free(raw as *mut libc::c_void);
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -42,7 +42,7 @@ pub fn dc_token_lookup(
params![namespc as i32, foreign_id as i32], params![namespc as i32, foreign_id as i32],
0, 0,
) )
.map(|s| unsafe { to_cstring(s) }) .map(|s| unsafe { s.strdup() })
.unwrap_or_else(|| std::ptr::null_mut()) .unwrap_or_else(|| std::ptr::null_mut())
} }

View File

@@ -17,7 +17,6 @@ const ELLIPSE: &'static str = "[...]";
/* Some tools and enhancements to the used libraries, there should be /* Some tools and enhancements to the used libraries, there should be
no references to Context and other "larger" classes here. */ no references to Context and other "larger" classes here. */
// for carray etc.
/* ** library-private **********************************************************/ /* ** library-private **********************************************************/
/* math tools */ /* math tools */
pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool { pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
@@ -178,14 +177,13 @@ pub unsafe fn dc_trim(buf: *mut libc::c_char) {
/* the result must be free()'d */ /* the result must be free()'d */
pub unsafe fn dc_strlower(in_0: *const libc::c_char) -> *mut libc::c_char { pub unsafe fn dc_strlower(in_0: *const libc::c_char) -> *mut libc::c_char {
to_cstring(to_string(in_0).to_lowercase()) to_string(in_0).to_lowercase().strdup()
} }
pub unsafe fn dc_strlower_in_place(in_0: *mut libc::c_char) { pub unsafe fn dc_strlower_in_place(in_0: *mut libc::c_char) {
let raw = to_cstring(to_string(in_0).to_lowercase()); let raw = CString::yolo(to_string(in_0).to_lowercase());
assert_eq!(strlen(in_0), strlen(raw)); assert_eq!(strlen(in_0), strlen(raw.as_ptr()));
memcpy(in_0 as *mut _, raw as *const _, strlen(in_0)); memcpy(in_0 as *mut _, raw.as_ptr() as *const _, strlen(in_0));
free(raw as *mut _);
} }
pub unsafe fn dc_str_contains( pub unsafe fn dc_str_contains(
@@ -233,7 +231,7 @@ pub unsafe fn dc_binary_to_uc_hex(buf: *const uint8_t, bytes: size_t) -> *mut li
let buf = std::slice::from_raw_parts(buf, bytes); let buf = std::slice::from_raw_parts(buf, bytes);
let raw = hex::encode_upper(buf); let raw = hex::encode_upper(buf);
to_cstring(raw) raw.strdup()
} }
/* remove all \r characters from string */ /* remove all \r characters from string */
@@ -263,8 +261,9 @@ pub unsafe fn dc_unify_lineends(buf: *mut libc::c_char) {
} }
/* replace bad UTF-8 characters by sequences of `_` (to avoid problems in filenames, we do not use eg. `?`) the function is useful if strings are unexpectingly encoded eg. as ISO-8859-1 */ /* replace bad UTF-8 characters by sequences of `_` (to avoid problems in filenames, we do not use eg. `?`) the function is useful if strings are unexpectingly encoded eg. as ISO-8859-1 */
#[allow(non_snake_case)]
pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) { pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) {
let current_block: u64; let mut OK_TO_CONTINUE = true;
if buf.is_null() { if buf.is_null() {
return; return;
} }
@@ -280,7 +279,6 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) {
ix = p1len; ix = p1len;
's_36: loop { 's_36: loop {
if !(i < ix) { if !(i < ix) {
current_block = 13550086250199790493;
break; break;
} }
c = *p1.offset(i as isize) as libc::c_int; c = *p1.offset(i as isize) as libc::c_int;
@@ -293,7 +291,7 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) {
&& *p1.offset((i + 1i32) as isize) as libc::c_int & 0xa0i32 == 0xa0i32 && *p1.offset((i + 1i32) as isize) as libc::c_int & 0xa0i32 == 0xa0i32
{ {
/* U+d800 to U+dfff */ /* U+d800 to U+dfff */
current_block = 2775201239069267972; OK_TO_CONTINUE = false;
break; break;
} else if c & 0xf0i32 == 0xe0i32 { } else if c & 0xf0i32 == 0xe0i32 {
n = 2i32 n = 2i32
@@ -302,7 +300,7 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) {
} else { } else {
//else if ((c & 0xFC) == 0xF8) { n=4; } /* 111110bb - not valid in https://tools.ietf.org/html/rfc3629 */ //else if ((c & 0xFC) == 0xF8) { n=4; } /* 111110bb - not valid in https://tools.ietf.org/html/rfc3629 */
//else if ((c & 0xFE) == 0xFC) { n=5; } /* 1111110b - not valid in https://tools.ietf.org/html/rfc3629 */ //else if ((c & 0xFE) == 0xFC) { n=5; } /* 1111110b - not valid in https://tools.ietf.org/html/rfc3629 */
current_block = 2775201239069267972; OK_TO_CONTINUE = false;
break; break;
} }
j = 0i32; j = 0i32;
@@ -310,25 +308,22 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) {
/* n bytes matching 10bbbbbb follow ? */ /* n bytes matching 10bbbbbb follow ? */
i += 1; i += 1;
if i == ix || *p1.offset(i as isize) as libc::c_int & 0xc0i32 != 0x80i32 { if i == ix || *p1.offset(i as isize) as libc::c_int & 0xc0i32 != 0x80i32 {
current_block = 2775201239069267972; OK_TO_CONTINUE = false;
break 's_36; break 's_36;
} }
j += 1 j += 1
} }
i += 1 i += 1
} }
match current_block { if OK_TO_CONTINUE == false {
13550086250199790493 => return, while 0 != *p1 {
_ => { if *p1 as libc::c_int > 0x7fi32 {
while 0 != *p1 { *p1 = '_' as i32 as libc::c_uchar
if *p1 as libc::c_int > 0x7fi32 {
*p1 = '_' as i32 as libc::c_uchar
}
p1 = p1.offset(1isize)
} }
return; p1 = p1.offset(1isize)
} }
}; return;
}
} }
pub unsafe fn dc_utf8_strlen(s: *const libc::c_char) -> size_t { pub unsafe fn dc_utf8_strlen(s: *const libc::c_char) -> size_t {
@@ -421,47 +416,30 @@ unsafe fn dc_utf8_strnlen(s: *const libc::c_char, n: size_t) -> size_t {
} }
/* split string into lines*/ /* split string into lines*/
pub unsafe fn dc_split_into_lines(buf_terminated: *const libc::c_char) -> *mut carray { pub unsafe fn dc_split_into_lines(buf_terminated: *const libc::c_char) -> Vec<*mut libc::c_char> {
let lines: *mut carray = carray_new(1024i32 as libc::c_uint); let mut lines = Vec::new();
let mut line_chars = 0; let mut line_chars = 0;
let mut p1: *const libc::c_char = buf_terminated; let mut p1: *const libc::c_char = buf_terminated;
let mut line_start: *const libc::c_char = p1; let mut line_start: *const libc::c_char = p1;
let mut l_indx: libc::c_uint = 0i32 as libc::c_uint;
while 0 != *p1 { while 0 != *p1 {
if *p1 as libc::c_int == '\n' as i32 { if *p1 as libc::c_int == '\n' as i32 {
carray_add( lines.push(strndup(line_start, line_chars));
lines,
strndup(line_start, line_chars) as *mut libc::c_void,
&mut l_indx,
);
p1 = p1.offset(1isize); p1 = p1.offset(1isize);
line_start = p1; line_start = p1;
line_chars = 0; line_chars = 0;
} else { } else {
p1 = p1.offset(1isize); p1 = p1.offset(1isize);
line_chars = line_chars.wrapping_add(1) line_chars += 1;
} }
} }
carray_add( lines.push(strndup(line_start, line_chars));
lines,
strndup(line_start, line_chars) as *mut libc::c_void,
&mut l_indx,
);
lines lines
} }
pub unsafe fn dc_free_splitted_lines(lines: *mut carray) { pub unsafe fn dc_free_splitted_lines(lines: Vec<*mut libc::c_char>) {
if !lines.is_null() { for s in lines {
let mut i: libc::c_int; free(s as *mut libc::c_void);
let cnt: libc::c_int = carray_count(lines) as libc::c_int; }
i = 0i32;
while i < cnt {
free(carray_get(lines, i as libc::c_uint));
i += 1
}
carray_free(lines);
};
} }
/* insert a break every n characters, the return must be free()'d */ /* insert a break every n characters, the return must be free()'d */
@@ -530,7 +508,7 @@ pub unsafe fn dc_str_from_clist(
} }
} }
to_cstring(res) res.strdup()
} }
pub unsafe fn dc_str_to_clist( pub unsafe fn dc_str_to_clist(
@@ -561,32 +539,32 @@ pub unsafe fn dc_str_to_clist(
list list
} }
/* the colors must fulfill some criterions as:
- contrast to black and to white
- work as a text-color
- being noticeable on a typical map
- harmonize together while being different enough
(therefore, we cannot just use random rgb colors :) */
const COLORS: [u32; 16] = [
0xe56555, 0xf28c48, 0x8e85ee, 0x76c84d, 0x5bb6cc, 0x549cdd, 0xd25c99, 0xb37800, 0xf23030,
0x39b249, 0xbb243b, 0x964078, 0x66874f, 0x308ab9, 0x127ed0, 0xbe450c,
];
pub fn dc_str_to_color_safe(s: impl AsRef<str>) -> u32 {
let str_lower = s.as_ref().to_lowercase();
let mut checksum = 0;
let bytes = str_lower.as_bytes();
for i in 0..str_lower.len() {
checksum += (i + 1) * bytes[i] as usize;
checksum %= 0xffffff;
}
let color_index = checksum % COLORS.len();
COLORS[color_index]
}
pub unsafe fn dc_str_to_color(str: *const libc::c_char) -> libc::c_int { pub unsafe fn dc_str_to_color(str: *const libc::c_char) -> libc::c_int {
let str_lower: *mut libc::c_char = dc_strlower(str); let str_lower: *mut libc::c_char = dc_strlower(str);
/* the colors must fulfill some criterions as:
- contrast to black and to white
- work as a text-color
- being noticeable on a typical map
- harmonize together while being different enough
(therefore, we cannot just use random rgb colors :) */
static mut COLORS: [uint32_t; 16] = [
0xe56555i32 as uint32_t,
0xf28c48i32 as uint32_t,
0x8e85eei32 as uint32_t,
0x76c84di32 as uint32_t,
0x5bb6cci32 as uint32_t,
0x549cddi32 as uint32_t,
0xd25c99i32 as uint32_t,
0xb37800i32 as uint32_t,
0xf23030i32 as uint32_t,
0x39b249i32 as uint32_t,
0xbb243bi32 as uint32_t,
0x964078i32 as uint32_t,
0x66874fi32 as uint32_t,
0x308ab9i32 as uint32_t,
0x127ed0i32 as uint32_t,
0xbe450ci32 as uint32_t,
];
let mut checksum: libc::c_int = 0i32; let mut checksum: libc::c_int = 0i32;
let str_len: libc::c_int = strlen(str_lower) as libc::c_int; let str_len: libc::c_int = strlen(str_lower) as libc::c_int;
let mut i: libc::c_int = 0i32; let mut i: libc::c_int = 0i32;
@@ -669,13 +647,7 @@ pub unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
* date/time tools * date/time tools
******************************************************************************/ ******************************************************************************/
/* the return value must be free()'d */ pub fn dc_timestamp_to_str(wanted: i64) -> String {
pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char {
let res = dc_timestamp_to_str_safe(wanted);
to_cstring(res)
}
pub fn dc_timestamp_to_str_safe(wanted: i64) -> String {
let ts = chrono::Utc.timestamp(wanted, 0); let ts = chrono::Utc.timestamp(wanted, 0);
ts.format("%Y.%m.%d %H:%M:%S").to_string() ts.format("%Y.%m.%d %H:%M:%S").to_string()
} }
@@ -726,7 +698,7 @@ pub unsafe fn dc_create_smeared_timestamps(context: &Context, count: libc::c_int
} }
/* Message-ID tools */ /* Message-ID tools */
pub unsafe fn dc_create_id() -> *mut libc::c_char { pub fn dc_create_id() -> String {
/* generate an id. the generated ID should be as short and as unique as possible: /* generate an id. the generated ID should be as short and as unique as possible:
- short, because it may also used as part of Message-ID headers or in QR codes - short, because it may also used as part of Message-ID headers or in QR codes
- unique as two IDs generated on two devices should not be the same. However, collisions are not world-wide but only by the few contacts. - unique as two IDs generated on two devices should not be the same. However, collisions are not world-wide but only by the few contacts.
@@ -744,39 +716,26 @@ pub unsafe fn dc_create_id() -> *mut libc::c_char {
encode_66bits_as_base64(buf[0usize], buf[1usize], buf[2usize]) encode_66bits_as_base64(buf[0usize], buf[1usize], buf[2usize])
} }
/* ****************************************************************************** /// Encode 66 bits as a base64 string.
* generate Message-IDs /// This is useful for ID generating with short strings as we save 5 character
******************************************************************************/ /// in each id compared to 64 bit hex encoding. For a typical group ID, these
unsafe fn encode_66bits_as_base64(v1: uint32_t, v2: uint32_t, fill: uint32_t) -> *mut libc::c_char { /// are 10 characters (grpid+msgid):
/* encode 66 bits as a base64 string. This is useful for ID generating with short strings as /// hex: 64 bit, 4 bits/character, length = 64/4 = 16 characters
we save 5 character in each id compared to 64 bit hex encoding, for a typical group ID, these are 10 characters (grpid+msgid): /// base64: 64 bit, 6 bits/character, length = 64/6 = 11 characters (plus 2 additional bits)
hex: 64 bit, 4 bits/character, length = 64/4 = 16 characters /// Only the lower 2 bits of `fill` are used.
base64: 64 bit, 6 bits/character, length = 64/6 = 11 characters (plus 2 additional bits) */ fn encode_66bits_as_base64(v1: u32, v2: u32, fill: u32) -> String {
let ret: *mut libc::c_char = malloc(12) as *mut libc::c_char; use byteorder::{BigEndian, WriteBytesExt};
assert!(!ret.is_null());
static mut CHARS: [libc::c_char; 65] = [ let mut wrapped_writer = Vec::new();
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, {
88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, let mut enc = base64::write::EncoderWriter::new(&mut wrapped_writer, base64::URL_SAFE);
113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, enc.write_u32::<BigEndian>(v1).unwrap();
45, 95, 0, enc.write_u32::<BigEndian>(v2).unwrap();
]; enc.write_u8(((fill & 0x3) as u8) << 6).unwrap();
*ret.offset(0isize) = CHARS[(v1 >> 26i32 & 0x3fi32 as libc::c_uint) as usize]; enc.finish().unwrap();
*ret.offset(1isize) = CHARS[(v1 >> 20i32 & 0x3fi32 as libc::c_uint) as usize]; }
*ret.offset(2isize) = CHARS[(v1 >> 14i32 & 0x3fi32 as libc::c_uint) as usize]; assert_eq!(wrapped_writer.pop(), Some('A' as u8)); // Remove last "A"
*ret.offset(3isize) = CHARS[(v1 >> 8i32 & 0x3fi32 as libc::c_uint) as usize]; String::from_utf8(wrapped_writer).unwrap()
*ret.offset(4isize) = CHARS[(v1 >> 2i32 & 0x3fi32 as libc::c_uint) as usize];
*ret.offset(5isize) = CHARS
[(v1 << 4i32 & 0x30i32 as libc::c_uint | v2 >> 28i32 & 0xfi32 as libc::c_uint) as usize];
*ret.offset(6isize) = CHARS[(v2 >> 22i32 & 0x3fi32 as libc::c_uint) as usize];
*ret.offset(7isize) = CHARS[(v2 >> 16i32 & 0x3fi32 as libc::c_uint) as usize];
*ret.offset(8isize) = CHARS[(v2 >> 10i32 & 0x3fi32 as libc::c_uint) as usize];
*ret.offset(9isize) = CHARS[(v2 >> 4i32 & 0x3fi32 as libc::c_uint) as usize];
*ret.offset(10isize) =
CHARS[(v2 << 2i32 & 0x3ci32 as libc::c_uint | fill & 0x3i32 as libc::c_uint) as usize];
*ret.offset(11isize) = 0i32 as libc::c_char;
ret
} }
pub unsafe fn dc_create_incoming_rfc724_mid( pub unsafe fn dc_create_incoming_rfc724_mid(
@@ -816,7 +775,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid(
- the message ID should be globally unique - the message ID should be globally unique
- do not add a counter or any private data as as this may give unneeded information to the receiver */ - do not add a counter or any private data as as this may give unneeded information to the receiver */
let mut rand1: *mut libc::c_char = 0 as *mut libc::c_char; let mut rand1: *mut libc::c_char = 0 as *mut libc::c_char;
let rand2: *mut libc::c_char = dc_create_id(); let rand2: *mut libc::c_char = dc_create_id().strdup();
let ret: *mut libc::c_char; let ret: *mut libc::c_char;
let mut at_hostname: *const libc::c_char = strchr(from_addr, '@' as i32); let mut at_hostname: *const libc::c_char = strchr(from_addr, '@' as i32);
if at_hostname.is_null() { if at_hostname.is_null() {
@@ -830,7 +789,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid(
at_hostname, at_hostname,
) )
} else { } else {
rand1 = dc_create_id(); rand1 = dc_create_id().strdup();
ret = dc_mprintf( ret = dc_mprintf(
b"Mr.%s.%s%s\x00" as *const u8 as *const libc::c_char, b"Mr.%s.%s%s\x00" as *const u8 as *const libc::c_char,
rand1, rand1,
@@ -844,52 +803,49 @@ pub unsafe fn dc_create_outgoing_rfc724_mid(
ret ret
} }
pub unsafe fn dc_extract_grpid_from_rfc724_mid(mid: *const libc::c_char) -> *mut libc::c_char { /// Extract the group id (grpid) from a message id (mid)
/* extract our group ID from Message-IDs as `Gr.12345678901.morerandom@domain.de`; "12345678901" is the wanted ID in this example. */ ///
let mut success: libc::c_int = 0i32; /// # Arguments
let mut grpid: *mut libc::c_char = 0 as *mut libc::c_char; ///
let p1: *mut libc::c_char; /// * `mid` - A string that holds the message id
let grpid_len: libc::c_int; ///
if !(mid.is_null() /// # Examples
|| strlen(mid) < 8 ///
|| *mid.offset(0isize) as libc::c_int != 'G' as i32 /// ```
|| *mid.offset(1isize) as libc::c_int != 'r' as i32 /// use deltachat::dc_tools::dc_extract_grpid_from_rfc724_mid;
|| *mid.offset(2isize) as libc::c_int != '.' as i32) /// let mid = "Gr.12345678901.morerandom@domain.de";
{ /// let grpid = dc_extract_grpid_from_rfc724_mid(mid);
grpid = dc_strdup(&*mid.offset(3isize)); /// assert_eq!(grpid, Some("12345678901"));
p1 = strchr(grpid, '.' as i32); /// ```
if !p1.is_null() { pub fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> {
*p1 = 0i32 as libc::c_char; if mid.len() < 9 || !mid.starts_with("Gr.") {
grpid_len = strlen(grpid) as libc::c_int; return None;
if !(grpid_len != 11i32 && grpid_len != 16i32) { }
/* strict length comparison, the 'Gr.' magic is weak enough */
success = 1i32 if let Some(mid_without_offset) = mid.get(3..) {
if let Some(grpid_len) = mid_without_offset.find('.') {
/* strict length comparison, the 'Gr.' magic is weak enough */
if grpid_len == 11 || grpid_len == 16 {
return Some(mid_without_offset.get(0..grpid_len).unwrap());
} }
} }
} }
if success == 0i32 {
free(grpid as *mut libc::c_void); None
grpid = 0 as *mut libc::c_char
}
return if 0 != success {
grpid
} else {
0 as *mut libc::c_char
};
} }
pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut libc::c_char { pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut libc::c_char {
if !list.is_null() { if !list.is_null() {
let mut cur: *mut clistiter = (*list).first; let mut cur: *mut clistiter = (*list).first;
while !cur.is_null() { while !cur.is_null() {
let mid: *const libc::c_char = (if !cur.is_null() { let mid = if !cur.is_null() {
(*cur).data as_str((*cur).data as *const libc::c_char)
} else { } else {
0 as *mut libc::c_void ""
}) as *const libc::c_char; };
let grpid: *mut libc::c_char = dc_extract_grpid_from_rfc724_mid(mid);
if !grpid.is_null() { if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(mid) {
return grpid; return grpid.strdup();
} }
cur = if !cur.is_null() { cur = if !cur.is_null() {
(*cur).next (*cur).next
@@ -1080,6 +1036,26 @@ pub unsafe fn dc_get_filemeta(
0 0
} }
/// Expand paths relative to $BLOBDIR into absolute paths.
///
/// If `path` starts with "$BLOBDIR", replaces it with the blobdir path.
/// Otherwise, returns path as is.
pub fn dc_get_abs_path_safe<P: AsRef<std::path::Path>>(
context: &Context,
path: P,
) -> std::path::PathBuf {
let p: &std::path::Path = path.as_ref();
if let Ok(p) = p.strip_prefix("$BLOBDIR") {
assert!(
context.has_blobdir(),
"Expected context to have blobdir to substitute $BLOBDIR",
);
std::path::PathBuf::from(as_str(context.get_blobdir())).join(p)
} else {
p.into()
}
}
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub unsafe fn dc_get_abs_path( pub unsafe fn dc_get_abs_path(
context: &Context, context: &Context,
@@ -1110,137 +1086,79 @@ pub unsafe fn dc_get_abs_path(
pathNfilename_abs pathNfilename_abs
} }
#[allow(non_snake_case)] pub fn dc_file_exist(context: &Context, path: *const libc::c_char) -> libc::c_int {
pub unsafe fn dc_file_exist(context: &Context, pathNfilename: *const libc::c_char) -> libc::c_int { dc_get_abs_path_safe(context, as_path(path)).exists() as libc::c_int
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
if pathNfilename_abs.is_null() {
return 0;
}
let exist = {
let p = std::path::Path::new(as_str(pathNfilename_abs));
p.exists()
};
free(pathNfilename_abs as *mut libc::c_void);
exist as libc::c_int
} }
#[allow(non_snake_case)] pub fn dc_get_filebytes(context: &Context, path: *const libc::c_char) -> uint64_t {
pub unsafe fn dc_get_filebytes(context: &Context, pathNfilename: *const libc::c_char) -> uint64_t { let path_abs = dc_get_abs_path_safe(context, as_path(path));
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename); match fs::metadata(&path_abs) {
if pathNfilename_abs.is_null() { Ok(meta) => meta.len() as uint64_t,
return 0; Err(_err) => 0,
} }
let p = std::ffi::CStr::from_ptr(pathNfilename_abs)
.to_str()
.unwrap();
let filebytes = match fs::metadata(p) {
Ok(meta) => meta.len(),
Err(_err) => {
return 0;
}
};
free(pathNfilename_abs as *mut libc::c_void);
filebytes as uint64_t
} }
#[allow(non_snake_case)] pub fn dc_delete_file(context: &Context, path: *const libc::c_char) -> libc::c_int {
pub unsafe fn dc_delete_file(context: &Context, pathNfilename: *const libc::c_char) -> libc::c_int { let path = as_path(path);
let mut success: libc::c_int = 0i32; let path_abs = dc_get_abs_path_safe(context, path);
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename); let res = if path_abs.is_file() {
if pathNfilename_abs.is_null() { fs::remove_file(path_abs)
return 0;
}
let p = std::path::Path::new(
std::ffi::CStr::from_ptr(pathNfilename_abs)
.to_str()
.unwrap(),
);
let res = if p.is_file() {
fs::remove_file(p)
} else { } else {
fs::remove_dir_all(p) fs::remove_dir_all(path_abs)
}; };
match res { match res {
Ok(_) => { Ok(_) => 1,
success = 1;
}
Err(_err) => { Err(_err) => {
warn!(context, 0, "Cannot delete \"{}\".", as_str(pathNfilename),); warn!(context, 0, "Cannot delete \"{}\".", path.display());
0
} }
} }
free(pathNfilename_abs as *mut libc::c_void);
success
} }
#[allow(non_snake_case)] pub fn dc_copy_file(
pub unsafe fn dc_copy_file(
context: &Context, context: &Context,
src: *const libc::c_char, src: *const libc::c_char,
dest: *const libc::c_char, dest: *const libc::c_char,
) -> libc::c_int { ) -> libc::c_int {
let mut success = 0; let src = as_path(src);
let dest = as_path(dest);
let src_abs = dc_get_abs_path(context, src); let src_abs = dc_get_abs_path_safe(context, src);
let dest_abs = dc_get_abs_path(context, dest); let dest_abs = dc_get_abs_path_safe(context, dest);
match fs::copy(&src_abs, &dest_abs) {
if src_abs.is_null() || dest_abs.is_null() { Ok(_) => 1,
return 0;
}
let src_p = std::ffi::CStr::from_ptr(src_abs).to_str().unwrap();
let dest_p = std::ffi::CStr::from_ptr(dest_abs).to_str().unwrap();
match fs::copy(src_p, dest_p) {
Ok(_) => {
success = 1;
}
Err(_) => { Err(_) => {
error!(context, 0, "Cannot copy \"{}\" to \"{}\".", src_p, dest_p,); error!(
context,
0,
"Cannot copy \"{}\" to \"{}\".",
src.display(),
dest.display(),
);
0
} }
} }
free(src_abs as *mut libc::c_void);
free(dest_abs as *mut libc::c_void);
success
} }
#[allow(non_snake_case)] pub fn dc_create_folder(context: &Context, path: *const libc::c_char) -> libc::c_int {
pub unsafe fn dc_create_folder( let path = as_path(path);
context: &Context, let path_abs = dc_get_abs_path_safe(context, path);
pathNfilename: *const libc::c_char, if !path_abs.exists() {
) -> libc::c_int { match fs::create_dir_all(path_abs) {
let mut success = 0; Ok(_) => 1,
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename); Err(_err) => {
{ warn!(
let p = std::path::Path::new(as_str(pathNfilename_abs)); context,
if !p.exists() { 0,
match fs::create_dir_all(p) { "Cannot create directory \"{}\".",
Ok(_) => { path.display(),
success = 1; );
} 0
Err(_err) => {
warn!(
context,
0,
"Cannot create directory \"{}\".",
as_str(pathNfilename),
);
}
} }
} else {
success = 1;
} }
} else {
1
} }
free(pathNfilename_abs as *mut libc::c_void);
success
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@@ -1255,35 +1173,24 @@ pub unsafe fn dc_write_file(
dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int
} }
#[allow(non_snake_case)] pub fn dc_write_file_safe<P: AsRef<std::path::Path>>(
pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef<str>, buf: &[u8]) -> bool { context: &Context,
let pathNfilename_abs = unsafe { path: P,
let n = to_cstring(pathNfilename.as_ref()); buf: &[u8],
let res = dc_get_abs_path(context, n); ) -> bool {
free(n as *mut _); let path_abs = dc_get_abs_path_safe(context, &path);
res if let Err(_err) = fs::write(&path_abs, buf) {
};
if pathNfilename_abs.is_null() {
return false;
}
let p = as_str(pathNfilename_abs);
let success = if let Err(_err) = fs::write(p, buf) {
warn!( warn!(
context, context,
0, 0,
"Cannot write {} bytes to \"{}\".", "Cannot write {} bytes to \"{}\".",
buf.len(), buf.len(),
pathNfilename.as_ref(), path.as_ref().display(),
); );
false false
} else { } else {
true true
}; }
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
success
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@@ -1306,36 +1213,20 @@ pub unsafe fn dc_read_file(
} }
} }
#[allow(non_snake_case)] pub fn dc_read_file_safe<P: AsRef<std::path::Path>>(context: &Context, path: P) -> Option<Vec<u8>> {
pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef<str>) -> Option<Vec<u8>> { let path_abs = dc_get_abs_path_safe(context, &path);
let pathNfilename_abs = unsafe { match fs::read(&path_abs) {
let n = to_cstring(pathNfilename.as_ref());
let p = dc_get_abs_path(context, n);
free(n as *mut _);
p
};
if pathNfilename_abs.is_null() {
return None;
}
let p = as_str(pathNfilename_abs);
let res = match fs::read(p) {
Ok(bytes) => Some(bytes), Ok(bytes) => Some(bytes),
Err(_err) => { Err(_err) => {
warn!( warn!(
context, context,
0, 0,
"Cannot read \"{}\" or file is empty.", "Cannot read \"{}\" or file is empty.",
pathNfilename.as_ref(), path.as_ref().display()
); );
None None
} }
}; }
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
res
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@@ -1545,10 +1436,49 @@ fn os_str_to_c_string_unicode(
} }
} }
/// Needs to free the result after use! /// Convenience methods/associated functions for working with [CString]
pub unsafe fn to_cstring<S: AsRef<str>>(s: S) -> *mut libc::c_char { ///
let cstr = CString::new(s.as_ref()).expect("invalid string converted"); /// This is helps transitioning from unsafe code.
dc_strdup(cstr.as_ref().as_ptr()) pub trait CStringExt {
/// Create a new [CString], yolo style
///
/// This unwrap the result, panicking when there are embedded NULL
/// bytes.
fn yolo<T: Into<Vec<u8>>>(t: T) -> CString {
CString::new(t).expect("String contains null byte, can not be CString")
}
}
impl CStringExt for CString {}
/// Convenience methods to make transitioning from raw C strings easier.
///
/// To interact with (legacy) C APIs we often need to convert from
/// Rust strings to raw C strings. This can be clumsy to do correctly
/// and the compiler sometimes allows it in an unsafe way. These
/// methods make it more succinct and help you get it right.
pub trait StrExt {
/// Allocate a new raw C `*char` version of this string.
///
/// This allocates a new raw C string which must be freed using
/// `free`. It takes care of some common pitfalls with using
/// [CString::as_ptr].
///
/// [CString::as_ptr]: std::ffi::CString::as_ptr
///
/// # Panics
///
/// This function will panic when the original string contains an
/// interior null byte as this can not be represented in raw C
/// strings.
unsafe fn strdup(&self) -> *mut libc::c_char;
}
impl<T: AsRef<str>> StrExt for T {
unsafe fn strdup(&self) -> *mut libc::c_char {
let tmp = CString::yolo(self.as_ref());
dc_strdup(tmp.as_ptr())
}
} }
pub fn to_string(s: *const libc::c_char) -> String { pub fn to_string(s: *const libc::c_char) -> String {
@@ -1987,11 +1917,28 @@ mod tests {
#[test] #[test]
fn test_dc_create_id() { fn test_dc_create_id() {
unsafe { let buf = dc_create_id();
let buf = dc_create_id(); assert_eq!(buf.len(), 11);
assert_eq!(strlen(buf), 11); }
free(buf as *mut libc::c_void);
} #[test]
fn test_encode_66bits_as_base64() {
assert_eq!(
encode_66bits_as_base64(0x01234567, 0x89abcdef, 0),
"ASNFZ4mrze8"
);
assert_eq!(
encode_66bits_as_base64(0x01234567, 0x89abcdef, 1),
"ASNFZ4mrze9"
);
assert_eq!(
encode_66bits_as_base64(0x01234567, 0x89abcdef, 2),
"ASNFZ4mrze-"
);
assert_eq!(
encode_66bits_as_base64(0x01234567, 0x89abcdef, 3),
"ASNFZ4mrze_"
);
} }
#[test] #[test]
@@ -2090,4 +2037,53 @@ mod tests {
let ptr = some_path.as_ptr(); let ptr = some_path.as_ptr();
assert_eq!(as_path_unicode(ptr), std::ffi::OsString::from("/some/path")); assert_eq!(as_path_unicode(ptr), std::ffi::OsString::from("/some/path"));
} }
#[test]
fn test_cstring_yolo() {
assert_eq!(CString::new("hello").unwrap(), CString::yolo("hello"));
}
#[test]
fn test_strdup_str() {
unsafe {
let s = "hello".strdup();
let cmp = strcmp(s, b"hello\x00" as *const u8 as *const libc::c_char);
free(s as *mut libc::c_void);
assert_eq!(cmp, 0);
}
}
#[test]
fn test_strdup_string() {
unsafe {
let s = String::from("hello").strdup();
let cmp = strcmp(s, b"hello\x00" as *const u8 as *const libc::c_char);
free(s as *mut libc::c_void);
assert_eq!(cmp, 0);
}
}
#[test]
fn test_dc_extract_grpid_from_rfc724_mid() {
// Should return None if we pass invalid mid
let mid = "foobar";
let grpid = dc_extract_grpid_from_rfc724_mid(mid);
assert_eq!(grpid, None);
// Should return None if grpid has a length which is not 11 or 16
let mid = "Gr.12345678.morerandom@domain.de";
let grpid = dc_extract_grpid_from_rfc724_mid(mid);
assert_eq!(grpid, None);
// Should return extracted grpid for grpid with length of 11
let mid = "Gr.12345678901.morerandom@domain.de";
let grpid = dc_extract_grpid_from_rfc724_mid(mid);
assert_eq!(grpid, Some("12345678901"));
// Should return extracted grpid for grpid with length of 11
let mid = "Gr.1234567890123456.morerandom@domain.de";
let grpid = dc_extract_grpid_from_rfc724_mid(mid);
assert_eq!(grpid, Some("1234567890123456"));
}
} }

View File

@@ -1,3 +1,4 @@
use std::ffi::CString;
use std::net; use std::net;
use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::sync::{Arc, Condvar, Mutex, RwLock};
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
@@ -5,10 +6,9 @@ use std::time::{Duration, SystemTime};
use crate::constants::*; use crate::constants::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_loginparam::*; use crate::dc_loginparam::*;
use crate::dc_tools::{as_str, to_cstring}; use crate::dc_tools::CStringExt;
use crate::oauth2::dc_get_oauth2_access_token; use crate::oauth2::dc_get_oauth2_access_token;
use crate::types::*; use crate::types::*;
use crate::x::free;
pub const DC_IMAP_SEEN: usize = 0x0001; pub const DC_IMAP_SEEN: usize = 0x0001;
pub const DC_REGENERATE: usize = 0x01; pub const DC_REGENERATE: usize = 0x01;
@@ -705,26 +705,16 @@ impl Imap {
fn get_config_last_seen_uid<S: AsRef<str>>(&self, context: &Context, folder: S) -> (u32, u32) { fn get_config_last_seen_uid<S: AsRef<str>>(&self, context: &Context, folder: S) -> (u32, u32) {
let key = format!("imap.mailbox.{}", folder.as_ref()); let key = format!("imap.mailbox.{}", folder.as_ref());
let val1 = unsafe { if let Some(entry) = (self.get_config)(context, &key) {
let key_c = to_cstring(key); // the entry has the format `imap.mailbox.<folder>=<uidvalidity>:<lastseenuid>`
let val = (self.get_config)(context, key_c, 0 as *const libc::c_char); let mut parts = entry.split(':');
free(key_c as *mut _); (
val parts.next().unwrap().parse().unwrap_or_else(|_| 0),
}; parts.next().unwrap().parse().unwrap_or_else(|_| 0),
if val1.is_null() { )
return (0, 0); } else {
(0, 0)
} }
let entry = as_str(val1);
if entry.is_empty() {
return (0, 0);
}
// the entry has the format `imap.mailbox.<folder>=<uidvalidity>:<lastseenuid>`
let mut parts = entry.split(':');
(
parts.next().unwrap().parse().unwrap_or_else(|_| 0),
parts.next().unwrap().parse().unwrap_or_else(|_| 0),
)
} }
fn fetch_from_single_folder<S: AsRef<str>>(&self, context: &Context, folder: S) -> usize { fn fetch_from_single_folder<S: AsRef<str>>(&self, context: &Context, folder: S) -> usize {
@@ -853,10 +843,8 @@ impl Imap {
.expect("missing message id"); .expect("missing message id");
if 0 == unsafe { if 0 == unsafe {
let message_id_c = to_cstring(message_id); let message_id_c = CString::yolo(message_id);
let res = (self.precheck_imf)(context, message_id_c, folder.as_ref(), cur_uid); (self.precheck_imf)(context, message_id_c.as_ptr(), folder.as_ref(), cur_uid)
free(message_id_c as *mut _);
res
} { } {
// check passed, go fetch the rest // check passed, go fetch the rest
if self.fetch_single_msg(context, &folder, cur_uid) == 0 { if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
@@ -924,13 +912,7 @@ impl Imap {
let key = format!("imap.mailbox.{}", folder.as_ref()); let key = format!("imap.mailbox.{}", folder.as_ref());
let val = format!("{}:{}", uidvalidity, lastseenuid); let val = format!("{}:{}", uidvalidity, lastseenuid);
unsafe { (self.set_config)(context, &key, Some(&val));
let key_c = to_cstring(key);
let val_c = to_cstring(val);
(self.set_config)(context, key_c, val_c);
free(key_c as *mut _);
free(val_c as *mut _);
};
} }
fn fetch_single_msg<S: AsRef<str>>( fn fetch_single_msg<S: AsRef<str>>(

View File

@@ -216,22 +216,16 @@ impl Key {
} }
} }
/// Each header line must be terminated by `\r\n`, the result must be freed. /// Each header line must be terminated by `\r\n`
pub fn to_asc_c(&self, header: Option<(&str, &str)>) -> *mut libc::c_char { pub fn to_asc(&self, header: Option<(&str, &str)>) -> String {
let headers = header.map(|(key, value)| { let headers = header.map(|(key, value)| {
let mut m = BTreeMap::new(); let mut m = BTreeMap::new();
m.insert(key.to_string(), value.to_string()); m.insert(key.to_string(), value.to_string());
m m
}); });
let buf = self self.to_armored_string(headers.as_ref())
.to_armored_string(headers.as_ref()) .expect("failed to serialize key")
.expect("failed to serialize key");
let buf_c = CString::new(buf).unwrap();
// need to use strdup to allocate the result with malloc
// so it can be `free`d later.
unsafe { strdup(buf_c.as_ptr()) }
} }
pub fn write_asc_to_file(&self, file: *const libc::c_char, context: &Context) -> bool { pub fn write_asc_to_file(&self, file: *const libc::c_char, context: &Context) -> bool {
@@ -239,15 +233,16 @@ impl Key {
return false; return false;
} }
let file_content = self.to_asc_c(None); let file_content = self.to_asc(None);
let file_content_c = CString::new(file_content).unwrap();
let success = if 0 let success = if 0
== unsafe { == unsafe {
dc_write_file( dc_write_file(
context, context,
file, file,
file_content as *const libc::c_void, file_content_c.as_ptr() as *const libc::c_void,
strlen(file_content), file_content_c.as_bytes().len(),
) )
} { } {
error!(context, 0, "Cannot write key to {}", to_string(file)); error!(context, 0, "Cannot write key to {}", to_string(file));
@@ -256,8 +251,6 @@ impl Key {
true true
}; };
unsafe { free(file_content as *mut libc::c_void) };
success success
} }

View File

@@ -1,13 +0,0 @@
use crate::context::Context;
/* yes: uppercase */
/* library private: key-history */
pub fn dc_add_to_keyhistory(
_context: &Context,
_rfc724_mid: *const libc::c_char,
_sending_time: u64,
_addr: *const libc::c_char,
_fingerprint: *const libc::c_char,
) {
}

View File

@@ -1,4 +1,4 @@
#![feature(c_variadic, ptr_wrapping_offset_from)] #![feature(c_variadic, ptr_wrapping_offset_from, ptr_cast)]
#[macro_use] #[macro_use]
extern crate failure_derive; extern crate failure_derive;
@@ -8,6 +8,9 @@ extern crate num_derive;
extern crate smallvec; extern crate smallvec;
#[macro_use] #[macro_use]
extern crate rusqlite; extern crate rusqlite;
extern crate strum;
#[macro_use]
extern crate strum_macros;
#[macro_use] #[macro_use]
mod log; mod log;
@@ -18,10 +21,10 @@ pub mod aheader;
pub mod chatlist; pub mod chatlist;
pub mod config; pub mod config;
pub mod constants; pub mod constants;
pub mod contact;
pub mod context; pub mod context;
pub mod imap; pub mod imap;
pub mod key; pub mod key;
pub mod keyhistory;
pub mod keyring; pub mod keyring;
pub mod oauth2; pub mod oauth2;
pub mod param; pub mod param;
@@ -36,7 +39,6 @@ pub mod x;
pub mod dc_array; pub mod dc_array;
pub mod dc_chat; pub mod dc_chat;
pub mod dc_configure; pub mod dc_configure;
pub mod dc_contact;
pub mod dc_dehtml; pub mod dc_dehtml;
pub mod dc_e2ee; pub mod dc_e2ee;
pub mod dc_imex; pub mod dc_imex;

View File

@@ -7,10 +7,9 @@ macro_rules! info {
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
unsafe { unsafe {
let formatted = format!($msg, $($args),*); let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted); let formatted_c = std::ffi::CString::new(formatted).unwrap();
$ctx.call_cb($crate::constants::Event::INFO, $data1 as libc::uintptr_t, $ctx.call_cb($crate::constants::Event::INFO, $data1 as libc::uintptr_t,
formatted_c as libc::uintptr_t); formatted_c.as_ptr() as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void);
}}; }};
} }
@@ -23,10 +22,9 @@ macro_rules! warn {
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
unsafe { unsafe {
let formatted = format!($msg, $($args),*); let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted); let formatted_c = std::ffi::CString::new(formatted).unwrap();
$ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t, $ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t,
formatted_c as libc::uintptr_t); formatted_c.as_ptr() as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void) ;
}}; }};
} }
@@ -39,10 +37,9 @@ macro_rules! error {
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
unsafe { unsafe {
let formatted = format!($msg, $($args),*); let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted); let formatted_c = std::ffi::CString::new(formatted).unwrap();
$ctx.call_cb($crate::constants::Event::ERROR, $data1 as libc::uintptr_t, $ctx.call_cb($crate::constants::Event::ERROR, $data1 as libc::uintptr_t,
formatted_c as libc::uintptr_t); formatted_c.as_ptr() as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void);
}}; }};
} }
@@ -55,9 +52,8 @@ macro_rules! log_event {
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
unsafe { unsafe {
let formatted = format!($msg, $($args),*); let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted); let formatted_c = std::ffi::CString::new(formatted).unwrap();
$ctx.call_cb($event, $data1 as libc::uintptr_t, $ctx.call_cb($event, $data1 as libc::uintptr_t,
formatted_c as libc::uintptr_t); formatted_c.as_ptr() as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void);
}}; }};
} }

View File

@@ -166,7 +166,6 @@ impl<'a> Peerstate<'a> {
pub fn from_addr(context: &'a Context, _sql: &Sql, addr: &str) -> Option<Self> { pub fn from_addr(context: &'a Context, _sql: &Sql, addr: &str) -> Option<Self> {
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;"; let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;";
Self::from_stmt(context, query, &[addr]) Self::from_stmt(context, query, &[addr])
} }
@@ -191,6 +190,11 @@ impl<'a> Peerstate<'a> {
context context
.sql .sql
.query_row(query, params, |row| { .query_row(query, params, |row| {
/* all the above queries start with this: SELECT
addr, last_seen, last_seen_autocrypt, prefer_encrypted,
public_key, gossip_timestamp, gossip_key, public_key_fingerprint,
gossip_key_fingerprint, verified_key, verified_key_fingerprint
*/
let mut res = Self::new(context); let mut res = Self::new(context);
res.addr = Some(row.get(0)?); res.addr = Some(row.get(0)?);
@@ -198,13 +202,34 @@ impl<'a> Peerstate<'a> {
res.last_seen_autocrypt = row.get(2)?; res.last_seen_autocrypt = row.get(2)?;
res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default(); res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
res.gossip_timestamp = row.get(5)?; res.gossip_timestamp = row.get(5)?;
let pkf: String = row.get(7)?;
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
let gkf: String = row.get(8)?;
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
let vkf: String = row.get(10)?;
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) };
res.public_key_fingerprint = row.get(7)?;
if res
.public_key_fingerprint
.as_ref()
.map(|s| s.is_empty())
.unwrap_or_default()
{
res.public_key_fingerprint = None;
}
res.gossip_key_fingerprint = row.get(8)?;
if res
.gossip_key_fingerprint
.as_ref()
.map(|s| s.is_empty())
.unwrap_or_default()
{
res.gossip_key_fingerprint = None;
}
res.verified_key_fingerprint = row.get(10)?;
if res
.verified_key_fingerprint
.as_ref()
.map(|s| s.is_empty())
.unwrap_or_default()
{
res.verified_key_fingerprint = None;
}
res.public_key = row res.public_key = row
.get(4) .get(4)
.ok() .ok()
@@ -217,7 +242,8 @@ impl<'a> Peerstate<'a> {
.get(9) .get(9)
.ok() .ok()
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public)); .and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
res.verified_key = if vk == res.gossip_key {
res.verified_key = if vk == res.gossip_key && res.gossip_key.is_some() {
VerifiedKey::Gossip VerifiedKey::Gossip
} else if vk == res.public_key { } else if vk == res.public_key {
VerifiedKey::Public VerifiedKey::Public
@@ -422,6 +448,7 @@ impl<'a> Peerstate<'a> {
&self.addr, &self.addr,
], ],
).is_ok(); ).is_ok();
assert_eq!(success, true);
} else if self.to_save == Some(ToSave::Timestamps) { } else if self.to_save == Some(ToSave::Timestamps) {
success = sql::execute( success = sql::execute(
self.context, self.context,
@@ -462,16 +489,11 @@ mod tests {
use super::*; use super::*;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use std::ffi::CStr; use tempfile::TempDir;
use tempfile::{tempdir, TempDir};
use crate::context::*;
use crate::dc_tools::to_cstring;
use crate::x::free;
#[test] #[test]
fn test_peerstate_save_to_db() { fn test_peerstate_save_to_db() {
let ctx = unsafe { create_test_context() }; let ctx = crate::test_utils::dummy_context();
let addr = "hello@mail.com"; let addr = "hello@mail.com";
let pub_key = crate::key::Key::from_base64("xsBNBFztUVkBCADYaQl/UOUpRPd32nLRzx8eU0eI+jQEnG+g5anjYA+3oct1rROGl5SygjMULDKdaUy27O3o9Srsti0YjA7uxZnavIqhSopJhFidqY1M1wA9JZa/duucZdNwUGbjGIRsS/4Cjr5+3svscK24hVYub1dvDWXpwUTnj3K6xOEnJdoM+MhCqtSD5+zcJhFc9vyZm9ZTGWUxAhKh0iJTcCD8V6CQ3XZ2z9GruwzZT/FTFovWrz7m3TUI2OdSSHh0eZLRGEoxMCT/vzflAFGAr8ijCaRsEIfqP6FW8uQWnFTqkjxEUCZG6XkeFHB84aj5jqYG/1KCLjL5vEKwfl1tz/WnPhY7ABEBAAHNEDxoZWxsb0BtYWlsLmNvbT7CwIkEEAEIADMCGQEFAlztUVoCGwMECwkIBwYVCAkKCwIDFgIBFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7ijAwf+PTsuawUax9cNPn1bN90H+g9qyHZJMEwKXtUnNaXJxPW3iB7ThhpCiCzsZwP7+l7ArS8tmLeNDw2bENtcf1XCv4wovP2fdXOP3QOUUFX/GdakcTwv7DzC7CO0grB1HtaPhGw/6UX2o2cx2i9xiUf4Givq2MfCbgAW5zloH6WXGPb6yLQYJXxqDIphr4+uZDb+bMAyWHN/DUkAjHrV8nnVki7PMHqzzZpwglalxMX8RGeiGZE39ALJKL/Og87DMFah87/yoxQWGoS7Wqv0XDcCPKoTCPrpk8pOe2KEsq/lz215nefHd4aRpfUX5YCYa8HPvvfPQbGF73uvyQw5w7qjis7ATQRc7VFZAQgAt8ONdnX6KEEQ5Jw6ilJ+LBtY44SP5t0I3eK+goKepgIiKhjGDa+Mntyi4jdhH+HO6kvK5SHMh2sPp4rRO/WKHJwWFySyM1OdyiywhyH0J9R5rBY4vPHsJjf6vSKJdWLWT+ho1fNet2IIC+jVCYli91MAMbRvk6EKVj1nCc+67giOahXEkHt6xxkeCGlOvbw8hxGj1A8+AC1BLms/OR3oc4JMi9O3kq6uG0z9tlUEerac9HVwcjoO1XLe+hJhoT5H+TbnGjPuhuURP3pFiIKHpbRYgUfdSAY0dTObO7t4I5y/drPOrCTnWrBUg2wXAECUhpRKow9/ai2YemLv9KqhhwARAQABwsB2BBgBCAAgBQJc7VFaAhsMFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7jmyggAhs4QzCzIbT2OsAReBxkxtm0AI+g1HZ1KFKof5NDHfgv9C/Qu1I8mKEjlZzA4qFyPmLqntgwJ0RuFy6gLbljZBNCFO7vB478AhYtnWjuKZmA40HUPwcB1hEJ31c42akzfUbioY1TLLepngdsJg7Cm8O+rhI9+1WRA66haJDgFs793SVUDyJh8f9NX50l5zR87/bsV30CFSw0q4OSSy9VI/z+2g5khn1LnuuOrCfFnYIPYtJED1BfkXkosxGlgbzy79VvGmI9d23x4atDK7oBPCzIj+lP8sytJ0u3HOguXi9OgDitKy+Pt1r8gH8frdktMJr5Ts6DW+tIn2vR23KR8aA==", KeyType::Public).unwrap(); let pub_key = crate::key::Key::from_base64("xsBNBFztUVkBCADYaQl/UOUpRPd32nLRzx8eU0eI+jQEnG+g5anjYA+3oct1rROGl5SygjMULDKdaUy27O3o9Srsti0YjA7uxZnavIqhSopJhFidqY1M1wA9JZa/duucZdNwUGbjGIRsS/4Cjr5+3svscK24hVYub1dvDWXpwUTnj3K6xOEnJdoM+MhCqtSD5+zcJhFc9vyZm9ZTGWUxAhKh0iJTcCD8V6CQ3XZ2z9GruwzZT/FTFovWrz7m3TUI2OdSSHh0eZLRGEoxMCT/vzflAFGAr8ijCaRsEIfqP6FW8uQWnFTqkjxEUCZG6XkeFHB84aj5jqYG/1KCLjL5vEKwfl1tz/WnPhY7ABEBAAHNEDxoZWxsb0BtYWlsLmNvbT7CwIkEEAEIADMCGQEFAlztUVoCGwMECwkIBwYVCAkKCwIDFgIBFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7ijAwf+PTsuawUax9cNPn1bN90H+g9qyHZJMEwKXtUnNaXJxPW3iB7ThhpCiCzsZwP7+l7ArS8tmLeNDw2bENtcf1XCv4wovP2fdXOP3QOUUFX/GdakcTwv7DzC7CO0grB1HtaPhGw/6UX2o2cx2i9xiUf4Givq2MfCbgAW5zloH6WXGPb6yLQYJXxqDIphr4+uZDb+bMAyWHN/DUkAjHrV8nnVki7PMHqzzZpwglalxMX8RGeiGZE39ALJKL/Og87DMFah87/yoxQWGoS7Wqv0XDcCPKoTCPrpk8pOe2KEsq/lz215nefHd4aRpfUX5YCYa8HPvvfPQbGF73uvyQw5w7qjis7ATQRc7VFZAQgAt8ONdnX6KEEQ5Jw6ilJ+LBtY44SP5t0I3eK+goKepgIiKhjGDa+Mntyi4jdhH+HO6kvK5SHMh2sPp4rRO/WKHJwWFySyM1OdyiywhyH0J9R5rBY4vPHsJjf6vSKJdWLWT+ho1fNet2IIC+jVCYli91MAMbRvk6EKVj1nCc+67giOahXEkHt6xxkeCGlOvbw8hxGj1A8+AC1BLms/OR3oc4JMi9O3kq6uG0z9tlUEerac9HVwcjoO1XLe+hJhoT5H+TbnGjPuhuURP3pFiIKHpbRYgUfdSAY0dTObO7t4I5y/drPOrCTnWrBUg2wXAECUhpRKow9/ai2YemLv9KqhhwARAQABwsB2BBgBCAAgBQJc7VFaAhsMFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7jmyggAhs4QzCzIbT2OsAReBxkxtm0AI+g1HZ1KFKof5NDHfgv9C/Qu1I8mKEjlZzA4qFyPmLqntgwJ0RuFy6gLbljZBNCFO7vB478AhYtnWjuKZmA40HUPwcB1hEJ31c42akzfUbioY1TLLepngdsJg7Cm8O+rhI9+1WRA66haJDgFs793SVUDyJh8f9NX50l5zR87/bsV30CFSw0q4OSSy9VI/z+2g5khn1LnuuOrCfFnYIPYtJED1BfkXkosxGlgbzy79VvGmI9d23x4atDK7oBPCzIj+lP8sytJ0u3HOguXi9OgDitKy+Pt1r8gH8frdktMJr5Ts6DW+tIn2vR23KR8aA==", KeyType::Public).unwrap();
@@ -503,35 +525,44 @@ mod tests {
assert_eq!(peerstate, peerstate_new); assert_eq!(peerstate, peerstate_new);
} }
#[test]
fn test_peerstate_with_empty_gossip_key_save_to_db() {
let ctx = crate::test_utils::dummy_context();
let addr = "hello@mail.com";
let pub_key = crate::key::Key::from_base64("xsBNBFztUVkBCADYaQl/UOUpRPd32nLRzx8eU0eI+jQEnG+g5anjYA+3oct1rROGl5SygjMULDKdaUy27O3o9Srsti0YjA7uxZnavIqhSopJhFidqY1M1wA9JZa/duucZdNwUGbjGIRsS/4Cjr5+3svscK24hVYub1dvDWXpwUTnj3K6xOEnJdoM+MhCqtSD5+zcJhFc9vyZm9ZTGWUxAhKh0iJTcCD8V6CQ3XZ2z9GruwzZT/FTFovWrz7m3TUI2OdSSHh0eZLRGEoxMCT/vzflAFGAr8ijCaRsEIfqP6FW8uQWnFTqkjxEUCZG6XkeFHB84aj5jqYG/1KCLjL5vEKwfl1tz/WnPhY7ABEBAAHNEDxoZWxsb0BtYWlsLmNvbT7CwIkEEAEIADMCGQEFAlztUVoCGwMECwkIBwYVCAkKCwIDFgIBFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7ijAwf+PTsuawUax9cNPn1bN90H+g9qyHZJMEwKXtUnNaXJxPW3iB7ThhpCiCzsZwP7+l7ArS8tmLeNDw2bENtcf1XCv4wovP2fdXOP3QOUUFX/GdakcTwv7DzC7CO0grB1HtaPhGw/6UX2o2cx2i9xiUf4Givq2MfCbgAW5zloH6WXGPb6yLQYJXxqDIphr4+uZDb+bMAyWHN/DUkAjHrV8nnVki7PMHqzzZpwglalxMX8RGeiGZE39ALJKL/Og87DMFah87/yoxQWGoS7Wqv0XDcCPKoTCPrpk8pOe2KEsq/lz215nefHd4aRpfUX5YCYa8HPvvfPQbGF73uvyQw5w7qjis7ATQRc7VFZAQgAt8ONdnX6KEEQ5Jw6ilJ+LBtY44SP5t0I3eK+goKepgIiKhjGDa+Mntyi4jdhH+HO6kvK5SHMh2sPp4rRO/WKHJwWFySyM1OdyiywhyH0J9R5rBY4vPHsJjf6vSKJdWLWT+ho1fNet2IIC+jVCYli91MAMbRvk6EKVj1nCc+67giOahXEkHt6xxkeCGlOvbw8hxGj1A8+AC1BLms/OR3oc4JMi9O3kq6uG0z9tlUEerac9HVwcjoO1XLe+hJhoT5H+TbnGjPuhuURP3pFiIKHpbRYgUfdSAY0dTObO7t4I5y/drPOrCTnWrBUg2wXAECUhpRKow9/ai2YemLv9KqhhwARAQABwsB2BBgBCAAgBQJc7VFaAhsMFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7jmyggAhs4QzCzIbT2OsAReBxkxtm0AI+g1HZ1KFKof5NDHfgv9C/Qu1I8mKEjlZzA4qFyPmLqntgwJ0RuFy6gLbljZBNCFO7vB478AhYtnWjuKZmA40HUPwcB1hEJ31c42akzfUbioY1TLLepngdsJg7Cm8O+rhI9+1WRA66haJDgFs793SVUDyJh8f9NX50l5zR87/bsV30CFSw0q4OSSy9VI/z+2g5khn1LnuuOrCfFnYIPYtJED1BfkXkosxGlgbzy79VvGmI9d23x4atDK7oBPCzIj+lP8sytJ0u3HOguXi9OgDitKy+Pt1r8gH8frdktMJr5Ts6DW+tIn2vR23KR8aA==", KeyType::Public).unwrap();
let mut peerstate = Peerstate {
context: &ctx.ctx,
addr: Some(addr.into()),
last_seen: 10,
last_seen_autocrypt: 11,
prefer_encrypt: EncryptPreference::Mutual,
public_key: Some(pub_key.clone()),
public_key_fingerprint: Some(pub_key.fingerprint()),
gossip_key: None,
gossip_timestamp: 12,
gossip_key_fingerprint: None,
verified_key: VerifiedKey::None,
verified_key_fingerprint: None,
to_save: Some(ToSave::All),
degrade_event: None,
};
assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save");
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into())
.expect("failed to load peerstate from db");
// clear to_save, as that is not persissted
peerstate.to_save = None;
assert_eq!(peerstate, peerstate_new);
}
// TODO: don't copy this from stress.rs // TODO: don't copy this from stress.rs
#[allow(dead_code)] #[allow(dead_code)]
struct TestContext { struct TestContext {
ctx: Context, ctx: Context,
dir: TempDir, dir: TempDir,
} }
unsafe extern "C" fn cb(
_context: &Context,
_event: Event,
_data1: libc::uintptr_t,
_data2: libc::uintptr_t,
) -> libc::uintptr_t {
0
}
unsafe fn create_test_context() -> TestContext {
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
let dir = tempdir().unwrap();
let dbfile = to_cstring(dir.path().join("db.sqlite").to_str().unwrap());
assert_eq!(
dc_open(&mut ctx, dbfile, std::ptr::null()),
1,
"Failed to open {}",
CStr::from_ptr(dbfile as *const _).to_str().unwrap()
);
free(dbfile as *mut _);
TestContext { ctx: ctx, dir: dir }
}
} }

View File

@@ -17,15 +17,14 @@ use crate::keyring::*;
use crate::types::*; use crate::types::*;
use crate::x::*; use crate::x::*;
// TODO should return bool /rtn
pub unsafe fn dc_split_armored_data( pub unsafe fn dc_split_armored_data(
buf: *mut libc::c_char, buf: *mut libc::c_char,
ret_headerline: *mut *const libc::c_char, ret_headerline: *mut *const libc::c_char,
ret_setupcodebegin: *mut *const libc::c_char, ret_setupcodebegin: *mut *const libc::c_char,
ret_preferencrypt: *mut *const libc::c_char, ret_preferencrypt: *mut *const libc::c_char,
ret_base64: *mut *const libc::c_char, ret_base64: *mut *const libc::c_char,
) -> libc::c_int { ) -> bool {
let mut success: libc::c_int = 0i32; let mut success = false;
let mut line_chars: size_t = 0i32 as size_t; let mut line_chars: size_t = 0i32 as size_t;
let mut line: *mut libc::c_char = buf; let mut line: *mut libc::c_char = buf;
let mut p1: *mut libc::c_char = buf; let mut p1: *mut libc::c_char = buf;
@@ -128,7 +127,7 @@ pub unsafe fn dc_split_armored_data(
if !ret_base64.is_null() { if !ret_base64.is_null() {
*ret_base64 = base64 *ret_base64 = base64
} }
success = 1i32 success = true;
} }
} }
} }

View File

@@ -10,7 +10,6 @@ use crate::dc_tools::*;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::param::*; use crate::param::*;
use crate::peerstate::*; use crate::peerstate::*;
use crate::x::*;
const DC_OPEN_READONLY: usize = 0x01; const DC_OPEN_READONLY: usize = 0x01;
@@ -1007,35 +1006,15 @@ pub fn housekeeping(context: &Context) {
} }
let entry = entry.unwrap(); let entry = entry.unwrap();
let name_f = entry.file_name(); let name_f = entry.file_name();
let name_c = unsafe { to_cstring(name_f.to_string_lossy()) }; let name_s = name_f.to_string_lossy();
if unsafe { is_file_in_use(&mut files_in_use, 0 as *const libc::c_char, name_c) } if is_file_in_use(&mut files_in_use, None, &name_s)
|| unsafe { || is_file_in_use(&mut files_in_use, Some(".increation"), &name_s)
is_file_in_use( || is_file_in_use(&mut files_in_use, Some(".waveform"), &name_s)
&mut files_in_use, || is_file_in_use(&mut files_in_use, Some("-preview.jpg"), &name_s)
b".increation\x00" as *const u8 as *const libc::c_char,
name_c,
)
}
|| unsafe {
is_file_in_use(
&mut files_in_use,
b".waveform\x00" as *const u8 as *const libc::c_char,
name_c,
)
}
|| unsafe {
is_file_in_use(
&mut files_in_use,
b"-preview.jpg\x00" as *const u8 as *const libc::c_char,
name_c,
)
}
{ {
unsafe { free(name_c as *mut _) };
continue; continue;
} }
unsafe { free(name_c as *mut _) };
unreferenced_count += 1; unreferenced_count += 1;
@@ -1068,11 +1047,8 @@ pub fn housekeeping(context: &Context) {
unreferenced_count, unreferenced_count,
entry.file_name() entry.file_name()
); );
unsafe { let path = entry.path().to_c_string().unwrap();
let path = to_cstring(entry.path().to_str().unwrap()); dc_delete_file(context, path.as_ptr());
dc_delete_file(context, path);
free(path as *mut _);
}
} }
} }
Err(err) => { Err(err) => {
@@ -1089,26 +1065,18 @@ pub fn housekeeping(context: &Context) {
info!(context, 0, "Housekeeping done.",); info!(context, 0, "Housekeeping done.",);
} }
unsafe fn is_file_in_use( fn is_file_in_use(files_in_use: &HashSet<String>, namespc_opt: Option<&str>, name: &str) -> bool {
files_in_use: &HashSet<String>, let name_to_check = if let Some(namespc) = namespc_opt {
namespc: *const libc::c_char, let name_len = name.len();
name: *const libc::c_char, let namespc_len = namespc.len();
) -> bool { if name_len <= namespc_len || !name.ends_with(namespc) {
let name_to_check = dc_strdup(name);
if !namespc.is_null() {
let name_len: libc::c_int = strlen(name) as libc::c_int;
let namespc_len: libc::c_int = strlen(namespc) as libc::c_int;
if name_len <= namespc_len
|| strcmp(&*name.offset((name_len - namespc_len) as isize), namespc) != 0
{
return false; return false;
} }
*name_to_check.offset((name_len - namespc_len) as isize) = 0 as libc::c_char &name[..name_len - namespc_len]
} } else {
name
let contains = files_in_use.contains(as_str(name_to_check)); };
free(name_to_check as *mut libc::c_void); files_in_use.contains(name_to_check)
contains
} }
fn maybe_add_file(files_in_use: &mut HashSet<String>, file: impl AsRef<str>) { fn maybe_add_file(files_in_use: &mut HashSet<String>, file: impl AsRef<str>) {
@@ -1162,26 +1130,12 @@ mod test {
maybe_add_file(&mut files, "$BLOBDIR/world.txt"); maybe_add_file(&mut files, "$BLOBDIR/world.txt");
maybe_add_file(&mut files, "world2.txt"); maybe_add_file(&mut files, "world2.txt");
assert!(unsafe { assert!(is_file_in_use(&mut files, None, "hello"));
is_file_in_use( assert!(!is_file_in_use(&mut files, Some(".txt"), "hello"));
&mut files, assert!(is_file_in_use(
std::ptr::null(), &mut files,
b"hello\x00" as *const u8 as *const _, Some("-suffix"),
) "world.txt-suffix"
}); ));
assert!(!unsafe {
is_file_in_use(
&mut files,
b".txt\x00" as *const u8 as *const _,
b"hello\x00" as *const u8 as *const _,
)
});
assert!(unsafe {
is_file_in_use(
&mut files,
b"-suffix\x00" as *const u8 as *const _,
b"world.txt-suffix\x00" as *const u8 as *const _,
)
});
} }
} }

View File

@@ -1,12 +1,11 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::ffi::CString;
use strum::EnumProperty; use strum::EnumProperty;
use strum_macros::EnumProperty; use strum_macros::EnumProperty;
use crate::constants::Event; use crate::constants::Event;
use crate::contact::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_contact::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use libc::free; use libc::free;
@@ -200,40 +199,30 @@ impl Context {
from_id: u32, from_id: u32,
) -> String { ) -> String {
let insert1 = if id == StockMessage::MsgAddMember || id == StockMessage::MsgDelMember { let insert1 = if id == StockMessage::MsgAddMember || id == StockMessage::MsgDelMember {
unsafe { let contact_id = Contact::lookup_id_by_addr(self, param1.as_ref());
let param1_c = CString::new(param1.as_ref()).unwrap(); if contact_id != 0 {
let contact_id = dc_lookup_contact_id_by_addr(self, param1_c.as_ptr()); Contact::get_by_id(self, contact_id)
if contact_id != 0 { .map(|contact| contact.get_name_n_addr())
let contact = dc_get_contact(self, contact_id); .unwrap_or_default()
let displayname = dc_contact_get_name_n_addr(contact); } else {
let ret = to_string(displayname); param1.as_ref().to_string()
free(contact as *mut libc::c_void);
free(displayname as *mut libc::c_void);
ret
} else {
param1.as_ref().to_string()
}
} }
} else { } else {
param1.as_ref().to_string() param1.as_ref().to_string()
}; };
let action = self.stock_string_repl_str2(id, insert1, param2.as_ref().to_string()); let action = self.stock_string_repl_str2(id, insert1, param2.as_ref().to_string());
let action1 = action.trim_end_matches('.'); let action1 = action.trim_end_matches('.');
match from_id { match from_id {
0 => action, 0 => action,
1 => self.stock_string_repl_str(StockMessage::MsgActionByMe, action1), // DC_CONTACT_ID_SELF 1 => self.stock_string_repl_str(StockMessage::MsgActionByMe, action1), // DC_CONTACT_ID_SELF
_ => unsafe { _ => {
let contact = dc_get_contact(self, from_id); let displayname = Contact::get_by_id(self, from_id)
let displayname = dc_contact_get_display_name(contact); .map(|contact| contact.get_name_n_addr())
let ret = self.stock_string_repl_str2( .unwrap_or_default();
StockMessage::MsgActionByUser,
action1, self.stock_string_repl_str2(StockMessage::MsgActionByUser, action1, &displayname)
as_str(displayname), }
);
free(contact as *mut libc::c_void);
free(displayname as *mut libc::c_void);
ret
},
} }
} }
} }
@@ -264,7 +253,7 @@ mod tests {
#[test] #[test]
fn test_stock_str() { fn test_stock_str() {
let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); let ctx = dc_context_new(None, std::ptr::null_mut(), None);
assert_eq!(ctx.stock_str(StockMessage::NoMessages), "No messages."); assert_eq!(ctx.stock_str(StockMessage::NoMessages), "No messages.");
} }
@@ -290,7 +279,7 @@ mod tests {
#[test] #[test]
fn test_stock_string_repl_str() { fn test_stock_string_repl_str() {
let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); let ctx = dc_context_new(None, std::ptr::null_mut(), None);
// uses %1$s substitution // uses %1$s substitution
assert_eq!( assert_eq!(
ctx.stock_string_repl_str(StockMessage::Member, "42"), ctx.stock_string_repl_str(StockMessage::Member, "42"),
@@ -301,7 +290,7 @@ mod tests {
#[test] #[test]
fn test_stock_string_repl_int() { fn test_stock_string_repl_int() {
let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); let ctx = dc_context_new(None, std::ptr::null_mut(), None);
assert_eq!( assert_eq!(
ctx.stock_string_repl_int(StockMessage::Member, 42), ctx.stock_string_repl_int(StockMessage::Member, 42),
"42 member(s)" "42 member(s)"
@@ -310,7 +299,7 @@ mod tests {
#[test] #[test]
fn test_stock_string_repl_str2() { fn test_stock_string_repl_str2() {
let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); let ctx = dc_context_new(None, std::ptr::null_mut(), None);
assert_eq!( assert_eq!(
ctx.stock_string_repl_str2(StockMessage::ServerResponse, "foo", "bar"), ctx.stock_string_repl_str2(StockMessage::ServerResponse, "foo", "bar"),
"Response from foo: bar" "Response from foo: bar"
@@ -319,7 +308,7 @@ mod tests {
#[test] #[test]
fn test_stock_system_msg_simple() { fn test_stock_system_msg_simple() {
let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); let ctx = dc_context_new(None, std::ptr::null_mut(), None);
assert_eq!( assert_eq!(
ctx.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0), ctx.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0),
"Location streaming enabled." "Location streaming enabled."
@@ -328,7 +317,7 @@ mod tests {
#[test] #[test]
fn test_stock_system_msg_add_member_by_me() { fn test_stock_system_msg_add_member_by_me() {
let ctx = dc_context_new(None, std::ptr::null_mut(), std::ptr::null_mut()); let ctx = dc_context_new(None, std::ptr::null_mut(), None);
assert_eq!( assert_eq!(
ctx.stock_system_msg( ctx.stock_system_msg(
StockMessage::MsgAddMember, StockMessage::MsgAddMember,
@@ -343,11 +332,7 @@ mod tests {
#[test] #[test]
fn test_stock_system_msg_add_member_by_me_with_displayname() { fn test_stock_system_msg_add_member_by_me_with_displayname() {
let t = dummy_context(); let t = dummy_context();
unsafe { Contact::create(&t.ctx, "Alice", "alice@example.com").expect("failed to create contact");
let name = CString::new("Alice").unwrap();
let addr = CString::new("alice@example.com").unwrap();
assert!(dc_create_contact(&t.ctx, name.as_ptr(), addr.as_ptr()) > 0);
}
assert_eq!( assert_eq!(
t.ctx.stock_system_msg( t.ctx.stock_system_msg(
StockMessage::MsgAddMember, StockMessage::MsgAddMember,
@@ -356,23 +341,17 @@ mod tests {
DC_CONTACT_ID_SELF as u32 DC_CONTACT_ID_SELF as u32
), ),
"Member Alice (alice@example.com) added by me." "Member Alice (alice@example.com) added by me."
) );
} }
#[test] #[test]
fn test_stock_system_msg_add_member_by_other_with_displayname() { fn test_stock_system_msg_add_member_by_other_with_displayname() {
let t = dummy_context(); let t = dummy_context();
let contact_id = unsafe { let contact_id = {
let name = CString::new("Alice").unwrap(); Contact::create(&t.ctx, "Alice", "alice@example.com")
let addr = CString::new("alice@example.com").unwrap(); .expect("Failed to create contact Alice");
assert!( let id =
dc_create_contact(&t.ctx, name.as_ptr(), addr.as_ptr()) > 0, Contact::create(&t.ctx, "Bob", "bob@example.com").expect("failed to create bob");
"Failed to create contact Alice"
);
let name = CString::new("Bob").unwrap();
let addr = CString::new("bob@example.com").unwrap();
let id = dc_create_contact(&t.ctx, name.as_ptr(), addr.as_ptr());
assert!(id > 0, "Failed to create contact Bob");
id id
}; };
assert_eq!( assert_eq!(
@@ -382,8 +361,8 @@ mod tests {
"", "",
contact_id, contact_id,
), ),
"Member Alice (alice@example.com) added by Bob." "Member Alice (alice@example.com) added by Bob (bob@example.com)."
) );
} }
#[test] #[test]
@@ -403,21 +382,13 @@ mod tests {
#[test] #[test]
fn test_stock_system_msg_grp_name_other() { fn test_stock_system_msg_grp_name_other() {
let t = dummy_context(); let t = dummy_context();
let contact_id = unsafe { let id = Contact::create(&t.ctx, "Alice", "alice@example.com")
let name = CString::new("Alice").unwrap(); .expect("failed to create contact");
let addr = CString::new("alice@example.com").unwrap();
let id = dc_create_contact(&t.ctx, name.as_ptr(), addr.as_ptr());
assert!(id > 0, "Failed to create contact Alice");
id
};
assert_eq!( assert_eq!(
t.ctx.stock_system_msg( t.ctx
StockMessage::MsgGrpName, .stock_system_msg(StockMessage::MsgGrpName, "Some chat", "Other chat", id,),
"Some chat", "Group name changed from \"Some chat\" to \"Other chat\" by Alice (alice@example.com)."
"Other chat",
contact_id
),
"Group name changed from \"Some chat\" to \"Other chat\" by Alice."
) )
} }
} }

View File

@@ -7,8 +7,6 @@ use tempfile::{tempdir, TempDir};
use crate::context::{dc_context_new, dc_open, Context}; use crate::context::{dc_context_new, dc_open, Context};
use crate::types::dc_callback_t; use crate::types::dc_callback_t;
use crate::dc_tools::OsStrExt;
/// A Context and temporary directory. /// A Context and temporary directory.
/// ///
/// The temporary directory can be used to store the SQLite database, /// The temporary directory can be used to store the SQLite database,
@@ -26,13 +24,11 @@ pub struct TestContext {
/// [Context]: crate::context::Context /// [Context]: crate::context::Context
pub fn test_context(cb: Option<dc_callback_t>) -> TestContext { pub fn test_context(cb: Option<dc_callback_t>) -> TestContext {
unsafe { unsafe {
let mut ctx = dc_context_new(cb, std::ptr::null_mut(), std::ptr::null_mut()); let mut ctx = dc_context_new(cb, std::ptr::null_mut(), None);
let dir = tempdir().unwrap(); let dir = tempdir().unwrap();
let dbfile = dir.path().join("db.sqlite"); let dbfile = dir.path().join("db.sqlite");
let dbfile_c = dbfile.to_c_string().unwrap(); assert!(
assert_eq!( dc_open(&mut ctx, dbfile.to_str().unwrap(), None),
dc_open(&mut ctx, dbfile_c.as_ptr(), std::ptr::null()),
1,
"Failed to open {}", "Failed to open {}",
dbfile.display(), dbfile.display(),
); );

View File

@@ -2,7 +2,6 @@
use crate::constants::Event; use crate::constants::Event;
use crate::context::Context; use crate::context::Context;
pub use mmime::carray::*;
pub use mmime::clist::*; pub use mmime::clist::*;
pub use rusqlite::ffi::*; pub use rusqlite::ffi::*;
@@ -34,10 +33,8 @@ the online state. */
pub type dc_precheck_imf_t = pub type dc_precheck_imf_t =
unsafe fn(_: &Context, _: *const libc::c_char, _: &str, _: u32) -> libc::c_int; unsafe fn(_: &Context, _: *const libc::c_char, _: &str, _: u32) -> libc::c_int;
pub type dc_set_config_t = pub type dc_set_config_t = fn(_: &Context, _: &str, _: Option<&str>) -> ();
unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char) -> (); pub type dc_get_config_t = fn(_: &Context, _: &str) -> Option<String>;
pub type dc_get_config_t =
unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char) -> *mut libc::c_char;
pub type sqlite_int64 = i64; pub type sqlite_int64 = i64;
pub type sqlite3_int64 = sqlite_int64; pub type sqlite3_int64 = sqlite_int64;

View File

@@ -1,5 +1,3 @@
use crate::types::*;
pub use libc::{ pub use libc::{
calloc, exit, free, malloc, memcmp, memcpy, memmove, memset, realloc, strcat, strchr, strcmp, calloc, exit, free, malloc, memcmp, memcpy, memmove, memset, realloc, strcat, strchr, strcmp,
strcpy, strcspn, strlen, strncmp, strncpy, strrchr, strspn, strstr, strtol, system, strcpy, strcspn, strlen, strncmp, strncpy, strrchr, strspn, strstr, strtol, system,
@@ -37,14 +35,6 @@ pub fn strndup(s: *const libc::c_char, n: libc::c_ulong) -> *mut libc::c_char {
extern "C" { extern "C" {
pub fn clock() -> libc::clock_t; pub fn clock() -> libc::clock_t;
pub fn qsort(
__base: *mut libc::c_void,
__nel: size_t,
__width: size_t,
__compar: Option<
unsafe extern "C" fn(_: *const libc::c_void, _: *const libc::c_void) -> libc::c_int,
>,
);
// -- DC Methods // -- DC Methods
pub fn dc_mprintf(format: *const libc::c_char, _: ...) -> *mut libc::c_char; pub fn dc_mprintf(format: *const libc::c_char, _: ...) -> *mut libc::c_char;

View File

@@ -8,11 +8,11 @@ use tempfile::{tempdir, TempDir};
use deltachat::config; use deltachat::config;
use deltachat::constants::*; use deltachat::constants::*;
use deltachat::contact::*;
use deltachat::context::*; use deltachat::context::*;
use deltachat::dc_array::*; use deltachat::dc_array::*;
use deltachat::dc_chat::*; use deltachat::dc_chat::*;
use deltachat::dc_configure::*; use deltachat::dc_configure::*;
use deltachat::dc_contact::*;
use deltachat::dc_imex::*; use deltachat::dc_imex::*;
use deltachat::dc_location::*; use deltachat::dc_location::*;
use deltachat::dc_lot::*; use deltachat::dc_lot::*;
@@ -273,7 +273,6 @@ unsafe fn stress_functions(context: &Context) {
assert!(res.contains(" configured_send_port ")); assert!(res.contains(" configured_send_port "));
assert!(res.contains(" configured_server_flags ")); assert!(res.contains(" configured_server_flags "));
let mut ok: libc::c_int;
let mut buf_0: *mut libc::c_char; let mut buf_0: *mut libc::c_char;
let mut headerline: *const libc::c_char = 0 as *const libc::c_char; let mut headerline: *const libc::c_char = 0 as *const libc::c_char;
let mut setupcodebegin: *const libc::c_char = 0 as *const libc::c_char; let mut setupcodebegin: *const libc::c_char = 0 as *const libc::c_char;
@@ -283,14 +282,14 @@ unsafe fn stress_functions(context: &Context) {
b"-----BEGIN PGP MESSAGE-----\nNoVal:\n\ndata\n-----END PGP MESSAGE-----\x00" as *const u8 b"-----BEGIN PGP MESSAGE-----\nNoVal:\n\ndata\n-----END PGP MESSAGE-----\x00" as *const u8
as *const libc::c_char, as *const libc::c_char,
); );
ok = dc_split_armored_data( let ok = dc_split_armored_data(
buf_0, buf_0,
&mut headerline, &mut headerline,
&mut setupcodebegin, &mut setupcodebegin,
0 as *mut *const libc::c_char, 0 as *mut *const libc::c_char,
&mut base64, &mut base64,
); );
assert_eq!(ok, 1); assert!(ok);
assert!(!headerline.is_null()); assert!(!headerline.is_null());
assert_eq!( assert_eq!(
strcmp( strcmp(
@@ -308,7 +307,7 @@ unsafe fn stress_functions(context: &Context) {
buf_0 = buf_0 =
strdup(b"-----BEGIN PGP MESSAGE-----\n\ndat1\n-----END PGP MESSAGE-----\n-----BEGIN PGP MESSAGE-----\n\ndat2\n-----END PGP MESSAGE-----\x00" strdup(b"-----BEGIN PGP MESSAGE-----\n\ndat1\n-----END PGP MESSAGE-----\n-----BEGIN PGP MESSAGE-----\n\ndat2\n-----END PGP MESSAGE-----\x00"
as *const u8 as *const libc::c_char); as *const u8 as *const libc::c_char);
ok = dc_split_armored_data( let ok = dc_split_armored_data(
buf_0, buf_0,
&mut headerline, &mut headerline,
&mut setupcodebegin, &mut setupcodebegin,
@@ -316,7 +315,7 @@ unsafe fn stress_functions(context: &Context) {
&mut base64, &mut base64,
); );
assert_eq!(ok, 1); assert!(ok);
assert!(!headerline.is_null()); assert!(!headerline.is_null());
assert_eq!( assert_eq!(
strcmp( strcmp(
@@ -335,7 +334,7 @@ unsafe fn stress_functions(context: &Context) {
b"foo \n -----BEGIN PGP MESSAGE----- \n base64-123 \n -----END PGP MESSAGE-----\x00" b"foo \n -----BEGIN PGP MESSAGE----- \n base64-123 \n -----END PGP MESSAGE-----\x00"
as *const u8 as *const libc::c_char, as *const u8 as *const libc::c_char,
); );
ok = dc_split_armored_data( let ok = dc_split_armored_data(
buf_0, buf_0,
&mut headerline, &mut headerline,
&mut setupcodebegin, &mut setupcodebegin,
@@ -343,7 +342,7 @@ unsafe fn stress_functions(context: &Context) {
&mut base64, &mut base64,
); );
assert_eq!(ok, 1); assert!(ok);
assert!(!headerline.is_null()); assert!(!headerline.is_null());
assert_eq!( assert_eq!(
strcmp( strcmp(
@@ -360,7 +359,7 @@ unsafe fn stress_functions(context: &Context) {
free(buf_0 as *mut libc::c_void); free(buf_0 as *mut libc::c_void);
buf_0 = strdup(b"foo-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char); buf_0 = strdup(b"foo-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char);
ok = dc_split_armored_data( let ok = dc_split_armored_data(
buf_0, buf_0,
&mut headerline, &mut headerline,
&mut setupcodebegin, &mut setupcodebegin,
@@ -368,19 +367,19 @@ unsafe fn stress_functions(context: &Context) {
&mut base64, &mut base64,
); );
assert_eq!(ok, 0); assert!(!ok);
free(buf_0 as *mut libc::c_void); free(buf_0 as *mut libc::c_void);
buf_0 = buf_0 =
strdup(b"foo \n -----BEGIN PGP MESSAGE-----\n Passphrase-BeGIN : 23 \n \n base64-567 \r\n abc \n -----END PGP MESSAGE-----\n\n\n\x00" strdup(b"foo \n -----BEGIN PGP MESSAGE-----\n Passphrase-BeGIN : 23 \n \n base64-567 \r\n abc \n -----END PGP MESSAGE-----\n\n\n\x00"
as *const u8 as *const libc::c_char); as *const u8 as *const libc::c_char);
ok = dc_split_armored_data( let ok = dc_split_armored_data(
buf_0, buf_0,
&mut headerline, &mut headerline,
&mut setupcodebegin, &mut setupcodebegin,
0 as *mut *const libc::c_char, 0 as *mut *const libc::c_char,
&mut base64, &mut base64,
); );
assert_eq!(ok, 1); assert!(ok);
assert!(!headerline.is_null()); assert!(!headerline.is_null());
assert_eq!( assert_eq!(
strcmp( strcmp(
@@ -407,14 +406,14 @@ unsafe fn stress_functions(context: &Context) {
buf_0 = buf_0 =
strdup(b"-----BEGIN PGP PRIVATE KEY BLOCK-----\n Autocrypt-Prefer-Encrypt : mutual \n\nbase64\n-----END PGP PRIVATE KEY BLOCK-----\x00" strdup(b"-----BEGIN PGP PRIVATE KEY BLOCK-----\n Autocrypt-Prefer-Encrypt : mutual \n\nbase64\n-----END PGP PRIVATE KEY BLOCK-----\x00"
as *const u8 as *const libc::c_char); as *const u8 as *const libc::c_char);
ok = dc_split_armored_data( let ok = dc_split_armored_data(
buf_0, buf_0,
&mut headerline, &mut headerline,
0 as *mut *const libc::c_char, 0 as *mut *const libc::c_char,
&mut preferencrypt, &mut preferencrypt,
&mut base64, &mut base64,
); );
assert_eq!(ok, 1); assert!(ok);
assert!(!headerline.is_null()); assert!(!headerline.is_null());
assert_eq!( assert_eq!(
strcmp( strcmp(
@@ -470,16 +469,13 @@ unsafe fn stress_functions(context: &Context) {
let mut setupcodebegin_0: *const libc::c_char = 0 as *const libc::c_char; let mut setupcodebegin_0: *const libc::c_char = 0 as *const libc::c_char;
let mut preferencrypt_0: *const libc::c_char = 0 as *const libc::c_char; let mut preferencrypt_0: *const libc::c_char = 0 as *const libc::c_char;
buf_1 = strdup(S_EM_SETUPFILE); buf_1 = strdup(S_EM_SETUPFILE);
assert_ne!( assert!(dc_split_armored_data(
0, buf_1,
dc_split_armored_data( &mut headerline_0,
buf_1, &mut setupcodebegin_0,
&mut headerline_0, &mut preferencrypt_0,
&mut setupcodebegin_0, 0 as *mut *const libc::c_char,
&mut preferencrypt_0, ));
0 as *mut *const libc::c_char,
)
);
assert!(!headerline_0.is_null()); assert!(!headerline_0.is_null());
assert_eq!( assert_eq!(
0, 0,
@@ -499,16 +495,13 @@ unsafe fn stress_functions(context: &Context) {
free(buf_1 as *mut libc::c_void); free(buf_1 as *mut libc::c_void);
buf_1 = dc_decrypt_setup_file(context, S_EM_SETUPCODE, S_EM_SETUPFILE); buf_1 = dc_decrypt_setup_file(context, S_EM_SETUPCODE, S_EM_SETUPFILE);
assert!(!buf_1.is_null()); assert!(!buf_1.is_null());
assert_ne!( assert!(dc_split_armored_data(
0, buf_1,
dc_split_armored_data( &mut headerline_0,
buf_1, &mut setupcodebegin_0,
&mut headerline_0, &mut preferencrypt_0,
&mut setupcodebegin_0, 0 as *mut *const libc::c_char,
&mut preferencrypt_0, ));
0 as *mut *const libc::c_char,
)
);
assert!(!headerline_0.is_null()); assert!(!headerline_0.is_null());
assert_eq!( assert_eq!(
strcmp( strcmp(
@@ -528,65 +521,21 @@ unsafe fn stress_functions(context: &Context) {
); );
free(buf_1 as *mut libc::c_void); free(buf_1 as *mut libc::c_void);
if 0 != dc_is_configured(context) { if 0 != dc_is_configured(context) {
let setupfile: *mut libc::c_char; let setupcode = dc_create_setup_code(context);
let setupcode_c = let setupcode_c = CString::yolo(setupcode.clone());
CString::new(dc_create_setup_code(context)).expect("invalid string converted"); let setupfile = dc_render_setup_file(context, &setupcode).unwrap();
assert_eq!(setupcode_c.to_bytes().len(), 44); let setupfile_c = CString::yolo(setupfile);
let setupcode = setupcode_c.as_ptr();
assert!(
0 != !(*setupcode.offset(4isize) as libc::c_int == '-' as i32
&& *setupcode.offset(9isize) as libc::c_int == '-' as i32
&& *setupcode.offset(14isize) as libc::c_int == '-' as i32
&& *setupcode.offset(19isize) as libc::c_int == '-' as i32
&& *setupcode.offset(24isize) as libc::c_int == '-' as i32
&& *setupcode.offset(29isize) as libc::c_int == '-' as i32
&& *setupcode.offset(34isize) as libc::c_int == '-' as i32
&& *setupcode.offset(39isize) as libc::c_int == '-' as i32)
as usize
);
setupfile = dc_render_setup_file(context, setupcode);
assert!(!setupfile.is_null());
let buf_2: *mut libc::c_char = dc_strdup(setupfile);
let mut headerline_1: *const libc::c_char = 0 as *const libc::c_char;
let mut setupcodebegin_1: *const libc::c_char = 0 as *const libc::c_char;
assert_eq!(
0,
dc_split_armored_data(
buf_2,
&mut headerline_1,
&mut setupcodebegin_1,
0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char,
)
);
assert!(!headerline_1.is_null());
assert_eq!(
strcmp(
headerline_1,
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
),
0
);
assert!(
!(!setupcodebegin_1.is_null()
&& strlen(setupcodebegin_1) == 2
&& strncmp(setupcodebegin_1, setupcode, 2) == 0i32)
);
free(buf_2 as *mut libc::c_void);
let payload: *mut libc::c_char; let payload: *mut libc::c_char;
let mut headerline_2: *const libc::c_char = 0 as *const libc::c_char; let mut headerline_2: *const libc::c_char = 0 as *const libc::c_char;
payload = dc_decrypt_setup_file(context, setupcode, setupfile); payload = dc_decrypt_setup_file(context, setupcode_c.as_ptr(), setupfile_c.as_ptr());
assert!(payload.is_null()); assert!(payload.is_null());
assert_eq!( assert!(!dc_split_armored_data(
0, payload,
dc_split_armored_data( &mut headerline_2,
payload, 0 as *mut *const libc::c_char,
&mut headerline_2, 0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char, 0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char, ));
0 as *mut *const libc::c_char,
)
);
assert!(!headerline_2.is_null()); assert!(!headerline_2.is_null());
assert_eq!( assert_eq!(
strcmp( strcmp(
@@ -596,7 +545,6 @@ unsafe fn stress_functions(context: &Context) {
0 0
); );
free(payload as *mut libc::c_void); free(payload as *mut libc::c_void);
free(setupfile as *mut libc::c_void);
} }
if 0 != dc_is_configured(context) { if 0 != dc_is_configured(context) {
@@ -684,7 +632,7 @@ fn test_encryption_decryption() {
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----")); assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
let ctext_signed_bytes = ctext.len(); let ctext_signed_bytes = ctext.len();
let ctext_signed = to_cstring(ctext); let ctext_signed = CString::yolo(ctext);
let ctext = dc_pgp_pk_encrypt( let ctext = dc_pgp_pk_encrypt(
original_text as *const libc::c_void, original_text as *const libc::c_void,
@@ -697,7 +645,7 @@ fn test_encryption_decryption() {
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----")); assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
let ctext_unsigned_bytes = ctext.len(); let ctext_unsigned_bytes = ctext.len();
let ctext_unsigned = to_cstring(ctext); let ctext_unsigned = CString::yolo(ctext);
let mut keyring = Keyring::default(); let mut keyring = Keyring::default();
keyring.add_owned(private_key); keyring.add_owned(private_key);
@@ -711,7 +659,7 @@ fn test_encryption_decryption() {
let mut valid_signatures: HashSet<String> = Default::default(); let mut valid_signatures: HashSet<String> = Default::default();
let plain = dc_pgp_pk_decrypt( let plain = dc_pgp_pk_decrypt(
ctext_signed as *const _, ctext_signed.as_ptr() as *const _,
ctext_signed_bytes, ctext_signed_bytes,
&keyring, &keyring,
&public_keyring, &public_keyring,
@@ -726,7 +674,7 @@ fn test_encryption_decryption() {
let empty_keyring = Keyring::default(); let empty_keyring = Keyring::default();
let plain = dc_pgp_pk_decrypt( let plain = dc_pgp_pk_decrypt(
ctext_signed as *const _, ctext_signed.as_ptr() as *const _,
ctext_signed_bytes, ctext_signed_bytes,
&keyring, &keyring,
&empty_keyring, &empty_keyring,
@@ -739,7 +687,7 @@ fn test_encryption_decryption() {
valid_signatures.clear(); valid_signatures.clear();
let plain = dc_pgp_pk_decrypt( let plain = dc_pgp_pk_decrypt(
ctext_signed as *const _, ctext_signed.as_ptr() as *const _,
ctext_signed_bytes, ctext_signed_bytes,
&keyring, &keyring,
&public_keyring2, &public_keyring2,
@@ -754,7 +702,7 @@ fn test_encryption_decryption() {
public_keyring2.add_ref(&public_key); public_keyring2.add_ref(&public_key);
let plain = dc_pgp_pk_decrypt( let plain = dc_pgp_pk_decrypt(
ctext_signed as *const _, ctext_signed.as_ptr() as *const _,
ctext_signed_bytes, ctext_signed_bytes,
&keyring, &keyring,
&public_keyring2, &public_keyring2,
@@ -767,7 +715,7 @@ fn test_encryption_decryption() {
valid_signatures.clear(); valid_signatures.clear();
let plain = dc_pgp_pk_decrypt( let plain = dc_pgp_pk_decrypt(
ctext_unsigned as *const _, ctext_unsigned.as_ptr() as *const _,
ctext_unsigned_bytes, ctext_unsigned_bytes,
&keyring, &keyring,
&public_keyring, &public_keyring,
@@ -775,7 +723,6 @@ fn test_encryption_decryption() {
) )
.unwrap(); .unwrap();
free(ctext_unsigned as *mut _);
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),); assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
valid_signatures.clear(); valid_signatures.clear();
@@ -786,7 +733,7 @@ fn test_encryption_decryption() {
public_keyring.add_ref(&public_key); public_keyring.add_ref(&public_key);
let plain = dc_pgp_pk_decrypt( let plain = dc_pgp_pk_decrypt(
ctext_signed as *const _, ctext_signed.as_ptr() as *const _,
ctext_signed_bytes, ctext_signed_bytes,
&keyring, &keyring,
&public_keyring, &public_keyring,
@@ -794,7 +741,6 @@ fn test_encryption_decryption() {
) )
.unwrap(); .unwrap();
free(ctext_signed as *mut _);
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),); assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
} }
} }
@@ -815,16 +761,14 @@ struct TestContext {
} }
unsafe fn create_test_context() -> TestContext { unsafe fn create_test_context() -> TestContext {
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut()); let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), None);
let dir = tempdir().unwrap(); let dir = tempdir().unwrap();
let dbfile = to_cstring(dir.path().join("db.sqlite").to_str().unwrap()); let dbfile = dir.path().join("db.sqlite");
assert_eq!( assert!(
dc_open(&mut ctx, dbfile, std::ptr::null()), dc_open(&mut ctx, dbfile.to_str().unwrap(), None),
1,
"Failed to open {}", "Failed to open {}",
as_str(dbfile as *const libc::c_char) dbfile.display()
); );
free(dbfile as *mut _);
TestContext { ctx: ctx, dir: dir } TestContext { ctx: ctx, dir: dir }
} }
@@ -842,24 +786,24 @@ fn test_dc_kml_parse() {
assert!(!kml.addr.is_null()); assert!(!kml.addr.is_null());
assert_eq!(as_str(kml.addr as *const libc::c_char), "user@example.org",); assert_eq!(as_str(kml.addr as *const libc::c_char), "user@example.org",);
assert_eq!(dc_array_get_cnt(kml.locations), 2); let locations_ref = &kml.locations.as_ref().unwrap();
assert_eq!(locations_ref.len(), 2);
assert!(dc_array_get_latitude(kml.locations, 0) > 53.6f64); assert!(locations_ref[0].latitude > 53.6f64);
assert!(dc_array_get_latitude(kml.locations, 0) < 53.8f64); assert!(locations_ref[0].latitude < 53.8f64);
assert!(dc_array_get_longitude(kml.locations, 0) > 9.3f64); assert!(locations_ref[0].longitude > 9.3f64);
assert!(dc_array_get_longitude(kml.locations, 0) < 9.5f64); assert!(locations_ref[0].longitude < 9.5f64);
assert!(dc_array_get_accuracy(kml.locations, 0) > 31.9f64); assert!(locations_ref[0].accuracy > 31.9f64);
assert!(dc_array_get_accuracy(kml.locations, 0) < 32.1f64); assert!(locations_ref[0].accuracy < 32.1f64);
assert_eq!(dc_array_get_timestamp(kml.locations, 0), 1551906597); assert_eq!(locations_ref[0].timestamp, 1551906597);
assert!(dc_array_get_latitude(kml.locations, 1) > 63.6f64); assert!(locations_ref[1].latitude > 63.6f64);
assert!(dc_array_get_latitude(kml.locations, 1) < 63.8f64); assert!(locations_ref[1].latitude < 63.8f64);
assert!(dc_array_get_longitude(kml.locations, 1) > 19.3f64); assert!(locations_ref[1].longitude > 19.3f64);
assert!(dc_array_get_longitude(kml.locations, 1) < 19.5f64); assert!(locations_ref[1].longitude < 19.5f64);
assert!(dc_array_get_accuracy(kml.locations, 1) > 2.4f64); assert!(locations_ref[1].accuracy > 2.4f64);
assert!(dc_array_get_accuracy(kml.locations, 1) < 2.6f64); assert!(locations_ref[1].accuracy < 2.6f64);
assert_eq!(locations_ref[1].timestamp, 1544739072);
assert_eq!(dc_array_get_timestamp(kml.locations, 1), 1544739072);
dc_kml_unref(&mut kml); dc_kml_unref(&mut kml);
} }
@@ -898,7 +842,7 @@ fn test_dc_mimeparser_with_context() {
b"Chat-Version\x00" as *const u8 as *const libc::c_char, b"Chat-Version\x00" as *const u8 as *const libc::c_char,
); );
assert_eq!(as_str((*of).fld_value as *const libc::c_char), "1.0",); assert_eq!(as_str((*of).fld_value as *const libc::c_char), "1.0",);
assert_eq!(carray_count(mimeparser.parts), 1); assert_eq!(mimeparser.parts.len(), 1);
dc_mimeparser_unref(&mut mimeparser); dc_mimeparser_unref(&mut mimeparser);
} }
@@ -946,29 +890,20 @@ fn test_stress_tests() {
fn test_get_contacts() { fn test_get_contacts() {
unsafe { unsafe {
let context = create_test_context(); let context = create_test_context();
let name = to_cstring("some2"); let contacts = Contact::get_all(&context.ctx, 0, Some("some2")).unwrap();
let contacts = dc_get_contacts(&context.ctx, 0, name);
assert_eq!(dc_array_get_cnt(contacts), 0); assert_eq!(dc_array_get_cnt(contacts), 0);
dc_array_unref(contacts); dc_array_unref(contacts);
free(name as *mut _);
let name = to_cstring("bob"); let id = Contact::create(&context.ctx, "bob", "bob@mail.de").unwrap();
let email = to_cstring("bob@mail.de");
let id = dc_create_contact(&context.ctx, name, email);
assert_ne!(id, 0); assert_ne!(id, 0);
let contacts = dc_get_contacts(&context.ctx, 0, name); let contacts = Contact::get_all(&context.ctx, 0, Some("bob")).unwrap();
assert_eq!(dc_array_get_cnt(contacts), 1); assert_eq!(dc_array_get_cnt(contacts), 1);
dc_array_unref(contacts); dc_array_unref(contacts);
let name2 = to_cstring("alice"); let contacts = Contact::get_all(&context.ctx, 0, Some("alice")).unwrap();
let contacts = dc_get_contacts(&context.ctx, 0, name2);
assert_eq!(dc_array_get_cnt(contacts), 0); assert_eq!(dc_array_get_cnt(contacts), 0);
dc_array_unref(contacts); dc_array_unref(contacts);
free(name as *mut _);
free(name2 as *mut _);
free(email as *mut _);
} }
} }
@@ -976,12 +911,7 @@ fn test_get_contacts() {
fn test_chat() { fn test_chat() {
unsafe { unsafe {
let context = create_test_context(); let context = create_test_context();
let name = to_cstring("bob"); let contact1 = Contact::create(&context.ctx, "bob", "bob@mail.de").unwrap();
let email = to_cstring("bob@mail.de");
let contact1 = dc_create_contact(&context.ctx, name, email);
free(name as *mut _);
free(email as *mut _);
assert_ne!(contact1, 0); assert_ne!(contact1, 0);
let chat_id = dc_create_chat_by_contact_id(&context.ctx, contact1); let chat_id = dc_create_chat_by_contact_id(&context.ctx, contact1);
@@ -1001,14 +931,12 @@ fn test_chat() {
#[test] #[test]
fn test_wrong_db() { fn test_wrong_db() {
unsafe { unsafe {
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut()); let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), None);
let dir = tempdir().unwrap(); let dir = tempdir().unwrap();
let dbfile = dir.path().join("db.sqlite"); let dbfile = dir.path().join("db.sqlite");
std::fs::write(&dbfile, b"123").unwrap(); std::fs::write(&dbfile, b"123").unwrap();
let dbfile_c = to_cstring(dbfile.to_str().unwrap()); let res = dc_open(&mut ctx, dbfile.to_str().unwrap(), None);
let res = dc_open(&mut ctx, dbfile_c, std::ptr::null()); assert!(!res);
free(dbfile_c as *mut _);
assert_eq!(res, 0);
} }
} }