Change type of function from `const char *' to &str (#451)

Change type of function from `const char *' to &str
This commit is contained in:
Friedel Ziegelmayer
2019-09-08 11:51:16 +02:00
committed by GitHub
6 changed files with 274 additions and 346 deletions

View File

@@ -171,51 +171,20 @@ impl<'a> Chat<'a> {
return "Err".into(); return "Err".into();
} }
unsafe fn get_parent_mime_headers( pub fn get_parent_mime_headers(&self) -> Option<(String, String, String)> {
&self, let collect = |row: &rusqlite::Row| Ok((row.get(0)?, row.get(1)?, row.get(2)?));
parent_rfc724_mid: *mut *mut libc::c_char, let params = params![self.id as i32, DC_CONTACT_ID_SELF as i32];
parent_in_reply_to: *mut *mut libc::c_char, let sql = &self.context.sql;
parent_references: *mut *mut libc::c_char, let main_query = "SELECT rfc724_mid, mime_in_reply_to, mime_references \
) -> Result<(), Error> { FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT max(timestamp) \
if !(parent_rfc724_mid.is_null() FROM msgs WHERE chat_id=?1 AND from_id!=?2);";
|| parent_in_reply_to.is_null() let fallback_query = "SELECT rfc724_mid, mime_in_reply_to, mime_references \
|| parent_references.is_null()) FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT min(timestamp) \
{ FROM msgs WHERE chat_id=?1 AND from_id==?2);";
// prefer a last message that isn't from us
let next = self
.context
.sql
.query_row(
"SELECT rfc724_mid, mime_in_reply_to, mime_references \
FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT max(timestamp) \
FROM msgs WHERE chat_id=?1 AND from_id!=?2);",
params![self.id as i32, DC_CONTACT_ID_SELF as i32],
|row| {
*parent_rfc724_mid = row.get::<_, String>(0)?.strdup();
*parent_in_reply_to = row.get::<_, String>(1)?.strdup();
*parent_references = row.get::<_, String>(2)?.strdup();
Ok(())
},
)
.is_ok();
if !next { sql.query_row(main_query, params, collect)
self.context.sql.query_row( .or_else(|_| sql.query_row(fallback_query, params, collect))
"SELECT rfc724_mid, mime_in_reply_to, mime_references \ .ok()
FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT min(timestamp) \
FROM msgs WHERE chat_id=?1 AND from_id==?2);",
params![self.id as i32, DC_CONTACT_ID_SELF as i32],
|row| {
*parent_rfc724_mid = row.get::<_, String>(0)?.strdup();
*parent_in_reply_to = row.get::<_, String>(1)?.strdup();
*parent_references = row.get::<_, String>(2)?.strdup();
Ok(())
},
)?;
}
}
Ok(())
} }
pub unsafe fn get_profile_image(&self) -> Option<String> { pub unsafe fn get_profile_image(&self) -> Option<String> {
@@ -277,13 +246,8 @@ impl<'a> Chat<'a> {
) -> Result<u32, Error> { ) -> Result<u32, Error> {
let mut do_guarantee_e2ee: libc::c_int; let mut do_guarantee_e2ee: libc::c_int;
let e2ee_enabled: libc::c_int; let e2ee_enabled: libc::c_int;
let mut OK_TO_CONTINUE = true; let mut new_references = "".into();
let mut parent_rfc724_mid = ptr::null_mut(); let mut new_in_reply_to = "".into();
let mut parent_references = ptr::null_mut();
let mut parent_in_reply_to = ptr::null_mut();
let mut new_rfc724_mid = ptr::null_mut();
let mut new_references = ptr::null_mut();
let mut new_in_reply_to = ptr::null_mut();
let mut msg_id = 0; let mut msg_id = 0;
let mut to_id = 0; let mut to_id = 0;
let mut location_id = 0; let mut location_id = 0;
@@ -293,7 +257,10 @@ impl<'a> Chat<'a> {
|| self.typ == Chattype::VerifiedGroup) || self.typ == Chattype::VerifiedGroup)
{ {
error!(context, 0, "Cannot send to chat type #{}.", self.typ,); error!(context, 0, "Cannot send to chat type #{}.", self.typ,);
} else if (self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup) return Ok(0);
}
if (self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup)
&& 0 == is_contact_in_chat(context, self.id, 1 as u32) && 0 == is_contact_in_chat(context, self.id, 1 as u32)
{ {
log_event!( log_event!(
@@ -302,200 +269,173 @@ impl<'a> Chat<'a> {
0, 0,
"Cannot send message; self not in group.", "Cannot send message; self not in group.",
); );
} else { return Ok(0);
if let Some(from) = context.sql.get_config(context, "configured_addr") { }
let from_c = CString::yolo(from);
new_rfc724_mid = dc_create_outgoing_rfc724_mid(
if self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup {
self.grpid.strdup()
} else {
ptr::null_mut()
},
from_c.as_ptr(),
);
if self.typ == Chattype::Single { if let Some(from) = context.sql.get_config(context, "configured_addr") {
if let Some(id) = context.sql.query_row_col( let new_rfc724_mid = {
context, let grpid = match self.typ {
"SELECT contact_id FROM chats_contacts WHERE chat_id=?;", Chattype::Group | Chattype::VerifiedGroup => Some(self.grpid.as_str()),
params![self.id as i32], _ => None,
0, };
) { dc_create_outgoing_rfc724_mid_safe(grpid, &from)
to_id = id; };
} else {
error!( if self.typ == Chattype::Single {
context, if let Some(id) = context.sql.query_row_col(
0, "Cannot send message, contact for chat #{} not found.", self.id, context,
); "SELECT contact_id FROM chats_contacts WHERE chat_id=?;",
OK_TO_CONTINUE = false; params![self.id as i32],
} 0,
) {
to_id = id;
} else { } else {
if self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup { error!(
if self.param.get_int(Param::Unpromoted).unwrap_or_default() == 1 { context,
self.param.remove(Param::Unpromoted); 0, "Cannot send message, contact for chat #{} not found.", self.id,
self.update_param().unwrap(); );
} return Ok(0);
}
} else {
if self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup {
if self.param.get_int(Param::Unpromoted).unwrap_or_default() == 1 {
self.param.remove(Param::Unpromoted);
self.update_param().unwrap();
} }
} }
if OK_TO_CONTINUE { }
/* check if we can guarantee E2EE for this message.
if we guarantee E2EE, and circumstances change
so that E2EE is no longer available at a later point (reset, changed settings),
we do not send the message out at all */
do_guarantee_e2ee = 0;
e2ee_enabled = context
.sql
.get_config_int(context, "e2ee_enabled")
.unwrap_or_else(|| 1);
if 0 != e2ee_enabled
&& msg.param.get_int(Param::ForcePlaintext).unwrap_or_default() == 0
{
let mut can_encrypt = 1;
let mut all_mutual = 1;
let res = context.sql.query_row( /* check if we can guarantee E2EE for this message.
"SELECT ps.prefer_encrypted, c.addr \ if we guarantee E2EE, and circumstances change
FROM chats_contacts cc \ so that E2EE is no longer available at a later point (reset, changed settings),
LEFT JOIN contacts c ON cc.contact_id=c.id \ we do not send the message out at all */
LEFT JOIN acpeerstates ps ON c.addr=ps.addr \ do_guarantee_e2ee = 0;
WHERE cc.chat_id=? AND cc.contact_id>9;", e2ee_enabled = context
params![self.id], .sql
|row| { .get_config_int(context, "e2ee_enabled")
let state: String = row.get(1)?; .unwrap_or_else(|| 1);
if 0 != e2ee_enabled
&& msg.param.get_int(Param::ForcePlaintext).unwrap_or_default() == 0
{
let mut can_encrypt = 1;
let mut all_mutual = 1;
if let Some(prefer_encrypted) = row.get::<_, Option<i32>>(0)? { let res = context.sql.query_row(
if prefer_encrypted != 1 { "SELECT ps.prefer_encrypted, c.addr \
info!( FROM chats_contacts cc \
context, LEFT JOIN contacts c ON cc.contact_id=c.id \
0, LEFT JOIN acpeerstates ps ON c.addr=ps.addr \
"[autocrypt] peerstate for {} is {}", WHERE cc.chat_id=? AND cc.contact_id>9;",
state, params![self.id],
if prefer_encrypted == 0 { |row| {
"NOPREFERENCE" let state: String = row.get(1)?;
} else {
"RESET" if let Some(prefer_encrypted) = row.get::<_, Option<i32>>(0)? {
}, if prefer_encrypted != 1 {
); info!(
all_mutual = 0; context,
} 0,
} else { "[autocrypt] peerstate for {} is {}",
info!(context, 0, "[autocrypt] no peerstate for {}", state,); state,
can_encrypt = 0; if prefer_encrypted == 0 {
all_mutual = 0; "NOPREFERENCE"
} } else {
Ok(()) "RESET"
}, },
); );
match res { all_mutual = 0;
Ok(_) => {}
Err(err) => {
warn!(context, 0, "chat: failed to load peerstates: {:?}", err);
}
}
if 0 != can_encrypt {
if 0 != all_mutual {
do_guarantee_e2ee = 1;
} else if last_msg_in_chat_encrypted(context, &context.sql, self.id) {
do_guarantee_e2ee = 1;
} }
} else {
info!(context, 0, "[autocrypt] no peerstate for {}", state,);
can_encrypt = 0;
all_mutual = 0;
} }
Ok(())
},
);
match res {
Ok(_) => {}
Err(err) => {
warn!(context, 0, "chat: failed to load peerstates: {:?}", err);
} }
if 0 != do_guarantee_e2ee { }
msg.param.set_int(Param::GuranteeE2ee, 1);
if 0 != can_encrypt {
if 0 != all_mutual {
do_guarantee_e2ee = 1;
} else if last_msg_in_chat_encrypted(context, &context.sql, self.id) {
do_guarantee_e2ee = 1;
} }
msg.param.remove(Param::ErroneousE2ee); }
if !self.is_self_talk() }
&& self if 0 != do_guarantee_e2ee {
.get_parent_mime_headers( msg.param.set_int(Param::GuranteeE2ee, 1);
&mut parent_rfc724_mid, }
&mut parent_in_reply_to, msg.param.remove(Param::ErroneousE2ee);
&mut parent_references, if !self.is_self_talk() {
) if let Some((parent_rfc724_mid, parent_in_reply_to, parent_references)) =
.is_ok() self.get_parent_mime_headers()
{ {
if !parent_rfc724_mid.is_null() if !parent_rfc724_mid.is_empty() {
&& 0 != *parent_rfc724_mid.offset(0isize) as libc::c_int new_in_reply_to = parent_rfc724_mid.clone();
{
new_in_reply_to = dc_strdup(parent_rfc724_mid)
}
if !parent_references.is_null() {
let space: *mut libc::c_char;
space = strchr(parent_references, ' ' as i32);
if !space.is_null() {
*space = 0 as libc::c_char
}
}
if !parent_references.is_null()
&& 0 != *parent_references.offset(0isize) as libc::c_int
&& !parent_rfc724_mid.is_null()
&& 0 != *parent_rfc724_mid.offset(0isize) as libc::c_int
{
new_references = dc_mprintf(
b"%s %s\x00" as *const u8 as *const libc::c_char,
parent_references,
parent_rfc724_mid,
)
} else if !parent_references.is_null()
&& 0 != *parent_references.offset(0isize) as libc::c_int
{
new_references = dc_strdup(parent_references)
} else if !parent_in_reply_to.is_null()
&& 0 != *parent_in_reply_to.offset(0isize) as libc::c_int
&& !parent_rfc724_mid.is_null()
&& 0 != *parent_rfc724_mid.offset(0isize) as libc::c_int
{
new_references = dc_mprintf(
b"%s %s\x00" as *const u8 as *const libc::c_char,
parent_in_reply_to,
parent_rfc724_mid,
)
} else if !parent_in_reply_to.is_null()
&& 0 != *parent_in_reply_to.offset(0isize) as libc::c_int
{
new_references = dc_strdup(parent_in_reply_to)
}
} }
let parent_references = if let Some(n) = parent_references.find(' ') {
&parent_references[0..n]
} else {
&parent_references
};
// add independent location to database if !parent_references.is_empty() && !parent_rfc724_mid.is_empty() {
new_references = format!("{} {}", parent_references, parent_rfc724_mid);
if msg.param.exists(Param::SetLatitude) { } else if !parent_references.is_empty() {
if sql::execute( new_references = parent_references.to_string();
context, } else if !parent_in_reply_to.is_empty() && !parent_rfc724_mid.is_empty() {
&context.sql, new_references = format!("{} {}", parent_in_reply_to, parent_rfc724_mid);
"INSERT INTO locations \ } else if !parent_in_reply_to.is_empty() {
(timestamp,from_id,chat_id, latitude,longitude,independent)\ new_references = parent_in_reply_to.clone();
VALUES (?,?,?, ?,?,1);",
params![
timestamp,
DC_CONTACT_ID_SELF,
self.id as i32,
msg.param.get_float(Param::SetLatitude).unwrap_or_default(),
msg.param.get_float(Param::SetLongitude).unwrap_or_default(),
],
)
.is_ok()
{
location_id = sql::get_rowid2(
context,
&context.sql,
"locations",
"timestamp",
timestamp,
"from_id",
DC_CONTACT_ID_SELF as i32,
);
}
} }
}
}
// add message to the database // add independent location to database
if sql::execute( if msg.param.exists(Param::SetLatitude) {
if sql::execute(
context,
&context.sql,
"INSERT INTO locations \
(timestamp,from_id,chat_id, latitude,longitude,independent)\
VALUES (?,?,?, ?,?,1);",
params![
timestamp,
DC_CONTACT_ID_SELF,
self.id as i32,
msg.param.get_float(Param::SetLatitude).unwrap_or_default(),
msg.param.get_float(Param::SetLongitude).unwrap_or_default(),
],
)
.is_ok()
{
location_id = sql::get_rowid2(
context,
&context.sql,
"locations",
"timestamp",
timestamp,
"from_id",
DC_CONTACT_ID_SELF as i32,
);
}
}
// add message to the database
if sql::execute(
context, context,
&context.sql, &context.sql,
"INSERT INTO msgs (rfc724_mid, chat_id, from_id, to_id, timestamp, type, state, txt, param, hidden, mime_in_reply_to, mime_references, location_id) VALUES (?,?,?,?,?, ?,?,?,?,?, ?,?,?);", "INSERT INTO msgs (rfc724_mid, chat_id, from_id, to_id, timestamp, type, state, txt, param, hidden, mime_in_reply_to, mime_references, location_id) VALUES (?,?,?,?,?, ?,?,?,?,?, ?,?,?);",
params![ params![
as_str(new_rfc724_mid), new_rfc724_mid,
self.id as i32, self.id as i32,
1i32, 1i32,
to_id as i32, to_id as i32,
@@ -505,8 +445,8 @@ impl<'a> Chat<'a> {
msg.text.as_ref().map_or("", String::as_str), msg.text.as_ref().map_or("", String::as_str),
msg.param.to_string(), msg.param.to_string(),
msg.hidden, msg.hidden,
to_string(new_in_reply_to), new_in_reply_to,
to_string(new_references), new_references,
location_id as i32, location_id as i32,
] ]
).is_ok() { ).is_ok() {
@@ -515,7 +455,7 @@ impl<'a> Chat<'a> {
&context.sql, &context.sql,
"msgs", "msgs",
"rfc724_mid", "rfc724_mid",
as_str(new_rfc724_mid), new_rfc724_mid,
); );
} else { } else {
error!( error!(
@@ -525,19 +465,10 @@ impl<'a> Chat<'a> {
self.id, self.id,
); );
} }
} } else {
} else { error!(context, 0, "Cannot send message, not configured.",);
error!(context, 0, "Cannot send message, not configured.",);
}
} }
free(parent_rfc724_mid as *mut libc::c_void);
free(parent_in_reply_to as *mut libc::c_void);
free(parent_references as *mut libc::c_void);
free(new_rfc724_mid as *mut libc::c_void);
free(new_in_reply_to as *mut libc::c_void);
free(new_references as *mut libc::c_void);
Ok(msg_id) Ok(msg_id)
} }
} }

