mirror of
https://github.com/chatmail/core.git
synced 2026-04-23 00:16:34 +03:00
Change type of function from `const char *' to &str (#451)
Change type of function from `const char *' to &str
This commit is contained in:
413
src/chat.rs
413
src/chat.rs
@@ -171,51 +171,20 @@ impl<'a> Chat<'a> {
|
||||
return "Err".into();
|
||||
}
|
||||
|
||||
unsafe fn get_parent_mime_headers(
|
||||
&self,
|
||||
parent_rfc724_mid: *mut *mut libc::c_char,
|
||||
parent_in_reply_to: *mut *mut libc::c_char,
|
||||
parent_references: *mut *mut libc::c_char,
|
||||
) -> Result<(), Error> {
|
||||
if !(parent_rfc724_mid.is_null()
|
||||
|| parent_in_reply_to.is_null()
|
||||
|| parent_references.is_null())
|
||||
{
|
||||
// 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();
|
||||
pub fn get_parent_mime_headers(&self) -> Option<(String, String, String)> {
|
||||
let collect = |row: &rusqlite::Row| Ok((row.get(0)?, row.get(1)?, row.get(2)?));
|
||||
let params = params![self.id as i32, DC_CONTACT_ID_SELF as i32];
|
||||
let sql = &self.context.sql;
|
||||
let main_query = "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);";
|
||||
let fallback_query = "SELECT rfc724_mid, mime_in_reply_to, mime_references \
|
||||
FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT min(timestamp) \
|
||||
FROM msgs WHERE chat_id=?1 AND from_id==?2);";
|
||||
|
||||
if !next {
|
||||
self.context.sql.query_row(
|
||||
"SELECT rfc724_mid, mime_in_reply_to, mime_references \
|
||||
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(())
|
||||
sql.query_row(main_query, params, collect)
|
||||
.or_else(|_| sql.query_row(fallback_query, params, collect))
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub unsafe fn get_profile_image(&self) -> Option<String> {
|
||||
@@ -277,13 +246,8 @@ impl<'a> Chat<'a> {
|
||||
) -> Result<u32, Error> {
|
||||
let mut do_guarantee_e2ee: libc::c_int;
|
||||
let e2ee_enabled: libc::c_int;
|
||||
let mut OK_TO_CONTINUE = true;
|
||||
let mut parent_rfc724_mid = ptr::null_mut();
|
||||
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 new_references = "".into();
|
||||
let mut new_in_reply_to = "".into();
|
||||
let mut msg_id = 0;
|
||||
let mut to_id = 0;
|
||||
let mut location_id = 0;
|
||||
@@ -293,7 +257,10 @@ impl<'a> Chat<'a> {
|
||||
|| self.typ == Chattype::VerifiedGroup)
|
||||
{
|
||||
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)
|
||||
{
|
||||
log_event!(
|
||||
@@ -302,200 +269,173 @@ impl<'a> Chat<'a> {
|
||||
0,
|
||||
"Cannot send message; self not in group.",
|
||||
);
|
||||
} else {
|
||||
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(),
|
||||
);
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
if self.typ == Chattype::Single {
|
||||
if let Some(id) = context.sql.query_row_col(
|
||||
context,
|
||||
"SELECT contact_id FROM chats_contacts WHERE chat_id=?;",
|
||||
params![self.id as i32],
|
||||
0,
|
||||
) {
|
||||
to_id = id;
|
||||
} else {
|
||||
error!(
|
||||
context,
|
||||
0, "Cannot send message, contact for chat #{} not found.", self.id,
|
||||
);
|
||||
OK_TO_CONTINUE = false;
|
||||
}
|
||||
if let Some(from) = context.sql.get_config(context, "configured_addr") {
|
||||
let new_rfc724_mid = {
|
||||
let grpid = match self.typ {
|
||||
Chattype::Group | Chattype::VerifiedGroup => Some(self.grpid.as_str()),
|
||||
_ => None,
|
||||
};
|
||||
dc_create_outgoing_rfc724_mid_safe(grpid, &from)
|
||||
};
|
||||
|
||||
if self.typ == Chattype::Single {
|
||||
if let Some(id) = context.sql.query_row_col(
|
||||
context,
|
||||
"SELECT contact_id FROM chats_contacts WHERE chat_id=?;",
|
||||
params![self.id as i32],
|
||||
0,
|
||||
) {
|
||||
to_id = id;
|
||||
} 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();
|
||||
}
|
||||
error!(
|
||||
context,
|
||||
0, "Cannot send message, contact for chat #{} not found.", self.id,
|
||||
);
|
||||
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(
|
||||
"SELECT ps.prefer_encrypted, c.addr \
|
||||
FROM chats_contacts cc \
|
||||
LEFT JOIN contacts c ON cc.contact_id=c.id \
|
||||
LEFT JOIN acpeerstates ps ON c.addr=ps.addr \
|
||||
WHERE cc.chat_id=? AND cc.contact_id>9;",
|
||||
params![self.id],
|
||||
|row| {
|
||||
let state: String = row.get(1)?;
|
||||
/* 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;
|
||||
|
||||
if let Some(prefer_encrypted) = row.get::<_, Option<i32>>(0)? {
|
||||
if prefer_encrypted != 1 {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"[autocrypt] peerstate for {} is {}",
|
||||
state,
|
||||
if prefer_encrypted == 0 {
|
||||
"NOPREFERENCE"
|
||||
} else {
|
||||
"RESET"
|
||||
},
|
||||
);
|
||||
all_mutual = 0;
|
||||
}
|
||||
} 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 != 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;
|
||||
let res = context.sql.query_row(
|
||||
"SELECT ps.prefer_encrypted, c.addr \
|
||||
FROM chats_contacts cc \
|
||||
LEFT JOIN contacts c ON cc.contact_id=c.id \
|
||||
LEFT JOIN acpeerstates ps ON c.addr=ps.addr \
|
||||
WHERE cc.chat_id=? AND cc.contact_id>9;",
|
||||
params![self.id],
|
||||
|row| {
|
||||
let state: String = row.get(1)?;
|
||||
|
||||
if let Some(prefer_encrypted) = row.get::<_, Option<i32>>(0)? {
|
||||
if prefer_encrypted != 1 {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"[autocrypt] peerstate for {} is {}",
|
||||
state,
|
||||
if prefer_encrypted == 0 {
|
||||
"NOPREFERENCE"
|
||||
} else {
|
||||
"RESET"
|
||||
},
|
||||
);
|
||||
all_mutual = 0;
|
||||
}
|
||||
} 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
|
||||
.get_parent_mime_headers(
|
||||
&mut parent_rfc724_mid,
|
||||
&mut parent_in_reply_to,
|
||||
&mut parent_references,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
if !parent_rfc724_mid.is_null()
|
||||
&& 0 != *parent_rfc724_mid.offset(0isize) as libc::c_int
|
||||
{
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
if 0 != do_guarantee_e2ee {
|
||||
msg.param.set_int(Param::GuranteeE2ee, 1);
|
||||
}
|
||||
msg.param.remove(Param::ErroneousE2ee);
|
||||
if !self.is_self_talk() {
|
||||
if let Some((parent_rfc724_mid, parent_in_reply_to, parent_references)) =
|
||||
self.get_parent_mime_headers()
|
||||
{
|
||||
if !parent_rfc724_mid.is_empty() {
|
||||
new_in_reply_to = parent_rfc724_mid.clone();
|
||||
}
|
||||
let parent_references = if let Some(n) = parent_references.find(' ') {
|
||||
&parent_references[0..n]
|
||||
} else {
|
||||
&parent_references
|
||||
};
|
||||
|
||||
// add independent location to database
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
if !parent_references.is_empty() && !parent_rfc724_mid.is_empty() {
|
||||
new_references = format!("{} {}", parent_references, parent_rfc724_mid);
|
||||
} else if !parent_references.is_empty() {
|
||||
new_references = parent_references.to_string();
|
||||
} else if !parent_in_reply_to.is_empty() && !parent_rfc724_mid.is_empty() {
|
||||
new_references = format!("{} {}", parent_in_reply_to, parent_rfc724_mid);
|
||||
} else if !parent_in_reply_to.is_empty() {
|
||||
new_references = parent_in_reply_to.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.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 (?,?,?,?,?, ?,?,?,?,?, ?,?,?);",
|
||||
params![
|
||||
as_str(new_rfc724_mid),
|
||||
new_rfc724_mid,
|
||||
self.id as i32,
|
||||
1i32,
|
||||
to_id as i32,
|
||||
@@ -505,8 +445,8 @@ impl<'a> Chat<'a> {
|
||||
msg.text.as_ref().map_or("", String::as_str),
|
||||
msg.param.to_string(),
|
||||
msg.hidden,
|
||||
to_string(new_in_reply_to),
|
||||
to_string(new_references),
|
||||
new_in_reply_to,
|
||||
new_references,
|
||||
location_id as i32,
|
||||
]
|
||||
).is_ok() {
|
||||
@@ -515,7 +455,7 @@ impl<'a> Chat<'a> {
|
||||
&context.sql,
|
||||
"msgs",
|
||||
"rfc724_mid",
|
||||
as_str(new_rfc724_mid),
|
||||
new_rfc724_mid,
|
||||
);
|
||||
} else {
|
||||
error!(
|
||||
@@ -525,19 +465,10 @@ impl<'a> Chat<'a> {
|
||||
self.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!(context, 0, "Cannot send message, not configured.",);
|
||||
}
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ pub unsafe fn dc_mimefactory_load_msg(
|
||||
for row in rows {
|
||||
let (authname, addr) = row?;
|
||||
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(
|
||||
factory.recipients_names,
|
||||
(*factory.recipients_names).last,
|
||||
@@ -183,7 +183,7 @@ pub unsafe fn dc_mimefactory_load_msg(
|
||||
.unwrap_or_default();
|
||||
|
||||
if !email_to_remove.is_empty() && email_to_remove != self_addr {
|
||||
if clist_search_string_nocase(factory.recipients_addr, email_to_remove_c) == 0 {
|
||||
if !clist_search_string_nocase(factory.recipients_addr, email_to_remove_c) {
|
||||
clist_insert_after(
|
||||
factory.recipients_names,
|
||||
(*factory.recipients_names).last,
|
||||
|
||||
@@ -32,10 +32,10 @@ dc_mimeparser_t has no deep dependencies to Context or to the database
|
||||
#[repr(C)]
|
||||
pub struct dc_mimepart_t {
|
||||
pub type_0: Viewtype,
|
||||
pub is_meta: libc::c_int,
|
||||
pub is_meta: bool,
|
||||
pub int_mimetype: libc::c_int,
|
||||
pub msg: Option<String>,
|
||||
pub msg_raw: *mut libc::c_char,
|
||||
pub msg_raw: Option<String>,
|
||||
pub bytes: libc::c_int,
|
||||
pub param: Params,
|
||||
}
|
||||
@@ -50,11 +50,11 @@ pub struct dc_mimeparser_t<'a> {
|
||||
pub header: HashMap<String, *mut mailimf_field>,
|
||||
pub header_root: *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 decrypting_failed: libc::c_int,
|
||||
pub decrypting_failed: bool,
|
||||
pub e2ee_helper: E2eeHelper,
|
||||
pub is_forwarded: libc::c_int,
|
||||
pub is_forwarded: bool,
|
||||
pub context: &'a Context,
|
||||
pub reports: Vec<*mut mailmime>,
|
||||
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_root: std::ptr::null_mut(),
|
||||
header_protected: std::ptr::null_mut(),
|
||||
subject: std::ptr::null_mut(),
|
||||
subject: None,
|
||||
is_send_by_messenger: false,
|
||||
decrypting_failed: 0,
|
||||
decrypting_failed: false,
|
||||
e2ee_helper: Default::default(),
|
||||
is_forwarded: 0,
|
||||
is_forwarded: false,
|
||||
context,
|
||||
reports: Vec::new(),
|
||||
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) {
|
||||
for part in mimeparser.parts.drain(..) {
|
||||
dc_mimepart_unref(part);
|
||||
}
|
||||
assert!(mimeparser.parts.is_empty());
|
||||
mimeparser.parts = vec![];
|
||||
mimeparser.header_root = ptr::null_mut();
|
||||
mimeparser.header.clear();
|
||||
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_system_message = 0i32;
|
||||
free(mimeparser.subject as *mut libc::c_void);
|
||||
mimeparser.subject = ptr::null_mut();
|
||||
mimeparser.subject = None;
|
||||
if !mimeparser.mimeroot.is_null() {
|
||||
mailmime_free(mimeparser.mimeroot);
|
||||
mimeparser.mimeroot = ptr::null_mut()
|
||||
}
|
||||
mimeparser.is_forwarded = 0i32;
|
||||
mimeparser.is_forwarded = false;
|
||||
mimeparser.reports.clear();
|
||||
mimeparser.decrypting_failed = 0i32;
|
||||
mimeparser.decrypting_failed = false;
|
||||
mimeparser.e2ee_helper.thanks();
|
||||
|
||||
mimeparser.location_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;
|
||||
|
||||
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);
|
||||
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 {
|
||||
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() {
|
||||
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;
|
||||
while i != mimeparser.parts.len() {
|
||||
if mimeparser.parts[i].int_mimetype != 111 {
|
||||
let part = mimeparser.parts.remove(i);
|
||||
dc_mimepart_unref(part);
|
||||
mimeparser.parts.remove(i);
|
||||
} else {
|
||||
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 {
|
||||
let imgpart = &mut mimeparser.parts[1];
|
||||
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::Video
|
||||
|| filepart.type_0 == Viewtype::File)
|
||||
&& 0 == filepart.is_meta
|
||||
&& !filepart.is_meta
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
// swap new with old
|
||||
let old = std::mem::replace(&mut mimeparser.parts[0], filepart);
|
||||
|
||||
// unref old one
|
||||
dc_mimepart_unref(old);
|
||||
std::mem::replace(&mut mimeparser.parts[0], filepart);
|
||||
}
|
||||
}
|
||||
if !mimeparser.subject.is_null() {
|
||||
if let Some(ref subject) = mimeparser.subject {
|
||||
let mut prepend_subject: libc::c_int = 1i32;
|
||||
if 0 == mimeparser.decrypting_failed {
|
||||
let p: *mut libc::c_char = strchr(mimeparser.subject, ':' as i32);
|
||||
if p.wrapping_offset_from(mimeparser.subject) == 2
|
||||
|| p.wrapping_offset_from(mimeparser.subject) == 3
|
||||
if !mimeparser.decrypting_failed {
|
||||
let colon = subject.find(':');
|
||||
if colon == Some(2)
|
||||
|| colon == Some(3)
|
||||
|| mimeparser.is_send_by_messenger
|
||||
|| !strstr(
|
||||
mimeparser.subject,
|
||||
b"Chat:\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
.is_null()
|
||||
|| subject.contains("Chat:")
|
||||
{
|
||||
prepend_subject = 0i32
|
||||
}
|
||||
}
|
||||
if 0 != prepend_subject {
|
||||
let subj: *mut libc::c_char = dc_strdup(mimeparser.subject);
|
||||
let p_0: *mut libc::c_char = strchr(subj, '[' as i32);
|
||||
if !p_0.is_null() {
|
||||
*p_0 = 0i32 as libc::c_char
|
||||
let subj = if let Some(n) = subject.find('[') {
|
||||
&subject[0..n]
|
||||
} else {
|
||||
subject
|
||||
}
|
||||
dc_trim(subj);
|
||||
if 0 != *subj.offset(0isize) {
|
||||
.trim();
|
||||
|
||||
if !subj.is_empty() {
|
||||
let subj_c = CString::yolo(subj);
|
||||
for part in mimeparser.parts.iter_mut() {
|
||||
if part.type_0 == Viewtype::Text {
|
||||
let msg_c = part.msg.as_ref().unwrap().strdup();
|
||||
let new_txt: *mut libc::c_char = dc_mprintf(
|
||||
b"%s \xe2\x80\x93 %s\x00" as *const u8 as *const libc::c_char,
|
||||
subj,
|
||||
subj_c.as_ptr(),
|
||||
msg_c,
|
||||
);
|
||||
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() {
|
||||
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(
|
||||
&mimeparser,
|
||||
"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() {
|
||||
let mut part_5 = dc_mimepart_new();
|
||||
part_5.type_0 = Viewtype::Text;
|
||||
if !mimeparser.subject.is_null() && !mimeparser.is_send_by_messenger {
|
||||
part_5.msg = Some(to_string(mimeparser.subject));
|
||||
} else {
|
||||
part_5.msg = Some("".into());
|
||||
part_5.msg = Some("".into());
|
||||
|
||||
if let Some(ref subject) = mimeparser.subject {
|
||||
if !mimeparser.is_send_by_messenger {
|
||||
part_5.msg = Some(subject.to_string())
|
||||
}
|
||||
}
|
||||
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 {
|
||||
dc_mimepart_t {
|
||||
type_0: Viewtype::Unknown,
|
||||
is_meta: 0,
|
||||
is_meta: false,
|
||||
int_mimetype: 0,
|
||||
msg: None,
|
||||
msg_raw: std::ptr::null_mut(),
|
||||
msg_raw: None,
|
||||
bytes: 0,
|
||||
param: Params::new(),
|
||||
}
|
||||
@@ -378,11 +372,7 @@ unsafe fn dc_mimepart_new() -> dc_mimepart_t {
|
||||
pub fn dc_mimeparser_get_last_nonmeta<'a>(
|
||||
mimeparser: &'a mut dc_mimeparser_t,
|
||||
) -> Option<&'a mut dc_mimepart_t> {
|
||||
mimeparser
|
||||
.parts
|
||||
.iter_mut()
|
||||
.rev()
|
||||
.find(|part| part.is_meta == 0)
|
||||
mimeparser.parts.iter_mut().rev().find(|part| !part.is_meta)
|
||||
}
|
||||
|
||||
/*the result must be freed*/
|
||||
@@ -596,12 +586,12 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
|
||||
.stock_str(StockMessage::CantDecryptMsgBody);
|
||||
|
||||
let txt = format!("[{}]", msg_body);
|
||||
part.msg_raw = txt.strdup();
|
||||
part.msg_raw = Some(txt.clone());
|
||||
part.msg = Some(txt);
|
||||
|
||||
mimeparser.parts.push(part);
|
||||
any_part_added = 1i32;
|
||||
mimeparser.decrypting_failed = 1i32
|
||||
mimeparser.decrypting_failed = true;
|
||||
}
|
||||
46 => {
|
||||
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.int_mimetype = mime_type;
|
||||
part.msg = Some(simplified_txt);
|
||||
part.msg_raw =
|
||||
strndup(decoded_data, decoded_data_bytes as libc::c_ulong);
|
||||
part.msg_raw = {
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
msg_type,
|
||||
mime_type,
|
||||
raw_mime,
|
||||
as_str(raw_mime),
|
||||
decoded_data,
|
||||
decoded_data_bytes,
|
||||
desired_filename,
|
||||
@@ -1312,7 +1307,7 @@ unsafe fn do_add_single_file_part(
|
||||
parser: &mut dc_mimeparser_t,
|
||||
msg_type: Viewtype,
|
||||
mime_type: libc::c_int,
|
||||
raw_mime: *const libc::c_char,
|
||||
raw_mime: &str,
|
||||
decoded_data: *const libc::c_char,
|
||||
decoded_data_bytes: size_t,
|
||||
desired_filename: *const libc::c_char,
|
||||
@@ -1338,7 +1333,7 @@ unsafe fn do_add_single_file_part(
|
||||
part.int_mimetype = mime_type;
|
||||
part.bytes = decoded_data_bytes as libc::c_int;
|
||||
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 {
|
||||
assert!(!decoded_data.is_null(), "invalid image data");
|
||||
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];
|
||||
part.type_0 = Viewtype::Text;
|
||||
part.msg = Some(format!("[{}]", to_string(error_msg)));
|
||||
for part in mimeparser.parts.drain(1..) {
|
||||
dc_mimepart_unref(part);
|
||||
}
|
||||
mimeparser.parts.truncate(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 mut mimeparser = dc_mimeparser_parse(&context.ctx, &raw[..]);
|
||||
|
||||
assert_eq!(
|
||||
&to_string(mimeparser.subject as *const libc::c_char),
|
||||
"inner-subject",
|
||||
);
|
||||
assert_eq!(mimeparser.subject, Some("inner-subject".into()));
|
||||
|
||||
let mut of: *mut mailimf_optional_field =
|
||||
dc_mimeparser_lookup_optional_field(&mimeparser, "X-Special-A");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use itertools::join;
|
||||
@@ -625,7 +626,7 @@ unsafe fn add_parts(
|
||||
|mut stmt, conn| {
|
||||
for i in 0..icnt {
|
||||
let part = &mut mime_parser.parts[i];
|
||||
if part.is_meta != 0 {
|
||||
if part.is_meta {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -641,14 +642,18 @@ unsafe fn add_parts(
|
||||
}
|
||||
}
|
||||
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(
|
||||
b"%s\n\n%s\x00" as *const u8 as *const libc::c_char,
|
||||
if !mime_parser.subject.is_null() {
|
||||
mime_parser.subject
|
||||
} else {
|
||||
b"\x00" as *const u8 as *const libc::c_char
|
||||
},
|
||||
part.msg_raw,
|
||||
subject_c.as_ptr(),
|
||||
msg_raw.as_ptr(),
|
||||
)
|
||||
}
|
||||
if 0 != mime_parser.is_system_message {
|
||||
@@ -1568,8 +1573,8 @@ unsafe fn create_or_lookup_adhoc_group(
|
||||
}
|
||||
|
||||
// use subject as initial chat name
|
||||
if !mime_parser.subject.is_null() && 0 != *mime_parser.subject.offset(0isize) as libc::c_int {
|
||||
grpname = dc_strdup(mime_parser.subject)
|
||||
if let Some(subject) = mime_parser.subject.as_ref().filter(|s| !s.is_empty()) {
|
||||
grpname = subject.strdup();
|
||||
} else {
|
||||
grpname = context
|
||||
.stock_string_repl_int(StockMessage::Member, member_ids.len() as libc::c_int)
|
||||
|
||||
@@ -435,21 +435,10 @@ pub unsafe fn clist_free_content(haystack: *const clist) {
|
||||
pub unsafe fn clist_search_string_nocase(
|
||||
haystack: *const clist,
|
||||
needle: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut iter = (*haystack).first;
|
||||
|
||||
while !iter.is_null() {
|
||||
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
|
||||
) -> bool {
|
||||
(&*haystack)
|
||||
.into_iter()
|
||||
.any(|data| strcasecmp(data.cast(), needle) == 0)
|
||||
}
|
||||
|
||||
/* date/time tools */
|
||||
@@ -630,6 +619,21 @@ pub unsafe fn dc_create_outgoing_rfc724_mid(
|
||||
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)
|
||||
///
|
||||
/// # Arguments
|
||||
|
||||
@@ -692,9 +692,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_int {
|
||||
);
|
||||
} else {
|
||||
/* unrecoverable */
|
||||
if clist_search_string_nocase(mimefactory.recipients_addr, mimefactory.from_addr)
|
||||
== 0i32
|
||||
{
|
||||
if !clist_search_string_nocase(mimefactory.recipients_addr, mimefactory.from_addr) {
|
||||
clist_insert_after(
|
||||
mimefactory.recipients_names,
|
||||
(*mimefactory.recipients_names).last,
|
||||
|
||||
Reference in New Issue
Block a user