View File

@@ -148,7 +148,7 @@ pub unsafe fn dc_mimefactory_load_msg(
for row in rows { for row in rows {
let (authname, addr) = row?; let (authname, addr) = row?;
let addr_c = addr.strdup(); 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) {
clist_insert_after( clist_insert_after(
factory.recipients_names, factory.recipients_names,
(*factory.recipients_names).last, (*factory.recipients_names).last,
@@ -183,7 +183,7 @@ pub unsafe fn dc_mimefactory_load_msg(
.unwrap_or_default(); .unwrap_or_default();
if !email_to_remove.is_empty() && email_to_remove != self_addr { if !email_to_remove.is_empty() && email_to_remove != self_addr {
if clist_search_string_nocase(factory.recipients_addr, email_to_remove_c) == 0 { if !clist_search_string_nocase(factory.recipients_addr, email_to_remove_c) {
clist_insert_after( clist_insert_after(
factory.recipients_names, factory.recipients_names,
(*factory.recipients_names).last, (*factory.recipients_names).last,

View File

@@ -32,10 +32,10 @@ dc_mimeparser_t has no deep dependencies to Context or to the database
#[repr(C)] #[repr(C)]
pub struct dc_mimepart_t { pub struct dc_mimepart_t {
pub type_0: Viewtype, pub type_0: Viewtype,
pub is_meta: libc::c_int, pub is_meta: bool,
pub int_mimetype: libc::c_int, pub int_mimetype: libc::c_int,
pub msg: Option<String>, pub msg: Option<String>,
pub msg_raw: *mut libc::c_char, pub msg_raw: Option<String>,
pub bytes: libc::c_int, pub bytes: libc::c_int,
pub param: Params, pub param: Params,
} }
@@ -50,11 +50,11 @@ pub struct dc_mimeparser_t<'a> {
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,
pub header_protected: *mut mailimf_fields, pub header_protected: *mut mailimf_fields,
pub subject: *mut libc::c_char, pub subject: Option<String>,
pub is_send_by_messenger: bool, pub is_send_by_messenger: bool,
pub decrypting_failed: libc::c_int, pub decrypting_failed: bool,
pub e2ee_helper: E2eeHelper, pub e2ee_helper: E2eeHelper,
pub is_forwarded: libc::c_int, pub is_forwarded: bool,
pub context: &'a Context, pub context: &'a Context,
pub reports: Vec<*mut mailmime>, pub reports: Vec<*mut mailmime>,
pub is_system_message: libc::c_int, pub is_system_message: libc::c_int,
@@ -69,11 +69,11 @@ pub fn dc_mimeparser_new(context: &Context) -> dc_mimeparser_t {
header: Default::default(), header: Default::default(),
header_root: std::ptr::null_mut(), header_root: std::ptr::null_mut(),
header_protected: std::ptr::null_mut(), header_protected: std::ptr::null_mut(),
subject: std::ptr::null_mut(), subject: None,
is_send_by_messenger: false, is_send_by_messenger: false,
decrypting_failed: 0, decrypting_failed: false,
e2ee_helper: Default::default(), e2ee_helper: Default::default(),
is_forwarded: 0, is_forwarded: false,
context, context,
reports: Vec::new(), reports: Vec::new(),
is_system_message: 0, is_system_message: 0,
@@ -87,10 +87,7 @@ pub unsafe fn dc_mimeparser_unref(mimeparser: &mut dc_mimeparser_t) {
} }
unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) { unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) {
for part in mimeparser.parts.drain(..) { mimeparser.parts = vec![];
dc_mimepart_unref(part);
}
assert!(mimeparser.parts.is_empty());
mimeparser.header_root = ptr::null_mut(); mimeparser.header_root = ptr::null_mut();
mimeparser.header.clear(); mimeparser.header.clear();
if !mimeparser.header_protected.is_null() { if !mimeparser.header_protected.is_null() {
@@ -99,26 +96,20 @@ unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) {
} }
mimeparser.is_send_by_messenger = false; mimeparser.is_send_by_messenger = false;
mimeparser.is_system_message = 0i32; mimeparser.is_system_message = 0i32;
free(mimeparser.subject as *mut libc::c_void); mimeparser.subject = None;
mimeparser.subject = ptr::null_mut();
if !mimeparser.mimeroot.is_null() { if !mimeparser.mimeroot.is_null() {
mailmime_free(mimeparser.mimeroot); mailmime_free(mimeparser.mimeroot);
mimeparser.mimeroot = ptr::null_mut() mimeparser.mimeroot = ptr::null_mut()
} }
mimeparser.is_forwarded = 0i32; mimeparser.is_forwarded = false;
mimeparser.reports.clear(); mimeparser.reports.clear();
mimeparser.decrypting_failed = 0i32; mimeparser.decrypting_failed = false;
mimeparser.e2ee_helper.thanks(); mimeparser.e2ee_helper.thanks();
mimeparser.location_kml = None; mimeparser.location_kml = None;
mimeparser.message_kml = None; mimeparser.message_kml = None;
} }
unsafe fn dc_mimepart_unref(mut mimepart: dc_mimepart_t) {
mimepart.msg = None;
free(mimepart.msg_raw as *mut libc::c_void);
mimepart.msg_raw = ptr::null_mut();
}
const DC_MIMETYPE_AC_SETUP_FILE: i32 = 111; const DC_MIMETYPE_AC_SETUP_FILE: i32 = 111;
pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_mimeparser_t<'a> { pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_mimeparser_t<'a> {
@@ -141,7 +132,15 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
dc_mimeparser_parse_mime_recursive(mimeparser_ref, mimeparser_ref.mimeroot); dc_mimeparser_parse_mime_recursive(mimeparser_ref, mimeparser_ref.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 = dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value) let decoded = dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value);
if decoded.is_null()
/* XXX: can it happen? */
{
mimeparser.subject = None
} else {
mimeparser.subject = Some(to_string(decoded));
free(decoded.cast());
}
} }
if !dc_mimeparser_lookup_optional_field(&mut mimeparser, "Chat-Version").is_null() { if !dc_mimeparser_lookup_optional_field(&mut mimeparser, "Chat-Version").is_null() {
mimeparser.is_send_by_messenger = true mimeparser.is_send_by_messenger = true
@@ -169,8 +168,7 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
let mut i = 0; let mut i = 0;
while i != mimeparser.parts.len() { while i != mimeparser.parts.len() {
if mimeparser.parts[i].int_mimetype != 111 { if mimeparser.parts[i].int_mimetype != 111 {
let part = mimeparser.parts.remove(i); mimeparser.parts.remove(i);
dc_mimepart_unref(part);
} else { } else {
i += 1; i += 1;
} }
@@ -196,7 +194,7 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
if mimeparser.parts.len() >= 2 { if mimeparser.parts.len() >= 2 {
let imgpart = &mut mimeparser.parts[1]; let imgpart = &mut mimeparser.parts[1];
if imgpart.type_0 == Viewtype::Image { if imgpart.type_0 == Viewtype::Image {
imgpart.is_meta = 1i32 imgpart.is_meta = true;
} }
} }
} }
@@ -212,7 +210,7 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
|| filepart.type_0 == Viewtype::Voice || filepart.type_0 == Viewtype::Voice
|| filepart.type_0 == Viewtype::Video || filepart.type_0 == Viewtype::Video
|| filepart.type_0 == Viewtype::File) || filepart.type_0 == Viewtype::File)
&& 0 == filepart.is_meta && !filepart.is_meta
}; };
if need_drop { if need_drop {
@@ -225,42 +223,37 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
mimeparser.parts[0].msg = None; mimeparser.parts[0].msg = None;
// swap new with old // swap new with old
let old = std::mem::replace(&mut mimeparser.parts[0], filepart); std::mem::replace(&mut mimeparser.parts[0], filepart);
// unref old one
dc_mimepart_unref(old);
} }
} }
if !mimeparser.subject.is_null() { if let Some(ref subject) = mimeparser.subject {
let mut prepend_subject: libc::c_int = 1i32; let mut prepend_subject: libc::c_int = 1i32;
if 0 == mimeparser.decrypting_failed { if !mimeparser.decrypting_failed {
let p: *mut libc::c_char = strchr(mimeparser.subject, ':' as i32); let colon = subject.find(':');
if p.wrapping_offset_from(mimeparser.subject) == 2 if colon == Some(2)
|| p.wrapping_offset_from(mimeparser.subject) == 3 || colon == Some(3)
|| mimeparser.is_send_by_messenger || mimeparser.is_send_by_messenger
|| !strstr( || subject.contains("Chat:")
mimeparser.subject,
b"Chat:\x00" as *const u8 as *const libc::c_char,
)
.is_null()
{ {
prepend_subject = 0i32 prepend_subject = 0i32
} }
} }
if 0 != prepend_subject { if 0 != prepend_subject {
let subj: *mut libc::c_char = dc_strdup(mimeparser.subject); let subj = if let Some(n) = subject.find('[') {
let p_0: *mut libc::c_char = strchr(subj, '[' as i32); &subject[0..n]
if !p_0.is_null() { } else {
*p_0 = 0i32 as libc::c_char subject
} }
dc_trim(subj); .trim();
if 0 != *subj.offset(0isize) {
if !subj.is_empty() {
let subj_c = CString::yolo(subj);
for part in mimeparser.parts.iter_mut() { for part in mimeparser.parts.iter_mut() {
if part.type_0 == Viewtype::Text { if part.type_0 == Viewtype::Text {
let msg_c = part.msg.as_ref().unwrap().strdup(); let msg_c = part.msg.as_ref().unwrap().strdup();
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_c.as_ptr(),
msg_c, msg_c,
); );
free(msg_c.cast()); free(msg_c.cast());
@@ -270,10 +263,9 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
} }
} }
} }
free(subj as *mut libc::c_void);
} }
} }
if 0 != mimeparser.is_forwarded { if mimeparser.is_forwarded {
for part in mimeparser.parts.iter_mut() { for part in mimeparser.parts.iter_mut() {
part.param.set_int(Param::Forwarded, 1); part.param.set_int(Param::Forwarded, 1);
} }
@@ -301,7 +293,7 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
} }
} }
} }
if 0 == mimeparser.decrypting_failed { if !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,
"Chat-Disposition-Notification-To", "Chat-Disposition-Notification-To",
@@ -350,10 +342,12 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
if dc_mimeparser_get_last_nonmeta(&mut mimeparser).is_none() && mimeparser.reports.is_empty() { if dc_mimeparser_get_last_nonmeta(&mut mimeparser).is_none() && mimeparser.reports.is_empty() {
let mut part_5 = dc_mimepart_new(); let mut part_5 = dc_mimepart_new();
part_5.type_0 = Viewtype::Text; part_5.type_0 = Viewtype::Text;
if !mimeparser.subject.is_null() && !mimeparser.is_send_by_messenger { part_5.msg = Some("".into());
part_5.msg = Some(to_string(mimeparser.subject));
} else { if let Some(ref subject) = mimeparser.subject {
part_5.msg = Some("".into()); if !mimeparser.is_send_by_messenger {
part_5.msg = Some(subject.to_string())
}
} }
mimeparser.parts.push(part_5); mimeparser.parts.push(part_5);
}; };
@@ -366,10 +360,10 @@ pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_m
unsafe fn dc_mimepart_new() -> dc_mimepart_t { unsafe fn dc_mimepart_new() -> dc_mimepart_t {
dc_mimepart_t { dc_mimepart_t {
type_0: Viewtype::Unknown, type_0: Viewtype::Unknown,
is_meta: 0, is_meta: false,
int_mimetype: 0, int_mimetype: 0,
msg: None, msg: None,
msg_raw: std::ptr::null_mut(), msg_raw: None,
bytes: 0, bytes: 0,
param: Params::new(), param: Params::new(),
} }
@@ -378,11 +372,7 @@ unsafe fn dc_mimepart_new() -> dc_mimepart_t {
pub fn dc_mimeparser_get_last_nonmeta<'a>( pub fn dc_mimeparser_get_last_nonmeta<'a>(
mimeparser: &'a mut dc_mimeparser_t, mimeparser: &'a mut dc_mimeparser_t,
) -> Option<&'a mut dc_mimepart_t> { ) -> Option<&'a mut dc_mimepart_t> {
mimeparser mimeparser.parts.iter_mut().rev().find(|part| !part.is_meta)
.parts
.iter_mut()
.rev()
.find(|part| part.is_meta == 0)
} }
/*the result must be freed*/ /*the result must be freed*/
@@ -596,12 +586,12 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
.stock_str(StockMessage::CantDecryptMsgBody); .stock_str(StockMessage::CantDecryptMsgBody);
let txt = format!("[{}]", msg_body); let txt = format!("[{}]", msg_body);
part.msg_raw = txt.strdup(); part.msg_raw = Some(txt.clone());
part.msg = Some(txt); part.msg = Some(txt);
mimeparser.parts.push(part); mimeparser.parts.push(part);
any_part_added = 1i32; any_part_added = 1i32;
mimeparser.decrypting_failed = 1i32 mimeparser.decrypting_failed = true;
} }
46 => { 46 => {
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
@@ -1124,13 +1114,18 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
part.type_0 = Viewtype::Text; part.type_0 = Viewtype::Text;
part.int_mimetype = mime_type; part.int_mimetype = mime_type;
part.msg = Some(simplified_txt); part.msg = Some(simplified_txt);
part.msg_raw = part.msg_raw = {
strndup(decoded_data, decoded_data_bytes as libc::c_ulong); let raw_c =
strndup(decoded_data, decoded_data_bytes as libc::c_ulong);
let raw = to_string(raw_c);
free(raw_c.cast());
Some(raw)
};
do_add_single_part(mimeparser, part); do_add_single_part(mimeparser, part);
} }
if simplifier.unwrap().is_forwarded { if simplifier.unwrap().is_forwarded {
mimeparser.is_forwarded = 1i32 mimeparser.is_forwarded = true;
} }
} }
} }
@@ -1284,7 +1279,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
mimeparser, mimeparser,
msg_type, msg_type,
mime_type, mime_type,
raw_mime, as_str(raw_mime),
decoded_data, decoded_data,
decoded_data_bytes, decoded_data_bytes,
desired_filename, desired_filename,
@@ -1312,7 +1307,7 @@ unsafe fn do_add_single_file_part(
parser: &mut dc_mimeparser_t, parser: &mut dc_mimeparser_t,
msg_type: Viewtype, msg_type: Viewtype,
mime_type: libc::c_int, mime_type: libc::c_int,
raw_mime: *const libc::c_char, raw_mime: &str,
decoded_data: *const libc::c_char, decoded_data: *const libc::c_char,
decoded_data_bytes: size_t, decoded_data_bytes: size_t,
desired_filename: *const libc::c_char, desired_filename: *const libc::c_char,
@@ -1338,7 +1333,7 @@ unsafe fn do_add_single_file_part(
part.int_mimetype = mime_type; part.int_mimetype = mime_type;
part.bytes = decoded_data_bytes as libc::c_int; part.bytes = decoded_data_bytes as libc::c_int;
part.param.set(Param::File, as_str(pathNfilename)); part.param.set(Param::File, as_str(pathNfilename));
part.param.set(Param::MimeType, as_str(raw_mime)); part.param.set(Param::MimeType, raw_mime);
if mime_type == 80 { if mime_type == 80 {
assert!(!decoded_data.is_null(), "invalid image data"); assert!(!decoded_data.is_null(), "invalid image data");
let data = std::slice::from_raw_parts( let data = std::slice::from_raw_parts(
@@ -1655,9 +1650,7 @@ pub unsafe fn dc_mimeparser_repl_msg_by_error(
let part = &mut mimeparser.parts[0]; let part = &mut mimeparser.parts[0];
part.type_0 = Viewtype::Text; part.type_0 = Viewtype::Text;
part.msg = Some(format!("[{}]", to_string(error_msg))); part.msg = Some(format!("[{}]", to_string(error_msg)));
for part in mimeparser.parts.drain(1..) { mimeparser.parts.truncate(1);
dc_mimepart_unref(part);
}
assert_eq!(mimeparser.parts.len(), 1); assert_eq!(mimeparser.parts.len(), 1);
} }
@@ -1814,10 +1807,7 @@ mod tests {
let raw = b"Content-Type: multipart/mixed; boundary=\"==break==\";\nSubject: outer-subject\nX-Special-A: special-a\nFoo: Bar\nChat-Version: 0.0\n\n--==break==\nContent-Type: text/plain; protected-headers=\"v1\";\nSubject: inner-subject\nX-Special-B: special-b\nFoo: Xy\nChat-Version: 1.0\n\ntest1\n\n--==break==--\n\n\x00"; let raw = b"Content-Type: multipart/mixed; boundary=\"==break==\";\nSubject: outer-subject\nX-Special-A: special-a\nFoo: Bar\nChat-Version: 0.0\n\n--==break==\nContent-Type: text/plain; protected-headers=\"v1\";\nSubject: inner-subject\nX-Special-B: special-b\nFoo: Xy\nChat-Version: 1.0\n\ntest1\n\n--==break==--\n\n\x00";
let mut mimeparser = dc_mimeparser_parse(&context.ctx, &raw[..]); let mut mimeparser = dc_mimeparser_parse(&context.ctx, &raw[..]);
assert_eq!( assert_eq!(mimeparser.subject, Some("inner-subject".into()));
&to_string(mimeparser.subject as *const libc::c_char),
"inner-subject",
);
let mut of: *mut mailimf_optional_field = let mut of: *mut mailimf_optional_field =
dc_mimeparser_lookup_optional_field(&mimeparser, "X-Special-A"); dc_mimeparser_lookup_optional_field(&mimeparser, "X-Special-A");

View File

@@ -1,3 +1,4 @@
use std::ffi::CString;
use std::ptr; use std::ptr;
use itertools::join; use itertools::join;
@@ -625,7 +626,7 @@ unsafe fn add_parts(
|mut stmt, conn| { |mut stmt, conn| {
for i in 0..icnt { for i in 0..icnt {
let part = &mut mime_parser.parts[i]; let part = &mut mime_parser.parts[i];
if part.is_meta != 0 { if part.is_meta {
continue; continue;
} }
@@ -641,14 +642,18 @@ unsafe fn add_parts(
} }
} }
if part.type_0 == Viewtype::Text { if part.type_0 == Viewtype::Text {
let msg_raw = CString::yolo(part.msg_raw.as_ref().unwrap().clone());
let subject_c = CString::yolo(
mime_parser
.subject
.as_ref()
.map(|s| s.to_string())
.unwrap_or("".into()),
);
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() { subject_c.as_ptr(),
mime_parser.subject msg_raw.as_ptr(),
} else {
b"\x00" as *const u8 as *const libc::c_char
},
part.msg_raw,
) )
} }
if 0 != mime_parser.is_system_message { if 0 != mime_parser.is_system_message {
@@ -1568,8 +1573,8 @@ unsafe fn create_or_lookup_adhoc_group(
} }
// use subject as initial chat name // use subject as initial chat name
if !mime_parser.subject.is_null() && 0 != *mime_parser.subject.offset(0isize) as libc::c_int { if let Some(subject) = mime_parser.subject.as_ref().filter(|s| !s.is_empty()) {
grpname = dc_strdup(mime_parser.subject) grpname = subject.strdup();
} else { } else {
grpname = context grpname = context
.stock_string_repl_int(StockMessage::Member, member_ids.len() as libc::c_int) .stock_string_repl_int(StockMessage::Member, member_ids.len() as libc::c_int)

View File

@@ -435,21 +435,10 @@ pub unsafe fn clist_free_content(haystack: *const clist) {
pub unsafe fn clist_search_string_nocase( pub unsafe fn clist_search_string_nocase(
haystack: *const clist, haystack: *const clist,
needle: *const libc::c_char, needle: *const libc::c_char,
) -> libc::c_int { ) -> bool {
let mut iter = (*haystack).first; (&*haystack)
.into_iter()
while !iter.is_null() { .any(|data| strcasecmp(data.cast(), needle) == 0)
if strcasecmp((*iter).data as *const libc::c_char, needle) == 0 {
return 1;
}
iter = if !iter.is_null() {
(*iter).next
} else {
ptr::null_mut()
}
}
0
} }
/* date/time tools */ /* date/time tools */
@@ -630,6 +619,21 @@ pub unsafe fn dc_create_outgoing_rfc724_mid(
ret ret
} }
/// Generate globally-unique message-id for a new outgoing message.
///
/// Note: Do not add a counter or any private data as as this may give
/// unneeded information to the receiver
pub fn dc_create_outgoing_rfc724_mid_safe(grpid: Option<&str>, from_addr: &str) -> String {
let hostname = from_addr
.find('@')
.map(|k| &from_addr[k..])
.unwrap_or("@nohost");
match grpid {
Some(grpid) => format!("Gr.{}.{}{}", grpid, dc_create_id(), hostname),
None => format!("Mr.{}.{}{}", dc_create_id(), dc_create_id(), hostname),
}
}
/// Extract the group id (grpid) from a message id (mid) /// Extract the group id (grpid) from a message id (mid)
/// ///
/// # Arguments /// # Arguments

View File

@@ -692,9 +692,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
); );
} else { } else {
/* unrecoverable */ /* unrecoverable */
if clist_search_string_nocase(mimefactory.recipients_addr, mimefactory.from_addr) if !clist_search_string_nocase(mimefactory.recipients_addr, mimefactory.from_addr) {
== 0i32
{
clist_insert_after( clist_insert_after(
mimefactory.recipients_names, mimefactory.recipients_names,
(*mimefactory.recipients_names).last, (*mimefactory.recipients_names).last,