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

View File

@@ -6,7 +6,7 @@ use std::{fmt, str};
use mmime::mailimf_types::*;
use crate::constants::*;
use crate::dc_contact::*;
use crate::contact::*;
use crate::dc_tools::as_str;
use crate::key::*;
@@ -94,7 +94,7 @@ impl Aheader {
match Self::from_str(value) {
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() {
fine_header = Some(test);
} else {

View File

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

View File

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

View File

@@ -1,5 +1,8 @@
#![allow(non_camel_case_types)]
//! 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";
@@ -86,6 +89,7 @@ pub const DC_MAX_GET_TEXT_LEN: usize = 30000;
/// approx. max. length returned by dc_get_msg_info()
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_DEVICE: usize = 2;
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;
/// 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.
// These flags are optional
// 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 =
(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
// 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,

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 crate::constants::*;
use crate::contact::*;
use crate::dc_array::*;
use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_job::*;
use crate::dc_jobthread::*;
use crate::dc_loginparam::*;
@@ -27,15 +27,15 @@ pub struct Context {
pub blobdir: Arc<RwLock<*mut libc::c_char>>,
pub sql: Sql,
pub inbox: Arc<RwLock<Imap>>,
pub perform_inbox_jobs_needed: Arc<RwLock<i32>>,
pub probe_imap_network: Arc<RwLock<i32>>,
pub perform_inbox_jobs_needed: Arc<RwLock<bool>>,
pub probe_imap_network: Arc<RwLock<bool>>,
pub sentbox_thread: Arc<RwLock<dc_jobthread_t>>,
pub mvbox_thread: Arc<RwLock<dc_jobthread_t>>,
pub smtp: Arc<Mutex<Smtp>>,
pub smtp_state: Arc<(Mutex<SmtpState>, Condvar)>,
pub oauth2_critical: Arc<Mutex<()>>,
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 bob: Arc<RwLock<BobStatus>>,
pub last_smeared_timestamp: Arc<RwLock<i64>>,
@@ -106,17 +106,17 @@ impl Default for BobStatus {
#[derive(Default, Debug)]
pub struct SmtpState {
pub idle: bool,
pub suspended: i32,
pub doing_jobs: i32,
pub suspended: bool,
pub doing_jobs: bool,
pub perform_jobs_needed: i32,
pub probe_network: i32,
pub probe_network: bool,
}
// create/open/config/information
pub fn dc_context_new(
cb: Option<dc_callback_t>,
userdata: *mut libc::c_void,
os_name: *const libc::c_char,
os_name: Option<String>,
) -> Context {
Context {
blobdir: Arc::new(RwLock::new(std::ptr::null_mut())),
@@ -131,7 +131,7 @@ pub fn dc_context_new(
})),
userdata,
cb,
os_name: unsafe { dc_strdup_keep_null(os_name) },
os_name: os_name,
running_state: Arc::new(RwLock::new(Default::default())),
sql: Sql::new(),
smtp: Arc::new(Mutex::new(Smtp::new())),
@@ -160,8 +160,18 @@ pub fn dc_context_new(
cb_receive_imf,
),
))),
probe_imap_network: Arc::new(RwLock::new(0)),
perform_inbox_jobs_needed: Arc::new(RwLock::new(0)),
probe_imap_network: Arc::new(RwLock::new(false)),
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;
}
unsafe fn cb_set_config(context: &Context, key: *const libc::c_char, value: *const libc::c_char) {
let v = if value.is_null() {
None
} else {
Some(as_str(value))
};
context.sql.set_config(context, as_str(key), v).ok();
fn cb_set_config(context: &Context, key: &str, value: Option<&str>) {
context.sql.set_config(context, key, value).ok();
}
/* *
@@ -249,24 +254,14 @@ unsafe fn cb_set_config(context: &Context, key: *const libc::c_char, value: *con
*
* @private @memberof Context
*/
unsafe fn cb_get_config(
context: &Context,
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)
fn cb_get_config(context: &Context, key: &str) -> Option<String> {
context.sql.get_config(context, key)
}
pub unsafe fn dc_context_unref(context: &mut Context) {
if 0 != dc_is_open(context) {
dc_close(context);
}
free(context.os_name as *mut libc::c_void);
}
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 _
}
pub unsafe fn dc_open(
context: &Context,
dbfile: *const libc::c_char,
blobdir: *const libc::c_char,
) -> libc::c_int {
let mut success = 0;
pub unsafe fn dc_open(context: &Context, dbfile: &str, blobdir: Option<&str>) -> bool {
let mut success = false;
if 0 != dc_is_open(context) {
return 0;
return false;
}
if !dbfile.is_null() {
*context.dbfile.write().unwrap() = dc_strdup(dbfile);
if !blobdir.is_null() && 0 != *blobdir.offset(0isize) as libc::c_int {
let dir = dc_strdup(blobdir);
dc_ensure_no_slash(dir);
*context.blobdir.write().unwrap() = dir;
} else {
let dir = dc_mprintf(b"%s-blobs\x00" as *const u8 as *const libc::c_char, dbfile);
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
}
*context.dbfile.write().unwrap() = dbfile.strdup();
if blobdir.is_some() && blobdir.unwrap().len() > 0 {
let dir = dc_ensure_no_slash_safe(blobdir.unwrap()).strdup();
*context.blobdir.write().unwrap() = dir;
} else {
let dir = (dbfile.to_string() + "-blobs").strdup();
dc_create_folder(context, dir);
*context.blobdir.write().unwrap() = dir;
}
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);
}
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 real_msgs = dc_get_real_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
.sql
.get_config_int(context, "configured")
@@ -494,7 +483,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
fingerprint_str,
);
to_cstring(res)
res.strdup()
}
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 */
#[derive(Clone)]
#[allow(non_camel_case_types)]
pub enum dc_array_t {
Locations(Vec<dc_location>),
Uint(Vec<uintptr_t>),
@@ -136,6 +137,20 @@ impl dc_array_t {
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) {
@@ -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 Some(s) = &v[index].marker {
to_cstring(s)
s.strdup()
} else {
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(
array: *const dc_array_t,
sep: *const libc::c_char,
@@ -371,7 +375,7 @@ pub unsafe fn dc_array_get_string(
res + sep + &n.to_string()
}
});
to_cstring(res)
res.strdup()
} else {
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, 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, 1 as size_t), 7);

View File

@@ -2,9 +2,9 @@ use std::ffi::CString;
use crate::chatlist::*;
use crate::constants::*;
use crate::contact::*;
use crate::context::Context;
use crate::dc_array::*;
use crate::dc_contact::*;
use crate::dc_job::*;
use crate::dc_msg::*;
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);
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);
@@ -137,14 +137,8 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
c.id = row.get(0)?;
c.type_0 = row.get(1)?;
c.name = {
let raw: String = row.get(2)?;
unsafe { to_cstring(raw) }
};
c.grpid = {
let raw: String = row.get(3)?;
unsafe { to_cstring(raw) }
};
c.name = unsafe { row.get::<_, String>(2)?.strdup() };
c.grpid = unsafe { row.get::<_, String>(3)?.strdup() };
c.param = row.get::<_, String>(4)?.parse().unwrap_or_default();
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 {
1 => unsafe {
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 {
free((*chat).name as *mut libc::c_void);
let tempname = (*chat).context.stock_str(StockMessage::ArchivedChats);
let cnt = dc_get_archived_cnt((*chat).context);
(*chat).name = to_cstring(format!("{} ({})", tempname, cnt));
(*chat).name = format!("{} ({})", tempname, cnt).strdup();
},
5 => unsafe {
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) {
unsafe {
free((*chat).name as *mut libc::c_void);
(*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);
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!(
context,
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 {
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 {
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_blocked = 0;
let contact: *mut dc_contact_t;
let chat_name: *mut libc::c_char;
if !ret_chat_id.is_null() {
*ret_chat_id = 0;
@@ -267,14 +264,8 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
}
return;
}
contact = dc_contact_new(context);
if dc_contact_load_from_db(contact, &context.sql, contact_id) {
chat_name =
if !(*contact).name.is_null() && 0 != *(*contact).name.offset(0isize) as libc::c_int {
(*contact).name
} else {
(*contact).addr
};
if let Ok(contact) = Contact::load_from_db(context, contact_id) {
let chat_name = contact.get_display_name();
if sql::execute(
context,
@@ -282,10 +273,10 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
format!(
"INSERT INTO chats (type, name, param, blocked, grpid) VALUES({}, '{}', '{}', {}, '{}')",
100,
as_str(chat_name),
if contact_id == 1 { "K=1" } else { "" },
chat_name,
if contact_id == DC_CONTACT_ID_SELF as u32 { "K=1" } else { "" },
create_blocked,
as_str((*contact).addr),
contact.get_addr(),
),
params![],
).is_ok() {
@@ -294,7 +285,7 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
&context.sql,
"chats",
"grpid",
as_str((*contact).addr),
contact.get_addr(),
);
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() {
*ret_chat_id = chat_id
}
@@ -371,14 +361,14 @@ pub unsafe fn dc_prepare_msg<'a>(
return msg_id;
}
pub fn msgtype_has_file(msgtype: i32) -> bool {
pub fn msgtype_has_file(msgtype: Viewtype) -> bool {
match msgtype {
DC_MSG_IMAGE => true,
DC_MSG_GIF => true,
DC_MSG_AUDIO => true,
DC_MSG_VOICE => true,
DC_MSG_VIDEO => true,
DC_MSG_FILE => true,
Viewtype::Image => true,
Viewtype::Gif => true,
Viewtype::Audio => true,
Viewtype::Voice => true,
Viewtype::Video => true,
Viewtype::File => true,
_ => false,
}
}
@@ -392,13 +382,13 @@ unsafe fn prepare_msg_common<'a>(
let mut OK_TO_CONTINUE = true;
(*msg).id = 0i32 as uint32_t;
(*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 */
} else if msgtype_has_file((*msg).type_0) {
let mut pathNfilename = (*msg)
.param
.get(Param::File)
.map(|s| to_cstring(s))
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
if pathNfilename.is_null() {
error!(
@@ -417,16 +407,16 @@ unsafe fn prepare_msg_common<'a>(
OK_TO_CONTINUE = false;
} else {
(*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.
Typical conversions:
- from FILE to AUDIO/VIDEO/IMAGE
- from FILE/IMAGE to GIF */
let mut better_type = 0;
let mut better_type = Viewtype::Unknown;
let mut better_mime = std::ptr::null_mut();
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).param.set(Param::MimeType, as_str(better_mime));
}
@@ -436,7 +426,7 @@ unsafe fn prepare_msg_common<'a>(
dc_msg_guess_msgtype_from_suffix(
pathNfilename,
0 as *mut libc::c_int,
0 as *mut Viewtype,
&mut better_mime,
);
@@ -516,16 +506,15 @@ unsafe fn prepare_msg_raw(
if from.is_none() {
error!(context, 0, "Cannot send message, not configured.",);
} else {
let from_c = to_cstring(from.unwrap());
let from_c = CString::yolo(from.unwrap());
new_rfc724_mid = dc_create_outgoing_rfc724_mid(
if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
(*chat).grpid
} else {
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 let Some(id) = context.sql.query_row_col(
@@ -729,7 +718,7 @@ unsafe fn prepare_msg_raw(
timestamp,
(*msg).type_0,
(*msg).state,
if !(*msg).text.is_null() { Some(as_str((*msg).text)) } else { None },
(*msg).text,
(*msg).param.to_string(),
(*msg).hidden,
to_string(new_in_reply_to),
@@ -780,18 +769,19 @@ unsafe fn get_parent_mime_headers(
|| parent_in_reply_to.is_null()
|| parent_references.is_null())
{
// prefer a last message that isn't from us
success = (*chat)
.context
.sql
.query_row(
"SELECT rfc724_mid, mime_in_reply_to, mime_references \
FROM msgs WHERE timestamp=(SELECT max(timestamp) \
FROM msgs WHERE chat_id=? AND from_id!=?);",
params![(*chat).id as i32, 1],
FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT max(timestamp) \
FROM msgs WHERE chat_id=?1 AND from_id!=?2);",
params![(*chat).id as i32, DC_CONTACT_ID_SELF as i32],
|row| {
*parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?);
*parent_in_reply_to = to_cstring(row.get::<_, String>(1)?);
*parent_references = to_cstring(row.get::<_, String>(2)?);
*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(())
},
)
@@ -803,13 +793,13 @@ unsafe fn get_parent_mime_headers(
.sql
.query_row(
"SELECT rfc724_mid, mime_in_reply_to, mime_references \
FROM msgs WHERE timestamp=(SELECT min(timestamp) \
FROM msgs WHERE chat_id=? AND from_id==?);",
params![(*chat).id as i32, 1],
FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT min(timestamp) \
FROM msgs WHERE chat_id=?1 AND from_id==?2);",
params![(*chat).id as i32, DC_CONTACT_ID_SELF as i32],
|row| {
*parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?);
*parent_in_reply_to = to_cstring(row.get::<_, String>(1)?);
*parent_references = to_cstring(row.get::<_, String>(2)?);
*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(())
},
)
@@ -954,7 +944,7 @@ pub unsafe fn dc_send_msg<'a>(
pub unsafe fn dc_send_text_msg(
context: &Context,
chat_id: uint32_t,
text_to_send: *const libc::c_char,
text_to_send: String,
) -> uint32_t {
if chat_id <= 9 {
warn!(
@@ -964,18 +954,8 @@ pub unsafe fn dc_send_text_msg(
return 0;
}
if text_to_send.is_null() {
warn!(context, 0, "dc_send_text_msg: text_to_send is emtpy");
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 mut msg = dc_msg_new(context, Viewtype::Text);
(*msg).text = Some(text_to_send);
let ret = dc_send_msg(context, chat_id, msg);
dc_msg_unref(msg);
ret
@@ -1004,15 +984,13 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t
}
// save new draft
if !msg.is_null() {
if (*msg).type_0 == DC_MSG_TEXT {
if (*msg).text.is_null() || *(*msg).text.offset(0isize) as libc::c_int == 0i32 {
OK_TO_CONTINUE = false;
}
if (*msg).type_0 == Viewtype::Text {
OK_TO_CONTINUE = (*msg).text.as_ref().map_or(false, |s| !s.is_empty());
} else if msgtype_has_file((*msg).type_0) {
let mut pathNfilename = (*msg)
.param
.get(Param::File)
.map(|s| to_cstring(s))
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
if pathNfilename.is_null() {
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(),
(*msg).type_0,
DC_STATE_OUT_DRAFT,
if !(*msg).text.is_null() {
as_str((*msg).text)
} else {
""
},
(*msg).text.as_ref().map(String::as_str).unwrap_or(""),
(*msg).param.to_string(),
1,
],
@@ -1258,20 +1232,20 @@ pub fn dc_marknoticed_all_chats(context: &Context) -> bool {
pub fn dc_get_chat_media(
context: &Context,
chat_id: uint32_t,
msg_type: libc::c_int,
msg_type2: libc::c_int,
msg_type3: libc::c_int,
msg_type: Viewtype,
msg_type2: Viewtype,
msg_type3: Viewtype,
) -> *mut dc_array_t {
context.sql.query_map(
"SELECT id FROM msgs WHERE chat_id=? AND (type=? OR type=? OR type=?) ORDER BY timestamp, id;",
params![
chat_id as i32,
msg_type,
if msg_type2 > 0 {
if msg_type2 != Viewtype::Unknown {
msg_type2
} else {
msg_type
}, if msg_type3 > 0 {
}, if msg_type3 != Viewtype::Unknown {
msg_type3
} else {
msg_type
@@ -1292,9 +1266,9 @@ pub unsafe fn dc_get_next_media(
context: &Context,
curr_msg_id: uint32_t,
dir: libc::c_int,
msg_type: libc::c_int,
msg_type2: libc::c_int,
msg_type3: libc::c_int,
msg_type: Viewtype,
msg_type2: Viewtype,
msg_type3: Viewtype,
) -> uint32_t {
let mut ret_msg_id: uint32_t = 0i32 as uint32_t;
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(
context,
(*msg).chat_id,
if msg_type > 0i32 {
if msg_type != Viewtype::Unknown {
msg_type
} else {
(*msg).type_0
@@ -1494,7 +1468,7 @@ pub unsafe fn dc_create_group_chat(
let draft_txt =
CString::new(context.stock_string_repl_str(StockMessage::NewGroupDraft, as_str(chat_name)))
.unwrap();
let grpid = as_str(dc_create_id());
let grpid = dc_create_id();
if sql::execute(
context,
&context.sql,
@@ -1510,7 +1484,7 @@ pub unsafe fn dc_create_group_chat(
chat_id = sql::get_rowid(context, &context.sql, "chats", "grpid", grpid);
if chat_id != 0 {
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());
set_draft_raw(context, chat_id, draft_msg);
dc_msg_unref(draft_msg);
@@ -1561,15 +1535,18 @@ pub unsafe fn dc_add_contact_to_chat_ex(
) -> libc::c_int {
let mut OK_TO_CONTINUE = true;
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 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);
let contact = contact.unwrap();
/*this also makes sure, not contacts are added to special or normal chats*/
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))
{
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
.get_config(context, "configured_addr")
.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.
// 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 continue and send status mail
if (*chat).type_0 == 130 {
if dc_contact_is_verified(contact) != 2 {
if contact.is_verified() != VerifiedStatus::BidirectVerified {
error!(
context, 0,
"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 (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
(*msg).type_0 = DC_MSG_TEXT;
(*msg).text = to_cstring(context.stock_system_msg(
(*msg).type_0 = Viewtype::Text;
(*msg).text = Some(context.stock_system_msg(
StockMessage::MsgAddMember,
as_str((*contact).addr),
contact.get_addr(),
"",
DC_CONTACT_ID_SELF as uint32_t,
));
(*msg).param.set_int(Param::Cmd, 4);
if !(*contact).addr.is_null() {
(*msg).param.set(Param::Arg, as_str((*contact).addr));
}
(*msg).param.set(Param::Arg, contact.get_addr());
(*msg).param.set_int(Param::Arg2, flags);
(*msg).id = dc_send_msg(context, chat_id, msg);
context.call_cb(
@@ -1646,7 +1621,6 @@ pub unsafe fn dc_add_contact_to_chat_ex(
}
}
dc_chat_unref(chat);
dc_contact_unref(contact);
dc_msg_unref(msg);
success
@@ -1708,13 +1682,12 @@ pub unsafe fn dc_remove_contact_from_chat(
chat_id: u32,
contact_id: u32,
) -> libc::c_int {
let mut success: libc::c_int = 0;
let contact: *mut dc_contact_t = dc_get_contact(context, contact_id);
let mut success = 0;
let chat: *mut Chat = dc_chat_new(context);
let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context);
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 */
/* 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 {
/* 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 {
(*msg).type_0 = DC_MSG_TEXT;
if (*contact).id == 1 as libc::c_uint {
(*msg).type_0 = Viewtype::Text;
if contact.id == DC_CONTACT_ID_SELF as u32 {
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,
"",
"",
DC_CONTACT_ID_SELF as u32,
));
} else {
(*msg).text = to_cstring(context.stock_system_msg(
(*msg).text = Some(context.stock_system_msg(
StockMessage::MsgDelMember,
as_str((*contact).addr),
contact.get_addr(),
"",
DC_CONTACT_ID_SELF as u32,
));
}
(*msg).param.set_int(Param::Cmd, 5);
if !(*contact).addr.is_null() {
(*msg).param.set(Param::Arg, as_str((*contact).addr));
}
(*msg).param.set(Param::Arg, contact.get_addr());
(*msg).id = dc_send_msg(context, chat_id, msg);
context.call_cb(
Event::MSGS_CHANGED,
@@ -1775,7 +1746,6 @@ pub unsafe fn dc_remove_contact_from_chat(
}
dc_chat_unref(chat);
dc_contact_unref(contact);
dc_msg_unref(msg);
success
@@ -1845,8 +1815,8 @@ pub unsafe fn dc_set_chat_name(
.is_ok()
{
if (*chat).param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
(*msg).type_0 = DC_MSG_TEXT;
(*msg).text = to_cstring(context.stock_system_msg(
(*msg).type_0 = Viewtype::Text;
(*msg).text = Some(context.stock_system_msg(
StockMessage::MsgGrpName,
as_str((*chat).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 {
(*msg).param.set_int(Param::Cmd, 3);
(*msg).param.set(Param::Arg, as_str(new_image_rel));
(*msg).type_0 = DC_MSG_TEXT;
(*msg).text = to_cstring(context.stock_system_msg(
(*msg).type_0 = Viewtype::Text;
(*msg).text = Some(context.stock_system_msg(
if !new_image_rel.is_null() {
StockMessage::MsgGrpImgChanged
} else {
@@ -1966,8 +1936,7 @@ pub unsafe fn dc_forward_msgs(
let msg = dc_msg_new_untyped(context);
let chat = dc_chat_new(context);
let contact = dc_contact_new(context);
let created_db_entries = carray_new(16);
let mut created_db_entries = Vec::new();
let mut curr_timestamp: i64;
dc_unarchive_chat(context, chat_id);
@@ -2000,7 +1969,7 @@ pub unsafe fn dc_forward_msgs(
break;
}
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.remove(Param::GuranteeE2ee);
@@ -2034,33 +2003,18 @@ pub unsafe fn dc_forward_msgs(
new_msg_id = prepare_msg_raw(context, chat, msg, fresh10);
dc_job_send_msg(context, new_msg_id);
}
carray_add(
created_db_entries,
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,
);
created_db_entries.push(chat_id);
created_db_entries.push(new_msg_id);
}
}
if !created_db_entries.is_null() {
let mut i = 0u32;
let icnt = carray_count(created_db_entries);
while i < icnt {
context.call_cb(
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);
for i in (0..created_db_entries.len()).step_by(2) {
context.call_cb(
Event::MSGS_CHANGED,
created_db_entries[i] as uintptr_t,
created_db_entries[i + 1] as uintptr_t,
);
}
dc_contact_unref(contact);
dc_msg_unref(msg);
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();
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 {
let ret_raw: String = (*chat)
.context
@@ -2108,17 +2065,16 @@ pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char {
0,
)
.unwrap_or_else(|| "Err".into());
ret = to_cstring(ret_raw);
ret = ret_raw.strdup();
} else if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
if (*chat).id == 1 {
ret = to_cstring((*chat).context.stock_str(StockMessage::DeadDrop));
ret = (*chat).context.stock_str(StockMessage::DeadDrop).strdup();
} else {
let cnt = dc_get_chat_contact_cnt((*chat).context, (*chat).id);
ret = to_cstring(
(*chat)
.context
.stock_string_repl_int(StockMessage::Member, cnt),
);
ret = (*chat)
.context
.stock_string_repl_int(StockMessage::Member, cnt)
.strdup();
}
}
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_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 contact: *mut dc_contact_t = 0 as *mut dc_contact_t;
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 {
image_abs = dc_get_abs_path((*chat).context, image_rel)
} else if (*chat).type_0 == 100i32 {
contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
if !(*contacts).is_empty() {
contact = dc_get_contact((*chat).context, (*contacts).get_id(0));
image_abs = dc_contact_get_profile_image(contact)
if let Ok(contact) = Contact::get_by_id((*chat).context, (*contacts).get_id(0)) {
if let Some(img) = contact.get_profile_image() {
image_abs = img.strdup();
}
}
}
}
}
free(image_rel as *mut libc::c_void);
dc_array_unref(contacts);
dc_contact_unref(contact);
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 {
let mut color: uint32_t = 0i32 as uint32_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).type_0 == 100i32 {
contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
if !(*contacts).is_empty() {
contact = dc_get_contact((*chat).context, (*contacts).get_id(0));
color = dc_str_to_color((*contact).addr) as uint32_t
if let Ok(contact) = Contact::get_by_id((*chat).context, (*contacts).get_id(0)) {
color = contact.get_color();
}
}
} else {
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_contact_unref(contact);
color
}
@@ -2287,7 +2249,7 @@ pub fn dc_add_device_msg(context: &Context, chat_id: uint32_t, text: *const libc
2,
2,
unsafe {dc_create_smeared_timestamp(context)},
DC_MSG_TEXT,
Viewtype::Text,
DC_STATE_IN_NOTICED,
as_str(text),
as_str(rfc724_mid),

View File

@@ -1102,14 +1102,14 @@ unsafe fn moz_autoconfigure(
tag_config: 0,
};
let url_c = to_cstring(url);
let url_c = url.strdup();
let xml_raw = read_autoconf_file(context, url_c);
free(url_c as *mut libc::c_void);
if xml_raw.is_null() {
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);
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 val: *mut libc::c_char = dc_strdup(text);
dc_trim(val);
let addr = to_cstring(&(*moz_ac).in_0.addr);
let addr = (*moz_ac).in_0.addr.strdup();
dc_str_replace(
&mut val,
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()
.and_then(|mut res| res.text())
{
Ok(res) => unsafe { to_cstring(res) },
Ok(res) => unsafe { res.strdup() },
Err(_err) => {
info!(context, 0, "Can\'t read file.",);
@@ -1322,7 +1322,7 @@ unsafe fn outlk_autodiscover(
) -> Option<dc_loginparam_t> {
let current_block: u64;
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 {
in_0: param_in,
out: dc_loginparam_new(),

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@ lazy_static! {
struct Dehtml {
strbuilder: String,
add_text: AddText,
last_href: *mut libc::c_char,
last_href: Option<String>,
}
#[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 {
strbuilder: String::with_capacity(strlen(buf_terminated)),
add_text: AddText::YesRemoveLineEnds,
last_href: 0 as *mut libc::c_char,
last_href: None,
};
let mut saxparser = dc_saxparser_t {
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_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(
@@ -66,7 +65,11 @@ unsafe fn dehtml_text_cb(
if dehtml.add_text == AddText::YesPreserveLineEnds
|| 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 {
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;
}
"a" => {
if !dehtml.last_href.is_null() {
if let Some(ref last_href) = dehtml.last_href.take() {
dehtml.strbuilder += "](";
dehtml.strbuilder += std::ffi::CStr::from_ptr((*dehtml).last_href)
.to_string_lossy()
.as_ref();
dehtml.strbuilder += last_href;
dehtml.strbuilder += ")";
free(dehtml.last_href as *mut libc::c_void);
dehtml.last_href = 0 as *mut libc::c_char;
}
}
"b" | "strong" => {
@@ -131,12 +130,13 @@ unsafe fn dehtml_starttag_cb(
dehtml.add_text = AddText::YesPreserveLineEnds;
}
"a" => {
free(dehtml.last_href as *mut libc::c_void);
dehtml.last_href = dc_strdup_keep_null(dc_attr_find(
let text_c = std::ffi::CStr::from_ptr(dc_attr_find(
attr,
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 += "[";
}
}

View File

@@ -66,7 +66,7 @@ pub unsafe fn dc_e2ee_encrypt(
mut in_out_message: *mut mailmime,
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 do_encrypt: libc::c_int = 0i32;
/*just a pointer into mailmime structure, must not be freed*/
@@ -115,11 +115,22 @@ pub unsafe fn dc_e2ee_encrypt(
|| 0 != e2ee_guaranteed)
{
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) {
keyring.add_owned(key.clone());
peerstates.push(peerstate);
}
} else {
info!(
context,
0,
"dc_e2ee_encrypt {} HAS NO peerstate {}",
recipient_addr,
peerstate.is_some()
);
do_encrypt = 0i32;
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
break;
@@ -177,16 +188,12 @@ pub unsafe fn dc_e2ee_encrypt(
let p = peerstates[i as usize]
.render_gossip_header(min_verified as usize);
if p.is_some() {
let header = to_cstring(p.unwrap());
if let Some(header) = p {
mailimf_fields_add(
imffields_encrypted,
mailimf_field_new_custom(
strdup(
b"Autocrypt-Gossip\x00" as *const u8
as *const libc::c_char,
),
header,
"Autocrypt-Gossip".strdup(),
header.strdup(),
),
);
}
@@ -287,7 +294,7 @@ pub unsafe fn dc_e2ee_encrypt(
);
mailmime_write_mem(plain, &mut col, message_to_encrypt);
if (*plain).str_0.is_null() || (*plain).len <= 0 {
current_block = 14181132614457621749;
ok_to_continue = false;
} else {
if let Some(ctext_v) = dc_pgp_pk_encrypt(
(*plain).str_0 as *const libc::c_void,
@@ -296,8 +303,8 @@ pub unsafe fn dc_e2ee_encrypt(
sign_key.as_ref(),
) {
let ctext_bytes = ctext_v.len();
let ctext = to_cstring(ctext_v);
(*helper).cdata_to_free = ctext as *mut _;
let ctext = ctext_v.strdup();
helper.cdata_to_free = ctext as *mut _;
/* create MIME-structure that will contain the encrypted text */
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;
(*encrypted_part).mm_parent = in_out_message;
mailmime_free(message_to_encrypt);
(*helper).encryption_successfull = 1i32;
current_block = 13824533195664196414;
helper.encryption_successfull = 1i32;
}
}
} else {
current_block = 13824533195664196414;
}
match current_block {
14181132614457621749 => {}
_ => {
let aheader = Aheader::new(addr, public_key, prefer_encrypt);
let rendered = to_cstring(aheader.to_string());
mailimf_fields_add(
imffields_unprotected,
mailimf_field_new_custom(
strdup(b"Autocrypt\x00" as *const u8 as *const libc::c_char),
rendered,
),
);
}
if ok_to_continue {
let aheader = Aheader::new(addr, public_key, prefer_encrypt);
mailimf_fields_add(
imffields_unprotected,
mailimf_field_new_custom(
"Autocrypt".strdup(),
aheader.to_string().strdup(),
),
);
}
}
}
@@ -384,7 +383,7 @@ unsafe fn new_data_part(
default_content_type: *mut libc::c_char,
default_encoding: libc::c_int,
) -> *mut mailmime {
let mut current_block: u64;
let mut ok_to_continue = true;
//char basename_buf[PATH_MAX];
let mut encoding: *mut mailmime_mechanism;
let content: *mut mailmime_content;
@@ -404,7 +403,7 @@ unsafe fn new_data_part(
}
content = mailmime_content_new_with_str(content_type_str);
if content.is_null() {
current_block = 16266721588079097885;
ok_to_continue = false;
} else {
do_encoding = 1i32;
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);
if encoding.is_null() {
current_block = 16266721588079097885;
} else {
current_block = 11057878835866523405;
ok_to_continue = false;
}
} else {
current_block = 11057878835866523405;
}
match current_block {
16266721588079097885 => {}
_ => {
mime_fields = mailmime_fields_new_with_data(
encoding,
0 as *mut libc::c_char,
0 as *mut libc::c_char,
0 as *mut mailmime_disposition,
0 as *mut mailmime_language,
);
if mime_fields.is_null() {
current_block = 16266721588079097885;
if ok_to_continue {
mime_fields = mailmime_fields_new_with_data(
encoding,
0 as *mut libc::c_char,
0 as *mut libc::c_char,
0 as *mut mailmime_disposition,
0 as *mut mailmime_language,
);
if mime_fields.is_null() {
ok_to_continue = false;
} else {
mime = mailmime_new_empty(content, mime_fields);
if mime.is_null() {
mailmime_fields_free(mime_fields);
mailmime_content_free(content);
} else {
mime = mailmime_new_empty(content, mime_fields);
if mime.is_null() {
mailmime_fields_free(mime_fields);
mailmime_content_free(content);
} else {
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;
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);
}
current_block = 13668317689588454213;
return mime;
}
}
}
}
match current_block {
16266721588079097885 => {
if !encoding.is_null() {
mailmime_mechanism_free(encoding);
}
if !content.is_null() {
mailmime_content_free(content);
}
if ok_to_continue == false {
if !encoding.is_null() {
mailmime_mechanism_free(encoding);
}
if !content.is_null() {
mailmime_content_free(content);
}
_ => {}
}
return 0 as *mut mailmime;
}
@@ -596,7 +585,7 @@ pub unsafe fn dc_e2ee_decrypt(
}
} else if let Some(ref header) = autocryptheader {
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);
}
}
@@ -841,7 +830,7 @@ unsafe fn decrypt_part(
ret_valid_signatures: &mut HashSet<String>,
ret_decrypted_mime: *mut *mut mailmime,
) -> libc::c_int {
let current_block: u64;
let mut ok_to_continue = true;
let mime_data: *mut mailmime_data;
let mut mime_transfer_encoding: libc::c_int = MAILMIME_MECHANISM_BINARY as libc::c_int;
/* 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;
if decoded_data.is_null() || decoded_data_bytes <= 0 {
/* no error - but no data */
current_block = 2554982661806928548;
} else {
current_block = 4488286894823169796;
ok_to_continue = false;
}
} else {
let r: libc::c_int;
@@ -908,53 +895,49 @@ unsafe fn decrypt_part(
|| transfer_decoding_buffer.is_null()
|| decoded_data_bytes <= 0
{
current_block = 2554982661806928548;
ok_to_continue = false;
} else {
decoded_data = transfer_decoding_buffer;
current_block = 4488286894823169796;
}
}
match current_block {
2554982661806928548 => {}
_ => {
/* encrypted, decoded data in decoded_data now ... */
if !(0 == has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int))
{
let add_signatures = if ret_valid_signatures.is_empty() {
Some(ret_valid_signatures)
} else {
None
};
if ok_to_continue {
/* encrypted, decoded data in decoded_data now ... */
if !(0 == has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int)) {
let add_signatures = if ret_valid_signatures.is_empty() {
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 let Some(plain) = dc_pgp_pk_decrypt(
decoded_data as *const libc::c_void,
decoded_data_bytes,
&private_keyring,
&public_keyring_for_validate,
add_signatures,
) {
let plain_bytes = plain.len();
let plain_buf = plain.as_ptr() as *const libc::c_char;
/*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(
decoded_data as *const libc::c_void,
decoded_data_bytes,
&private_keyring,
&public_keyring_for_validate,
add_signatures,
) {
let plain_bytes = plain.len();
let plain_buf = plain.as_ptr() as *const libc::c_char;
let mut index: size_t = 0i32 as size_t;
let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime;
if mailmime_parse(
plain_buf as *const _,
plain_bytes,
&mut index,
&mut decrypted_mime,
) != MAIL_NO_ERROR as libc::c_int
|| decrypted_mime.is_null()
{
if !decrypted_mime.is_null() {
mailmime_free(decrypted_mime);
}
} else {
*ret_decrypted_mime = decrypted_mime;
sth_decrypted = 1i32
let mut index: size_t = 0i32 as size_t;
let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime;
if mailmime_parse(
plain_buf as *const _,
plain_bytes,
&mut index,
&mut decrypted_mime,
) != MAIL_NO_ERROR as libc::c_int
|| decrypted_mime.is_null()
{
if !decrypted_mime.is_null() {
mailmime_free(decrypted_mime);
}
} 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
}
#[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 rand::{thread_rng, Rng};
use crate::config::Config;
use crate::constants::*;
use crate::context::Context;
use crate::dc_chat::*;
@@ -13,6 +14,7 @@ use crate::dc_e2ee::*;
use crate::dc_job::*;
use crate::dc_msg::*;
use crate::dc_tools::*;
use crate::error::*;
use crate::key::*;
use crate::param::*;
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 {
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 chat_id: uint32_t;
let mut msg: *mut dc_msg_t = 0 as *mut dc_msg_t;
let msg_id: uint32_t;
if 0 == dc_alloc_ongoing(context) {
return 0 as *mut libc::c_char;
if dc_alloc_ongoing(context) == 0 {
return std::ptr::null_mut();
}
setup_code = to_cstring(dc_create_setup_code(context));
if !setup_code.is_null() {
/* this may require a keypair to be created. this may take a second ... */
if !context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
setup_file_content = dc_render_setup_file(context, setup_code);
if !setup_file_content.is_null() {
/* encrypting may also take a while ... */
if !context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
setup_file_name = dc_get_fine_pathNfilename(
let setup_code = dc_create_setup_code(context);
/* this may require a keypair to be created. this may take a second ... */
if !context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
if let Ok(setup_file_content) = dc_render_setup_file(context, &setup_code) {
let setup_file_content_c = CString::yolo(setup_file_content.as_str());
/* encrypting may also take a while ... */
if !context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
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,
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,
setup_file_name,
setup_file_content as *const libc::c_void,
strlen(setup_file_content),
))
{
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));
setup_file_name,
setup_file_content_c.as_ptr() as *const libc::c_void,
setup_file_content_c.as_bytes().len(),
))
{
let 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 = Viewtype::File;
(*msg).param.set(Param::File, as_str(setup_file_name));
(*msg)
.param
.set(Param::MimeType, "application/autocrypt-setup");
(*msg).param.set_int(Param::Cmd, 6);
(*msg).param.set_int(Param::ForcePlaintext, 2);
(*msg)
.param
.set(Param::MimeType, "application/autocrypt-setup");
(*msg).param.set_int(Param::Cmd, 6);
(*msg).param.set_int(Param::ForcePlaintext, 2);
if !context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
msg_id = dc_send_msg(context, chat_id, msg);
if !(msg_id == 0i32 as libc::c_uint) {
if !context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
let msg_id = dc_send_msg(context, chat_id, msg);
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);
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;
}
}
msg = 0 as *mut dc_msg_t
}
}
}
@@ -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_content as *mut libc::c_void);
dc_msg_unref(msg);
dc_free_ongoing(context);
setup_code
setup_code.strdup()
}
pub unsafe extern "C" fn dc_render_setup_file(
context: &Context,
passphrase: *const libc::c_char,
) -> *mut libc::c_char {
let stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
let mut passphrase_begin: [libc::c_char; 8] = [0; 8];
let mut ret_setupfilecontent: *mut libc::c_char = 0 as *mut libc::c_char;
if !(passphrase.is_null() || strlen(passphrase) < 2) {
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);
}
}
}
pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result<String> {
ensure!(
passphrase.len() >= 2,
"Passphrase must be at least 2 chars long."
);
unsafe {
ensure!(
!(dc_ensure_secret_key_exists(context) == 0),
"No secret key available."
);
}
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 {
@@ -351,7 +326,7 @@ pub unsafe fn dc_continue_key_transfer(
armored_key = dc_decrypt_setup_file(context, norm_sc, filecontent);
if armored_key.is_null() {
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*/
/* error already logged */
success = 1i32
@@ -368,12 +343,11 @@ pub unsafe fn dc_continue_key_transfer(
success
}
// TODO should return bool /rtn
fn set_self_key(
context: &Context,
armored_c: *const libc::c_char,
set_default: libc::c_int,
) -> libc::c_int {
) -> bool {
assert!(!armored_c.is_null(), "invalid buffer");
let armored = as_str(armored_c);
@@ -383,7 +357,7 @@ fn set_self_key(
if keys.is_none() {
error!(context, 0, "File does not contain a valid private key.",);
return 0;
return false;
}
let (private_key, public_key, header) = keys.unwrap();
@@ -397,7 +371,7 @@ fn set_self_key(
)
.is_err()
{
return 0;
return false;
}
if 0 != set_default {
@@ -409,7 +383,7 @@ fn set_self_key(
)
.is_err()
{
return 0;
return false;
}
} else {
error!(context, 0, "File does not contain a private key.",);
@@ -419,7 +393,7 @@ fn set_self_key(
if self_addr.is_none() {
error!(context, 0, "Missing self addr");
return 0;
return false;
}
if !dc_key_save_self_keypair(
@@ -431,20 +405,20 @@ fn set_self_key(
&context.sql,
) {
error!(context, 0, "Cannot save keypair.");
return 0;
return false;
}
match preferencrypt.map(|s| s.as_str()) {
Some("") => 0,
Some("") => false,
Some("nopreference") => context
.sql
.set_config_int(context, "e2ee_enabled", 0)
.is_ok() as libc::c_int,
.is_ok(),
Some("mutual") => context
.sql
.set_config_int(context, "e2ee_enabled", 1)
.is_ok() as libc::c_int,
_ => 1,
.is_ok(),
_ => 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;
fc_buf = dc_strdup(filecontent);
if !(0
== dc_split_armored_data(
fc_buf,
&mut fc_headerline,
0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char,
&mut fc_base64,
)
|| fc_headerline.is_null()
|| strcmp(
if dc_split_armored_data(
fc_buf,
&mut fc_headerline,
0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char,
&mut fc_base64,
) && !fc_headerline.is_null()
&& strcmp(
fc_headerline,
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
) != 0i32
|| fc_base64.is_null())
) == 0
&& !fc_base64.is_null()
{
/* convert base64 to binary */
/*must be freed using mmap_string_unref()*/
@@ -536,7 +508,7 @@ pub unsafe fn dc_normalize_setup_code(
p1 = p1.offset(1);
}
to_cstring(out)
out.strdup()
}
#[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 ongoing_allocated_here: libc::c_int = 0;
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)) {
ongoing_allocated_here = 1;
what = (*job).param.get_int(Param::Cmd).unwrap_or_default();
param1 = to_cstring((*job).param.get(Param::Arg).unwrap_or_default());
param2 = to_cstring((*job).param.get(Param::Arg2).unwrap_or_default());
let param1 = CString::yolo((*job).param.get(Param::Arg).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.",);
} else {
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;
} else {
dc_create_folder(context, param1);
dc_create_folder(context, param1.as_ptr());
current_block = 4495394744059808450;
}
} 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;
match current_block {
2973387206439775448 => {
if 0 == import_backup(context, param1) {
if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
11250025114629486028 => {
if 0 == import_self_keys(context, param1) {
if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
12669919903773909120 => {
if 0 == export_backup(context, param1) {
if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
_ => {
if 0 == export_self_keys(context, param1) {
if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
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;
match current_block {
2973387206439775448 => {
if 0 == import_backup(context, param1) {
if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
11250025114629486028 => {
if 0 == import_self_keys(context, param1) {
if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
12669919903773909120 => {
if 0 == export_backup(context, param1) {
if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
_ => {
if 0 == export_self_keys(context, param1) {
if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
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;
match current_block {
2973387206439775448 => {
if 0 == import_backup(context, param1) {
if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
11250025114629486028 => {
if 0 == import_self_keys(context, param1) {
if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
12669919903773909120 => {
if 0 == export_backup(context, param1) {
if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
_ => {
if 0 == export_self_keys(context, param1) {
if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
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;
match current_block {
2973387206439775448 => {
if 0 == import_backup(context, param1) {
if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
11250025114629486028 => {
if 0 == import_self_keys(context, param1) {
if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
12669919903773909120 => {
if 0 == export_backup(context, param1) {
if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
_ => {
if 0 == export_self_keys(context, param1) {
if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
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 {
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)
.format("delta-chat-%Y-%m-%d.bak")
.to_string();
let buffer = to_cstring(res);
let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer);
free(buffer as *mut _);
let buffer = CString::yolo(res);
let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer.as_ptr());
if dest_pathNfilename.is_null() {
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 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 name_c: *mut libc::c_char = 0 as *mut libc::c_char;
let mut set_default: libc::c_int;
let mut buf: *mut libc::c_char = 0 as *mut libc::c_char;
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();
free(suffix as *mut libc::c_void);
let name_f = entry.file_name();
free(name_c as *mut libc::c_void);
name_c = to_cstring(name_f.to_string_lossy());
suffix = dc_get_filesuffix_lc(name_c);
let name_c = name_f.to_c_string().unwrap();
suffix = dc_get_filesuffix_lc(name_c.as_ptr());
if suffix.is_null()
|| 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(
b"%s/%s\x00" as *const u8 as *const libc::c_char,
dir_name,
name_c,
name_c.as_ptr(),
);
info!(context, 0, "Checking: {}", as_str(path_plus_name));
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;
free(buf2 as *mut libc::c_void);
buf2 = dc_strdup(buf);
if 0 != dc_split_armored_data(
if dc_split_armored_data(
buf2,
&mut buf2_headerline,
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;
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!(
context,
0,
@@ -1184,7 +1154,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
);
set_default = 0i32
}
if 0 == set_self_key(context, private_key, set_default) {
if !set_self_key(context, private_key, set_default) {
continue;
}
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(path_plus_name as *mut libc::c_void);
free(buf as *mut libc::c_void);
@@ -1310,3 +1279,201 @@ unsafe fn export_key_to_asc_file(
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_tools::*;
use crate::imap::*;
use crate::keyhistory::*;
use crate::param::*;
use crate::sql;
use crate::types::*;
use crate::x::*;
const DC_IMAP_THREAD: libc::c_int = 100;
const DC_SMTP_THREAD: libc::c_int = 5000;
// thread IDs
// jobs in the INBOX-thread, range from DC_IMAP_THREAD..DC_IMAP_THREAD+999
// low priority ...
@@ -51,15 +53,15 @@ pub unsafe fn dc_perform_imap_jobs(context: &Context) {
info!(context, 0, "dc_perform_imap_jobs starting.",);
let probe_imap_network = *context.probe_imap_network.clone().read().unwrap();
*context.probe_imap_network.write().unwrap() = 0;
*context.perform_inbox_jobs_needed.write().unwrap() = 0;
*context.probe_imap_network.write().unwrap() = false;
*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.",);
}
unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: libc::c_int) {
let query = if probe_network == 0 {
unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: bool) {
let query = if !probe_network {
// processing for first-try and after backoff-timeouts:
// process jobs in the order they were added.
"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_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
} else {
params_probe
@@ -116,7 +118,11 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
context,
0,
"{}-job #{}, action {} started...",
if thread == 100 { "INBOX" } else { "SMTP" },
if thread == DC_IMAP_THREAD {
"INBOX"
} else {
"SMTP"
},
job.job_id,
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_jobthread_suspend(context, &context.sentbox_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;
@@ -167,7 +173,7 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
&mut context.mvbox_thread.clone().read().unwrap(),
0,
);
dc_suspend_smtp_thread(context, 0);
dc_suspend_smtp_thread(context, false);
break;
} else if job.try_again == 2 {
// 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,
0,
"{}-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
);
} 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,
0,
"{}-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,
tries,
time_offset,
job.added_timestamp + time_offset - time()
);
if thread == 5000 && tries < 17 - 1 {
if thread == DC_SMTP_THREAD && tries < 17 - 1 {
context
.smtp_state
.clone()
@@ -210,7 +224,7 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
}
dc_job_delete(context, &mut job);
}
if 0 == probe_network {
if !probe_network {
continue;
}
// on dc_maybe_network() we stop trying here;
@@ -236,7 +250,7 @@ fn dc_job_delete(context: &Context, job: &dc_job_t) -> bool {
* Tools
******************************************************************************/
#[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
let mut N = 2_i32.pow((c_tries - 1) as u32);
N = N * 60;
@@ -264,11 +278,11 @@ fn dc_job_update(context: &Context, job: &dc_job_t) -> bool {
.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;
if 0 != suspend {
if suspend {
loop {
if context.smtp_state.0.lock().unwrap().doing_jobs == 0 {
if !context.smtp_state.0.lock().unwrap().doing_jobs {
return;
}
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 {
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 {
warn!(context, 0, "Missing file name for job {}", job.job_id,);
} 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,
);
param.set(Param::File, as_str(pathNfilename));
param.set(Param::File, as_str(recipients));
param.set(Param::Recipients, as_str(recipients));
dc_job_add(
context,
action,
@@ -801,10 +815,10 @@ pub unsafe fn dc_job_add(
delay_seconds: libc::c_int,
) {
let timestamp = time();
let thread = if action >= 100 && action < 100 + 1000 {
100
} else if action >= 5000 && action < 5000 + 1000 {
5000
let thread = if action >= DC_IMAP_THREAD && action < DC_IMAP_THREAD + 1000 {
DC_IMAP_THREAD
} else if action >= DC_SMTP_THREAD && action < DC_SMTP_THREAD + 1000 {
DC_SMTP_THREAD
} else {
return;
};
@@ -823,7 +837,7 @@ pub unsafe fn dc_job_add(
]
).ok();
if thread == 100 {
if thread == DC_IMAP_THREAD {
dc_interrupt_imap_idle(context);
} else {
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) {
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();
}
@@ -952,7 +966,7 @@ pub fn dc_perform_imap_idle(context: &Context) {
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!(
context,
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 probe_smtp_network = state.probe_network;
state.probe_network = 0;
state.probe_network = false;
state.perform_jobs_needed = 0;
if 0 != state.suspended {
if state.suspended {
info!(context, 0, "SMTP-jobs suspended.",);
return;
}
state.doing_jobs = 1;
state.doing_jobs = true;
probe_smtp_network
};
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.");
{
let &(ref lock, _) = &*context.smtp_state.clone();
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.",
);
} else {
let dur = get_next_wakeup_time(context, 5000);
let dur = get_next_wakeup_time(context, DC_SMTP_THREAD);
loop {
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 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);
@@ -1162,15 +1176,14 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in
} else {
// 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) {
let pathNfilename = to_cstring(
(*mimefactory.msg)
.param
.get(Param::File)
.unwrap_or_default(),
);
let pathNfilename = (*mimefactory.msg)
.param
.get(Param::File)
.unwrap_or_default()
.strdup();
if strlen(pathNfilename) > 0 {
if ((*mimefactory.msg).type_0 == DC_MSG_IMAGE
|| (*mimefactory.msg).type_0 == DC_MSG_GIF)
if ((*mimefactory.msg).type_0 == Viewtype::Image
|| (*mimefactory.msg).type_0 == Viewtype::Gif)
&& !(*mimefactory.msg).param.exists(Param::Width)
{
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);
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);
}
}

View File

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

View File

@@ -1,6 +1,6 @@
use crate::contact::*;
use crate::context::Context;
use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_msg::*;
use crate::dc_tools::*;
use crate::stock::StockMessage;
@@ -127,41 +127,58 @@ pub unsafe fn dc_lot_fill(
mut lot: *mut dc_lot_t,
msg: *mut dc_msg_t,
chat: *const Chat,
contact: *const dc_contact_t,
contact: Option<&Contact>,
context: &Context,
) {
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint || msg.is_null() {
return;
}
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
} else if (*msg).from_id == 1i32 as libc::c_uint {
if 0 != dc_msg_is_info(msg) || 0 != dc_chat_is_self_talk(chat) {
(*lot).text1 = 0 as *mut libc::c_char;
(*lot).text1_meaning = 0i32
} else {
(*lot).text1 = to_cstring(context.stock_str(StockMessage::SelfMsg));
(*lot).text1 = context.stock_str(StockMessage::SelfMsg).strdup();
(*lot).text1_meaning = 3i32
}
} else if chat.is_null() {
(*lot).text1 = 0 as *mut libc::c_char;
(*lot).text1_meaning = 0i32
} else if (*chat).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_meaning = 0i32
} else {
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 {
(*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).state = (*msg).state;
}

View File

@@ -9,11 +9,12 @@ use mmime::mailmime_types_helper::*;
use mmime::mailmime_write_mem::*;
use mmime::mmapstring::*;
use mmime::other::*;
use std::ptr;
use crate::constants::*;
use crate::contact::*;
use crate::context::Context;
use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_e2ee::*;
use crate::dc_location::*;
use crate::dc_msg::*;
@@ -158,13 +159,13 @@ pub unsafe fn dc_mimefactory_load_msg(
|rows| {
for row in rows {
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 {
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
if !authname.is_empty() {
to_cstring(authname)
authname.strdup()
} else {
std::ptr::null_mut()
} as *mut libc::c_void,
@@ -188,7 +189,7 @@ pub unsafe fn dc_mimefactory_load_msg(
if command == 5 {
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
.sql
@@ -234,8 +235,8 @@ pub unsafe fn dc_mimefactory_load_msg(
);
match row {
Ok((in_reply_to, references)) => {
(*factory).in_reply_to = to_cstring(in_reply_to);
(*factory).references = to_cstring(references);
(*factory).in_reply_to = in_reply_to.strdup();
(*factory).references = references.strdup();
}
Err(err) => {
error!(
@@ -259,27 +260,28 @@ pub unsafe fn dc_mimefactory_load_msg(
unsafe fn load_from(mut factory: *mut dc_mimefactory_t) {
let context = (*factory).context;
(*factory).from_addr = to_cstring(
context
.sql
.get_config(context, "configured_addr")
.unwrap_or_default(),
);
(*factory).from_addr = context
.sql
.get_config(context, "configured_addr")
.unwrap_or_default()
.strdup();
(*factory).from_displayname = to_cstring(
context
.sql
.get_config(context, "displayname")
.unwrap_or_default(),
);
(*factory).selfstatus = to_cstring(
context
.sql
.get_config(context, "selfstatus")
.unwrap_or_default(),
);
(*factory).from_displayname = context
.sql
.get_config(context, "displayname")
.unwrap_or_default()
.strdup();
(*factory).selfstatus = context
.sql
.get_config(context, "selfstatus")
.unwrap_or_default()
.strdup();
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 contact = 0 as *mut dc_contact_t;
(*factory).recipients_names = clist_new();
(*factory).recipients_addr = clist_new();
@@ -304,24 +305,19 @@ pub unsafe fn dc_mimefactory_load_mdn(
.unwrap_or_else(|| 1)
{
// 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)
|| !dc_contact_load_from_db(
contact,
&(*factory).context.sql,
(*(*factory).msg).from_id,
))
{
if !(0 != (*contact).blocked || (*(*factory).msg).chat_id <= 9 as libc::c_uint) {
if !dc_msg_load_from_db((*factory).msg, (*factory).context, msg_id) {
return success;
}
if let Ok(contact) = Contact::load_from_db((*factory).context, (*(*factory).msg).from_id) {
if !(contact.is_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()
if !((*(*factory).msg).from_id <= 9 as libc::c_uint) {
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
(if !(*contact).authname.is_null()
&& 0 != *(*contact).authname.offset(0isize) as libc::c_int
{
dc_strdup((*contact).authname)
(if !contact.get_authname().is_empty() {
contact.get_authname().strdup()
} else {
0 as *mut libc::c_char
}) as *mut libc::c_void,
@@ -329,7 +325,7 @@ pub unsafe fn dc_mimefactory_load_mdn(
clist_insert_after(
(*factory).recipients_addr,
(*(*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);
(*factory).timestamp = dc_create_smeared_timestamp((*factory).context);
@@ -344,15 +340,13 @@ pub unsafe fn dc_mimefactory_load_mdn(
}
}
dc_contact_unref(contact);
success
}
// TODO should return bool /rtn
pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc::c_int {
let subject: *mut mailimf_subject;
let mut current_block: u64;
let mut ok_to_continue = true;
let imf_fields: *mut mailimf_fields;
let mut message: *mut mailmime = 0 as *mut mailmime;
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,
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(
imf_fields,
mailimf_field_new_custom(
strdup(b"X-Mailer\x00" as *const u8 as *const libc::c_char),
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,
if !(*(*factory).context).os_name.is_null() {
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
},
os_part.as_ptr(),
),
),
);
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -573,8 +567,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
),
);
if command == 5 {
let email_to_remove =
to_cstring((*msg).param.get(Param::Arg).unwrap_or_default());
let email_to_remove = (*msg).param.get(Param::Arg).unwrap_or_default().strdup();
if strlen(email_to_remove) > 0 {
mailimf_fields_add(
imf_fields,
@@ -589,7 +582,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
}
} else if command == 4 {
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 {
mailimf_fields_add(
imf_fields,
@@ -619,7 +612,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
);
}
} 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(
imf_fields,
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),
),
);
placeholdertext =
to_cstring((*factory).context.stock_str(StockMessage::AcSetupMsgBody));
placeholdertext = (*factory)
.context
.stock_str(StockMessage::AcSetupMsgBody)
.strdup();
}
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 {
info!(
(*msg).context,
@@ -680,7 +675,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
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 {
mailimf_fields_add(
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 {
mailimf_fields_add(
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) {
Some(id) => to_cstring(id),
Some(id) => id.strdup(),
None => std::ptr::null_mut(),
};
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 {
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);
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);
}
if (*msg).type_0 == DC_MSG_VOICE
|| (*msg).type_0 == DC_MSG_AUDIO
|| (*msg).type_0 == DC_MSG_VIDEO
if (*msg).type_0 == Viewtype::Voice
|| (*msg).type_0 == Viewtype::Audio
|| (*msg).type_0 == Viewtype::Video
{
if (*msg).type_0 == DC_MSG_VOICE {
if (*msg).type_0 == Viewtype::Voice {
mailimf_fields_add(
imf_fields,
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;
if !placeholdertext.is_null() {
final_text = placeholdertext
} else if !(*msg).text.is_null() && 0 != *(*msg).text.offset(0isize) as libc::c_int {
final_text = (*msg).text
}
let final_text = {
if !placeholdertext.is_null() {
to_string(placeholdertext)
} else if let Some(ref text) = (*msg).text {
text.clone()
} else {
"".into()
}
};
let final_text = CString::yolo(final_text);
let footer: *mut libc::c_char = (*factory).selfstatus;
message_text = dc_mprintf(
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 {
b"\x00" as *const u8 as *const libc::c_char
},
if !final_text.is_null() {
final_text
} else {
b"\x00" as *const u8 as *const libc::c_char
},
if !final_text.is_null()
final_text.as_ptr(),
if final_text != CString::yolo("")
&& !footer.is_null()
&& 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 */
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(
b"Message exceeds the recommended %i MB.\x00" as *const u8
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);
free(error as *mut libc::c_void);
current_block = 11328123142868406523;
ok_to_continue = false;
} else {
let file_part: *mut mailmime =
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);
parts += 1
}
current_block = 13000670339742628194;
}
} else {
current_block = 13000670339742628194;
}
match current_block {
11328123142868406523 => {}
_ => {
if parts == 0 {
set_error(
factory,
b"Empty message.\x00" as *const u8 as *const libc::c_char,
);
current_block = 11328123142868406523;
} else {
if !meta_part.is_null() {
mailmime_smart_add_part(message, meta_part);
}
if (*msg).param.exists(Param::SetLatitude) {
let latitude = (*msg)
.param
.get_float(Param::SetLatitude)
.unwrap_or_default();
let longitude = (*msg)
.param
.get_float(Param::SetLongitude)
.unwrap_or_default();
let kml_file =
dc_get_message_kml((*msg).timestamp_sort, latitude, longitude);
if !kml_file.is_null() {
let content_type = mailmime_content_new_with_str(
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 ok_to_continue {
if parts == 0 {
set_error(
factory,
b"Empty message.\x00" as *const u8 as *const libc::c_char,
);
ok_to_continue = false;
} else {
if !meta_part.is_null() {
mailmime_smart_add_part(message, meta_part);
}
if (*msg).param.exists(Param::SetLatitude) {
let latitude = (*msg)
.param
.get_float(Param::SetLatitude)
.unwrap_or_default();
let longitude = (*msg)
.param
.get_float(Param::SetLongitude)
.unwrap_or_default();
let kml_file =
dc_get_message_kml((*msg).timestamp_sort, latitude, longitude);
if !kml_file.is_null() {
let content_type = mailmime_content_new_with_str(
b"application/vnd.google-earth.kml+xml\x00" as *const u8
as *const libc::c_char,
);
if !kml_file.is_null() {
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;
}
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 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,
);
mailmime_add_part(message, multipart);
let p1: *mut libc::c_char;
let p2: *mut libc::c_char;
if 0 != (*(*factory).msg)
.param
.get_int(Param::GuranteeE2ee)
.unwrap_or_default()
let p1 = if 0
!= (*(*factory).msg)
.param
.get_int(Param::GuranteeE2ee)
.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)
.context
.stock_string_repl_str(StockMessage::ReadRcptMailBody, as_str(p1)),
);
message_text = dc_mprintf(b"%s\r\n\x00" as *const u8 as *const libc::c_char, p2);
free(p1 as *mut libc::c_void);
free(p2 as *mut libc::c_void);
.stock_str(StockMessage::EncryptedMsg)
.into_owned()
} else {
to_string(dc_msg_get_summarytext((*factory).msg, 32))
};
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);
mailmime_add_part(multipart, human_mime_part);
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_add_part(multipart, mach_mime_part);
force_plaintext = 2;
current_block = 9952640327414195044;
} else {
set_error(
factory,
b"No message loaded.\x00" as *const u8 as *const libc::c_char,
);
current_block = 11328123142868406523;
ok_to_continue = false;
}
match current_block {
11328123142868406523 => {}
_ => {
if (*factory).loaded as libc::c_uint
== DC_MF_MDN_LOADED as libc::c_int as libc::c_uint
{
let e = CString::new(
(*factory)
.context
.stock_str(StockMessage::ReadRcpt)
.as_ref(),
)
.unwrap();
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 ok_to_continue {
if (*factory).loaded as libc::c_uint == DC_MF_MDN_LOADED as libc::c_int as libc::c_uint
{
let e = CString::new(
(*factory)
.context
.stock_str(StockMessage::ReadRcpt)
.as_ref(),
)
.unwrap();
subject_str = dc_mprintf(
b"Chat: %s\x00" as *const u8 as *const libc::c_char,
e.as_ptr(),
);
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
} 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 {
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() {
@@ -1095,15 +1070,24 @@ unsafe fn get_subject(
) -> *mut libc::c_char {
let context = (*chat).context;
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 {
b"Fwd: \x00" as *const u8 as *const libc::c_char
} else {
b"\x00" as *const u8 as *const libc::c_char
};
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
|| (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP as libc::c_int
{
@@ -1166,12 +1150,12 @@ unsafe fn build_body_file(
let pathNfilename = (*msg)
.param
.get(Param::File)
.map(|s| to_cstring(s))
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
let mut mimetype = (*msg)
.param
.get(Param::MimeType)
.map(|s| to_cstring(s))
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
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;
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 suffix = if !suffix.is_null() {
@@ -1190,10 +1174,10 @@ unsafe fn build_body_file(
let res = ts
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
.to_string();
filename_to_send = to_cstring(res);
} else if (*msg).type_0 == DC_MSG_AUDIO {
filename_to_send = res.strdup();
} else if (*msg).type_0 == Viewtype::Audio {
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() {
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
},
)
} else if (*msg).type_0 == DC_MSG_VIDEO {
} else if (*msg).type_0 == Viewtype::Video {
filename_to_send = dc_mprintf(
b"video.%s\x00" as *const u8 as *const libc::c_char,
if !suffix.is_null() {
@@ -1328,13 +1312,13 @@ unsafe fn build_body_file(
* Render
******************************************************************************/
#[allow(non_snake_case)]
unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> libc::c_int {
let mut file_size_okay = 1;
let pathNfilename = to_cstring((*msg).param.get(Param::File).unwrap_or_default());
unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> bool {
let mut file_size_okay = true;
let pathNfilename = (*msg).param.get(Param::File).unwrap_or_default().strdup();
let bytes = dc_get_filebytes((*msg).context, pathNfilename);
if bytes > (49 * 1024 * 1024 / 4 * 3) {
file_size_okay = 0;
file_size_okay = false;
}
free(pathNfilename as *mut _);

View File

@@ -11,8 +11,8 @@ use mmime::mailmime_types::*;
use mmime::mmapstring::*;
use mmime::other::*;
use crate::contact::*;
use crate::context::Context;
use crate::dc_contact::*;
use crate::dc_e2ee::*;
use crate::dc_location::*;
use crate::dc_simplify::*;
@@ -44,7 +44,7 @@ pub struct dc_mimepart_t {
#[derive(Clone)]
#[allow(non_camel_case_types)]
pub struct dc_mimeparser_t<'a> {
pub parts: *mut carray,
pub parts: Vec<dc_mimepart_t>,
pub mimeroot: *mut mailmime,
pub header: HashMap<String, *mut mailimf_field>,
pub header_root: *mut mailimf_fields,
@@ -55,7 +55,7 @@ pub struct dc_mimeparser_t<'a> {
pub e2ee_helper: dc_e2ee_helper_t,
pub is_forwarded: libc::c_int,
pub context: &'a Context,
pub reports: *mut carray,
pub reports: Vec<*mut mailmime>,
pub is_system_message: libc::c_int,
pub location_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 {
dc_mimeparser_t {
parts: carray_new(16i32 as libc::c_uint),
parts: Vec::new(),
mimeroot: std::ptr::null_mut(),
header: Default::default(),
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(),
is_forwarded: 0,
context,
reports: carray_new(16i32 as libc::c_uint),
reports: Vec::new(),
is_system_message: 0,
location_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) {
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) {
if !(*mimeparser).parts.is_null() {
let mut i: libc::c_int;
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);
for part in mimeparser.parts.drain(..) {
dc_mimepart_unref(part);
}
(*mimeparser).header_root = 0 as *mut mailimf_fields;
(*mimeparser).header.clear();
if !(*mimeparser).header_protected.is_null() {
mailimf_fields_free((*mimeparser).header_protected);
(*mimeparser).header_protected = 0 as *mut mailimf_fields
assert!(mimeparser.parts.is_empty());
mimeparser.header_root = 0 as *mut mailimf_fields;
mimeparser.header.clear();
if !mimeparser.header_protected.is_null() {
mailimf_fields_free(mimeparser.header_protected);
mimeparser.header_protected = 0 as *mut mailimf_fields
}
(*mimeparser).is_send_by_messenger = 0i32;
(*mimeparser).is_system_message = 0i32;
free((*mimeparser).subject as *mut libc::c_void);
(*mimeparser).subject = 0 as *mut libc::c_char;
if !(*mimeparser).mimeroot.is_null() {
mailmime_free((*mimeparser).mimeroot);
(*mimeparser).mimeroot = 0 as *mut mailmime
mimeparser.is_send_by_messenger = 0i32;
mimeparser.is_system_message = 0i32;
free(mimeparser.subject as *mut libc::c_void);
mimeparser.subject = 0 as *mut libc::c_char;
if !mimeparser.mimeroot.is_null() {
mailmime_free(mimeparser.mimeroot);
mimeparser.mimeroot = 0 as *mut mailmime
}
(*mimeparser).is_forwarded = 0i32;
if !(*mimeparser).reports.is_null() {
carray_set_size((*mimeparser).reports, 0i32 as libc::c_uint);
}
(*mimeparser).decrypting_failed = 0i32;
dc_e2ee_thanks(&mut (*mimeparser).e2ee_helper);
mimeparser.is_forwarded = 0i32;
mimeparser.reports.clear();
mimeparser.decrypting_failed = 0i32;
dc_e2ee_thanks(&mut mimeparser.e2ee_helper);
if let Some(location_kml) = (*mimeparser).location_kml.as_mut() {
dc_kml_unref(location_kml as *mut dc_kml_t);
if let Some(location_kml) = mimeparser.location_kml.as_mut() {
dc_kml_unref(location_kml);
}
(*mimeparser).location_kml = None;
mimeparser.location_kml = None;
if let Some(message_kml) = (*mimeparser).message_kml.as_mut() {
dc_kml_unref(message_kml as *mut dc_kml_t);
if let Some(message_kml) = mimeparser.message_kml.as_mut() {
dc_kml_unref(message_kml);
}
(*mimeparser).message_kml = None;
mimeparser.message_kml = None;
}
unsafe fn dc_mimepart_unref(mut mimepart: dc_mimepart_t) {
@@ -165,19 +148,18 @@ pub unsafe fn dc_mimeparser_parse(
body_not_terminated,
body_bytes,
&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(
(*mimeparser).context,
(*mimeparser).mimeroot,
&mut (*mimeparser).e2ee_helper,
mimeparser.context,
mimeparser.mimeroot,
&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");
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)
mimeparser.subject = dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value)
}
if !dc_mimeparser_lookup_optional_field(
mimeparser,
@@ -185,32 +167,37 @@ pub unsafe fn dc_mimeparser_parse(
)
.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() {
let mut i: libc::c_int;
let mut has_setup_file: libc::c_int = 0i32;
i = 0i32;
while (i as libc::c_uint) < carray_count((*mimeparser).parts) {
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 {
for part in &mimeparser.parts {
if part.int_mimetype == 111i32 {
has_setup_file = 1i32
}
i += 1
}
if 0 != has_setup_file {
(*mimeparser).is_system_message = 6i32;
i = 0i32;
while (i as libc::c_uint) < carray_count((*mimeparser).parts) {
let part_0 =
carray_get((*mimeparser).parts, i as libc::c_uint) as *mut dc_mimepart_t;
if (*part_0).int_mimetype != 111i32 {
dc_mimepart_unref(*Box::from_raw(part_0));
carray_delete_slow((*mimeparser).parts, i as libc::c_uint);
i -= 1
mimeparser.is_system_message = 6i32;
// TODO: replace the following code with this
// once drain_filter stabilizes.
//
// See https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter
// and https://github.com/rust-lang/rust/issues/43244
//
// 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 {
@@ -224,56 +211,69 @@ pub unsafe fn dc_mimeparser_parse(
b"location-streaming-enabled\x00" as *const u8 as *const libc::c_char,
) == 0i32
{
(*mimeparser).is_system_message = 8i32
mimeparser.is_system_message = 8i32
}
}
}
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 =
carray_get((*mimeparser).parts, 0i32 as libc::c_uint) as *mut dc_mimepart_t;
if (*textpart).type_0 == 10i32 {
if carray_count((*mimeparser).parts) >= 2i32 as libc::c_uint {
let mut imgpart: *mut dc_mimepart_t =
carray_get((*mimeparser).parts, 1i32 as libc::c_uint) as *mut dc_mimepart_t;
if (*imgpart).type_0 == 20i32 {
(*imgpart).is_meta = 1i32
let textpart = &mimeparser.parts[0];
if textpart.type_0 == 10i32 {
if mimeparser.parts.len() >= 2 {
let imgpart = &mut mimeparser.parts[1];
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
&& 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 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
let need_drop: bool;
{
free((*filepart).msg as *mut libc::c_void);
(*filepart).msg = (*textpart_0).msg;
(*textpart_0).msg = 0 as *mut libc::c_char;
dc_mimepart_unref(*Box::from_raw(textpart_0));
carray_delete_slow((*mimeparser).parts, 0i32 as libc::c_uint);
let textpart = &mimeparser.parts[0];
let filepart = &mimeparser.parts[1];
need_drop = textpart.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;
}
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;
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
|| 0 != (*mimeparser).is_send_by_messenger
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
|| 0 != mimeparser.is_send_by_messenger
|| !strstr(
(*mimeparser).subject,
mimeparser.subject,
b"Chat:\x00" as *const u8 as *const libc::c_char,
)
.is_null()
@@ -282,62 +282,48 @@ pub unsafe fn dc_mimeparser_parse(
}
}
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);
if !p_0.is_null() {
*p_0 = 0i32 as libc::c_char
}
dc_trim(subj);
if 0 != *subj.offset(0isize) {
let mut i_0: libc::c_int;
let icnt: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int;
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 {
for part in mimeparser.parts.iter_mut() {
if part.type_0 == 10i32 {
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,
(*part_1).msg,
part.msg,
);
free((*part_1).msg as *mut libc::c_void);
(*part_1).msg = new_txt;
free(part.msg as *mut libc::c_void);
part.msg = new_txt;
break;
} else {
i_0 += 1
}
}
}
free(subj as *mut libc::c_void);
}
}
if 0 != (*mimeparser).is_forwarded {
let mut i_1: libc::c_int;
let icnt_0: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int;
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 0 != mimeparser.is_forwarded {
for part in mimeparser.parts.iter_mut() {
part.param.set_int(Param::Forwarded, 1);
}
}
if carray_count((*mimeparser).parts) == 1i32 as libc::c_uint {
let mut part_3: *mut dc_mimepart_t =
carray_get((*mimeparser).parts, 0i32 as libc::c_uint) as *mut dc_mimepart_t;
if (*part_3).type_0 == 40i32 {
if mimeparser.parts.len() == 1 {
if mimeparser.parts[0].type_0 == 40i32 {
if !dc_mimeparser_lookup_optional_field(
mimeparser,
b"Chat-Voice-Message\x00" as *const u8 as *const libc::c_char,
)
.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(
mimeparser,
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() {
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 {
(*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(
mimeparser,
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 index_0: size_t = 0i32 as size_t;
if mailimf_mailbox_list_parse(
@@ -379,10 +366,9 @@ pub unsafe fn dc_mimeparser_parse(
);
if !from_addr.is_null() {
if strcmp(from_addr, dn_to_addr) == 0i32 {
let part_4: *mut dc_mimepart_t =
dc_mimeparser_get_last_nonmeta(mimeparser);
if !part_4.is_null() {
(*part_4).param.set_int(Param::WantsMdn, 1);
if let Some(part_4) = dc_mimeparser_get_last_nonmeta(mimeparser)
{
part_4.param.set_int(Param::WantsMdn, 1);
}
}
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 */
if dc_mimeparser_get_last_nonmeta(mimeparser).is_null()
&& carray_count((*mimeparser).reports) == 0i32 as libc::c_uint
{
if dc_mimeparser_get_last_nonmeta(mimeparser).is_none() && mimeparser.reports.is_empty() {
let mut part_5 = dc_mimepart_new();
part_5.type_0 = 10i32;
if !(*mimeparser).subject.is_null() && 0 == (*mimeparser).is_send_by_messenger {
part_5.msg = dc_strdup((*mimeparser).subject)
if !mimeparser.subject.is_null() && 0 == mimeparser.is_send_by_messenger {
part_5.msg = dc_strdup(mimeparser.subject)
} else {
part_5.msg = dc_strdup(b"\x00" as *const u8 as *const libc::c_char)
}
carray_add(
(*mimeparser).parts,
Box::into_raw(Box::new(part_5)) as *mut libc::c_void,
0 as *mut libc::c_uint,
);
mimeparser.parts.push(part_5);
};
}
@@ -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 {
if !(*mimeparser).parts.is_null() {
let mut i: libc::c_int;
let icnt: libc::c_int = carray_count((*mimeparser).parts) as libc::c_int;
i = icnt - 1i32;
while i >= 0i32 {
let part: *mut dc_mimepart_t =
carray_get(mimeparser.parts, i as libc::c_uint) as *mut dc_mimepart_t;
if !part.is_null() && 0 == (*part).is_meta {
return part;
}
i -= 1
}
}
0 as *mut 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)
}
/*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
}) as *mut mailimf_mailbox;
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).next
@@ -531,32 +503,32 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
) == 0i32
{
info!(
(*mimeparser).context,
mimeparser.context,
0, "Protected headers found in text/rfc822-headers attachment: Will be ignored.",
);
return 0i32;
}
if (*mimeparser).header_protected.is_null() {
if mimeparser.header_protected.is_null() {
let mut dummy: size_t = 0i32 as size_t;
if mailimf_envelope_and_optional_fields_parse(
(*mime).mm_mime_start,
(*mime).mm_length,
&mut dummy,
&mut (*mimeparser).header_protected,
&mut mimeparser.header_protected,
) != 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 {
hash_header(
&mut (*mimeparser).header,
(*mimeparser).header_protected,
(*mimeparser).context,
&mut mimeparser.header,
mimeparser.header_protected,
mimeparser.context,
);
}
} else {
info!(
(*mimeparser).context,
mimeparser.context,
0,
"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();
part.type_0 = 10i32;
let msg_body = CString::new(
(*mimeparser)
mimeparser
.context
.stock_str(StockMessage::CantDecryptMsgBody)
.as_ref(),
@@ -671,13 +643,9 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
msg_body.as_ptr(),
);
part.msg_raw = dc_strdup(part.msg);
carray_add(
(*mimeparser).parts,
Box::into_raw(Box::new(part)) as *mut libc::c_void,
0 as *mut libc::c_uint,
);
mimeparser.parts.push(part);
any_part_added = 1i32;
(*mimeparser).decrypting_failed = 1i32
mimeparser.decrypting_failed = 1i32
}
46 => {
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,
) == 0i32
{
carray_add(
(*mimeparser).reports,
mime as *mut libc::c_void,
0 as *mut libc::c_uint,
);
mimeparser.reports.push(mime);
} else {
any_part_added = dc_mimeparser_parse_mime_recursive(
mimeparser,
@@ -759,7 +723,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
}
if plain_cnt == 1i32 && html_cnt == 1i32 {
warn!(
(*mimeparser).context,
mimeparser.context,
0i32,
"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 => {
if (*mimeparser).header_root.is_null() {
(*mimeparser).header_root = (*mime).mm_data.mm_message.mm_fields;
if mimeparser.header_root.is_null() {
mimeparser.header_root = (*mime).mm_data.mm_message.mm_fields;
hash_header(
&mut (*mimeparser).header,
(*mimeparser).header_root,
(*mimeparser).context,
&mut mimeparser.header,
mimeparser.header_root,
mimeparser.context,
);
}
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,
) -> libc::c_int {
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_data: *mut mailmime_data;
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());
}
/* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */
let charset: *const libc::c_char =
mailmime_content_charset_get((*mime).mm_content_type);
let charset = mailmime_content_charset_get((*mime).mm_content_type);
if !charset.is_null()
&& strcmp(charset, b"utf-8\x00" as *const u8 as *const libc::c_char)
!= 0i32
@@ -1190,12 +1153,16 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
);
let (res, _, _) = encoding.decode(data);
info!(mimeparser.context, 0, "decoded message: '{}'", res);
if res.is_empty() {
/* no error - but nothing to add */
current_block = 8795901732489102124;
} else {
decoded_data_bytes = res.len();
decoded_data = res.as_ptr() as *const libc::c_char;
let b = res.as_bytes();
decoded_data = b.as_ptr() as *const libc::c_char;
decoded_data_bytes = b.len();
std::mem::forget(res);
current_block = 17788412896529399552;
}
} else {
@@ -1215,19 +1182,19 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
8795901732489102124 => {}
_ => {
/* 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,
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;
let simplified_txt: *mut libc::c_char =
simplifier.unwrap().simplify(
decoded_data,
decoded_data_bytes as libc::c_int,
if mime_type == 70i32 { 1i32 } else { 0i32 },
is_msgrmsg,
);
let simplified_txt = simplifier.unwrap().simplify(
decoded_data,
decoded_data_bytes as libc::c_int,
if mime_type == 70i32 { 1i32 } else { 0i32 },
is_msgrmsg,
);
if !simplified_txt.is_null()
&& 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);
}
if 0 != simplifier.unwrap().is_forwarded {
(*mimeparser).is_forwarded = 1i32
mimeparser.is_forwarded = 1i32
}
current_block = 10261677128829721533;
}
@@ -1323,9 +1290,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
}
if !filename_parts.is_empty() {
free(desired_filename as *mut libc::c_void);
let parts_c = to_cstring(filename_parts);
desired_filename = dc_decode_ext_header(parts_c);
free(parts_c as *mut _);
let parts_c = CString::yolo(filename_parts);
desired_filename = dc_decode_ext_header(parts_c.as_ptr());
}
if desired_filename.is_null() {
let param = mailmime_find_ct_parameter(
@@ -1371,8 +1337,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
4,
) == 0i32
{
(*mimeparser).location_kml = Some(dc_kml_parse(
(*mimeparser).context,
mimeparser.location_kml = Some(dc_kml_parse(
mimeparser.context,
decoded_data,
decoded_data_bytes,
));
@@ -1390,8 +1356,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
4,
) == 0i32
{
(*mimeparser).message_kml = Some(dc_kml_parse(
(*mimeparser).context,
mimeparser.message_kml = Some(dc_kml_parse(
mimeparser.context,
decoded_data,
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(desired_filename 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 {
1i32
return if mimeparser.parts.len() > old_part_count {
1
} else {
0i32
0
};
}
#[allow(non_snake_case)]
unsafe fn do_add_single_file_part(
parser: &dc_mimeparser_t,
parser: &mut dc_mimeparser_t,
msg_type: libc::c_int,
mime_type: libc::c_int,
raw_mime: *const libc::c_char,
@@ -1488,17 +1454,13 @@ unsafe fn do_add_single_file_part(
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 {
part.param.set_int(Param::GuranteeE2ee, 1);
} else if 0 != (*parser).e2ee_helper.encrypted {
part.param.set_int(Param::ErroneousE2ee, 0x2);
}
carray_add(
(*parser).parts,
Box::into_raw(Box::new(part)) as *mut libc::c_void,
0 as *mut libc::c_uint,
);
parser.parts.push(part);
}
// 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 mut fld_from: *const mailimf_from = 0 as *const mailimf_from;
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 */
fld = mailimf_find_field(mimeparser.header_root, MAILIMF_FIELD_FROM as libc::c_int);
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
}) as *mut mailimf_mailbox;
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);
if recipients.len() == 1 {
if recipients.contains(as_str(from_addr_norm)) {
if recipients.contains(from_addr_norm) {
sender_equals_recipient = 1i32;
}
}
}
}
}
free(from_addr_norm as *mut libc::c_void);
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
******************************************************************************/
#[allow(non_snake_case)]
unsafe fn mailimf_get_recipients__add_addr(
recipients: &mut HashSet<String>,
mb: *mut mailimf_mailbox,
) {
if !mb.is_null() {
let addr_norm: *mut libc::c_char = dc_addr_normalize((*mb).mb_addr_spec);
recipients.insert(to_string(addr_norm));
free(addr_norm as *mut libc::c_void);
let addr_norm = addr_normalize(as_str((*mb).mb_addr_spec));
recipients.insert(addr_norm.into());
};
}
@@ -1785,27 +1746,20 @@ pub unsafe fn mailimf_find_field(
}
pub unsafe fn dc_mimeparser_repl_msg_by_error(
mimeparser: &dc_mimeparser_t,
mimeparser: &mut dc_mimeparser_t,
error_msg: *const libc::c_char,
) {
let mut part: *mut dc_mimepart_t;
let mut i: libc::c_int;
if (*mimeparser).parts.is_null() || carray_count((*mimeparser).parts) <= 0i32 as libc::c_uint {
if mimeparser.parts.is_empty() {
return;
}
part = carray_get((*mimeparser).parts, 0i32 as libc::c_uint) as *mut dc_mimepart_t;
(*part).type_0 = 10i32;
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);
i = 1i32;
while (i as libc::c_uint) < carray_count((*mimeparser).parts) {
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
let part = &mut mimeparser.parts[0];
part.type_0 = 10i32;
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);
for part in mimeparser.parts.drain(1..) {
dc_mimepart_unref(part);
}
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*/

View File

@@ -1,9 +1,9 @@
use std::ffi::CString;
use crate::constants::*;
use crate::contact::*;
use crate::context::*;
use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_job::*;
use crate::dc_lot::dc_lot_t;
use crate::dc_lot::*;
@@ -14,6 +14,7 @@ use crate::sql;
use crate::stock::StockMessage;
use crate::types::*;
use crate::x::*;
use std::ptr;
/* * the structure behind dc_msg_t */
#[derive(Clone)]
@@ -25,13 +26,13 @@ pub struct dc_msg_t<'a> {
pub to_id: uint32_t,
pub chat_id: uint32_t,
pub move_state: dc_move_state_t,
pub type_0: libc::c_int,
pub type_0: Viewtype,
pub state: libc::c_int,
pub hidden: libc::c_int,
pub timestamp_sort: i64,
pub timestamp_sent: i64,
pub timestamp_rcvd: i64,
pub text: *mut libc::c_char,
pub text: Option<String>,
pub context: &'a Context,
pub rfc724_mid: *mut libc::c_char,
pub in_reply_to: *mut libc::c_char,
@@ -47,12 +48,10 @@ pub struct dc_msg_t<'a> {
// handle messages
pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_char {
let msg = dc_msg_new_untyped(context);
let contact_from = dc_contact_new(context);
let mut p: *mut libc::c_char;
let mut ret = String::new();
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(
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() {
ret += &format!("Cannot load message #{}.", msg_id as usize);
dc_msg_unref(msg);
dc_contact_unref(contact_from);
return to_cstring(ret);
return ret.strdup();
}
let rawtxt = rawtxt.unwrap();
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);
p = dc_contact_get_name_n_addr(contact_from);
ret += &format!(" by {}", to_string(p));
free(p as *mut libc::c_void);
let name = Contact::load_from_db(context, (*msg).from_id)
.map(|contact| contact.get_name_n_addr())
.unwrap_or_default();
ret += &format!(" by {}", name);
ret += "\n";
if (*msg).from_id != 1 as libc::c_uint {
p = dc_timestamp_to_str(if 0 != (*msg).timestamp_rcvd {
if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint {
let s = dc_timestamp_to_str(if 0 != (*msg).timestamp_rcvd {
(*msg).timestamp_rcvd
} else {
(*msg).timestamp_sort
});
ret += &format!("Received: {}", as_str(p));
free(p as *mut libc::c_void);
ret += &format!("Received: {}", &s);
ret += "\n";
}
if (*msg).from_id == 2 || (*msg).to_id == 2 {
// device-internal message, no further details needed
dc_msg_unref(msg);
dc_contact_unref(contact_from);
return to_cstring(ret);
return ret.strdup();
}
context
@@ -109,17 +107,14 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|rows| {
for row in rows {
let (contact_id, ts) = row?;
let fts = dc_timestamp_to_str_safe(ts);
let fts = dc_timestamp_to_str(ts);
ret += &format!("Read: {}", fts);
let contact = dc_contact_new(context);
dc_contact_load_from_db(contact, &context.sql, contact_id as u32);
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);
let name = Contact::load_from_db(context, contact_id as u32)
.map(|contact| contact.get_name_n_addr())
.unwrap_or_default();
ret += &format!(" by {}", name);
ret += "\n";
}
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);
if (*msg).type_0 != DC_MSG_TEXT {
if (*msg).type_0 != Viewtype::Text {
ret += "Type: ";
match (*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 += &format!("{}", (*msg).type_0);
ret += "\n";
p = dc_msg_get_filemime(msg);
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_contact_unref(contact_from);
to_cstring(ret)
ret.strdup()
}
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()
// approx. max. length returned by dc_msg_get_text()
// 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 {
magic: 0x11561156,
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_sent: 0,
timestamp_rcvd: 0,
text: std::ptr::null_mut(),
text: None,
context,
rfc724_mid: 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 {
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);
(*msg).rfc724_mid = 0 as *mut libc::c_char;
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) {
match (*msg).param.get(Param::MimeType) {
Some(m) => {
ret = to_cstring(m);
ret = m.strdup();
}
None => {
if let Some(file) = (*msg).param.get(Param::File) {
let file_c = to_cstring(file);
dc_msg_guess_msgtype_from_suffix(file_c, 0 as *mut libc::c_int, &mut ret);
let file_c = CString::yolo(file);
dc_msg_guess_msgtype_from_suffix(file_c.as_ptr(), 0 as *mut Viewtype, &mut ret);
if ret.is_null() {
ret = dc_strdup(
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)]
pub unsafe fn dc_msg_guess_msgtype_from_suffix(
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,
) {
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;
if !pathNfilename.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() {
ret_mime = &mut dummy_buf
}
*ret_msgtype = 0;
*ret_msgtype = Viewtype::Unknown;
*ret_mime = 0 as *mut libc::c_char;
suffix = dc_get_filesuffix_lc(pathNfilename);
if !suffix.is_null() {
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)
} 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)
} 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)
} 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
{
*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)
} 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)
} 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)
} 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)
} 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
{
*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)
}
}
@@ -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 let Some(file_rel) = (*msg).param.get(Param::File) {
let file_rel_c = to_cstring(file_rel);
file_abs = dc_get_abs_path((*msg).context, file_rel_c);
free(file_rel_c as *mut _);
let file_rel_c = CString::yolo(file_rel);
file_abs = dc_get_abs_path((*msg).context, file_rel_c.as_ptr());
}
}
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);
(*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)? {
Some(s) => to_cstring(s),
Some(s) => s.strdup(),
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).move_state = row.get(5)?;
(*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).state = row.get(13)?;
(*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).starred = row.get(17)?;
(*msg).hidden = row.get(18)?;
(*msg).location_id = row.get(19)?;
(*msg).chat_blocked = row.get::<_, Option<i32>>(20)?.unwrap_or_default();
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(())
}
);
}
});
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 {
let h = to_cstring(headers);
let res = dc_strdup_keep_null(h);
free(h as *mut _);
res
let h = CString::yolo(headers);
dc_strdup_keep_null(h.as_ptr())
} else {
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 {
return 0i32;
return Viewtype::Unknown;
}
(*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 {
return dc_strdup(0 as *const libc::c_char);
}
let res = dc_truncate_str(as_str((*msg).text), 30000);
to_cstring(res)
if let Some(ref text) = (*msg).text {
dc_truncate_str(text, 30000).strdup()
} else {
ptr::null_mut()
}
}
#[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 let Some(file) = (*msg).param.get(Param::File) {
let file_c = to_cstring(file);
ret = dc_get_filename(file_c);
free(file_c as *mut _);
let file_c = CString::yolo(file);
ret = dc_get_filename(file_c.as_ptr());
}
}
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 let Some(file) = (*msg).param.get(Param::File) {
let file_c = to_cstring(file);
ret = dc_get_filebytes((*msg).context, file_c);
free(file_c as *mut _);
let file_c = CString::yolo(file);
ret = dc_get_filebytes((*msg).context, file_c.as_ptr());
}
}
@@ -802,8 +788,8 @@ pub unsafe fn dc_msg_get_summary<'a>(
) -> *mut dc_lot_t {
let mut success = true;
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;
if !(msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint) {
if chat.is_null() {
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;
}
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)
{
contact = dc_get_contact((*chat).context, (*msg).from_id)
}
dc_lot_fill(ret, msg, chat, contact, (*msg).context);
Contact::get_by_id((*chat).context, (*msg).from_id).ok()
} else {
None
};
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
}
}
dc_contact_unref(contact);
dc_chat_unref(chat_to_delete);
ret
@@ -838,9 +827,15 @@ pub unsafe fn dc_msg_get_summarytext(
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(
(*msg).type_0,
(*msg).text,
msgtext_ptr,
&mut (*msg).param,
approx_characters,
(*msg).context,
@@ -850,7 +845,7 @@ pub unsafe fn dc_msg_get_summarytext(
/* the returned value must be free()'d */
#[allow(non_snake_case)]
pub unsafe fn dc_msg_get_summarytext_by_raw(
type_0: libc::c_int,
type_0: Viewtype,
text: *const libc::c_char,
param: &mut Params,
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 append_text: libc::c_int = 1i32;
match type_0 {
20 => prefix = to_cstring(context.stock_str(StockMessage::Image)),
21 => prefix = to_cstring(context.stock_str(StockMessage::Gif)),
50 => prefix = to_cstring(context.stock_str(StockMessage::Video)),
41 => prefix = to_cstring(context.stock_str(StockMessage::VoiceMessage)),
40 | 60 => {
Viewtype::Image => prefix = context.stock_str(StockMessage::Image).strdup(),
Viewtype::Gif => prefix = context.stock_str(StockMessage::Gif).strdup(),
Viewtype::Video => prefix = context.stock_str(StockMessage::Video).strdup(),
Viewtype::Voice => prefix = context.stock_str(StockMessage::VoiceMessage).strdup(),
Viewtype::Audio | Viewtype::File => {
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
} 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);
let label = CString::new(
context
.stock_str(if type_0 == DC_MSG_AUDIO {
.stock_str(if type_0 == Viewtype::Audio {
StockMessage::Audio
} else {
StockMessage::File
@@ -893,7 +891,7 @@ pub unsafe fn dc_msg_get_summarytext_by_raw(
}
_ => {
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;
}
}
@@ -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) -> libc::c_int {
pub unsafe fn dc_msg_is_starred(msg: *const dc_msg_t) -> bool {
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
@@ -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 {
if msg.is_null()
|| (*msg).magic != 0x11561156i32 as libc::c_uint
|| (*msg).type_0 != DC_MSG_FILE as libc::c_int
|| (*msg).type_0 != Viewtype::File
{
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_bytes <= 0)
{
if !(0
== dc_split_armored_data(
buf,
&mut buf_headerline,
&mut buf_setupcodebegin,
0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char,
)
|| strcmp(
buf_headerline,
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
) != 0i32
|| buf_setupcodebegin.is_null())
if dc_split_armored_data(
buf,
&mut buf_headerline,
&mut buf_setupcodebegin,
0 as *mut *const libc::c_char,
0 as *mut *const libc::c_char,
) && strcmp(
buf_headerline,
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
) == 0
&& !buf_setupcodebegin.is_null()
{
ret = dc_strdup(buf_setupcodebegin)
}
@@ -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 {
return;
}
free((*msg).text as *mut libc::c_void);
(*msg).text = dc_strdup(text);
(*msg).text = if text.is_null() {
None
} else {
Some(to_string(text))
};
}
pub unsafe fn dc_msg_set_file(
@@ -1395,7 +1393,7 @@ pub fn dc_rfc724_mid_exists(
&[as_str(rfc724_mid)],
|row| {
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() {
unsafe { *ret_server_uid = row.get(1)? };
@@ -1437,12 +1435,13 @@ pub fn dc_update_server_uid(
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils as test;
use std::ffi::CStr;
#[test]
fn test_dc_msg_guess_msgtype_from_suffix() {
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;
dc_msg_guess_msgtype_from_suffix(
@@ -1450,7 +1449,7 @@ mod tests {
&mut type_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");
free(mime_0 as *mut libc::c_void);
@@ -1459,7 +1458,7 @@ mod tests {
&mut type_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");
free(mime_0 as *mut libc::c_void);
@@ -1468,7 +1467,7 @@ mod tests {
&mut type_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");
free(mime_0 as *mut libc::c_void);
@@ -1477,7 +1476,7 @@ mod tests {
&mut type_0,
&mut mime_0,
);
assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int);
assert_eq!(type_0, Viewtype::Image);
assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str()
@@ -1491,7 +1490,7 @@ mod tests {
&mut type_0,
&mut mime_0,
);
assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int);
assert_eq!(type_0, Viewtype::Image);
assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str()
@@ -1505,7 +1504,7 @@ mod tests {
&mut type_0,
&mut mime_0,
);
assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int);
assert_eq!(type_0, Viewtype::Image);
assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str()
@@ -1519,7 +1518,7 @@ mod tests {
&mut type_0,
&mut mime_0,
);
assert_eq!(type_0, DC_MSG_IMAGE as libc::c_int);
assert_eq!(type_0, Viewtype::Image);
assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str()
@@ -1533,7 +1532,7 @@ mod tests {
&mut type_0,
&mut mime_0,
);
assert_eq!(type_0, DC_MSG_GIF as libc::c_int);
assert_eq!(type_0, Viewtype::Gif);
assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str()
@@ -1547,7 +1546,7 @@ mod tests {
&mut type_0,
&mut mime_0,
);
assert_eq!(type_0, DC_MSG_FILE as libc::c_int);
assert_eq!(type_0, Viewtype::File);
assert_eq!(
CStr::from_ptr(mime_0 as *const libc::c_char)
.to_str()
@@ -1557,4 +1556,32 @@ mod tests {
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 crate::contact::*;
use crate::context::Context;
use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_lot::*;
use crate::dc_strencode::*;
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");
addr = param
.get(Param::Forwarded)
.map(|s| to_cstring(s))
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
if !addr.is_null() {
if let Some(ref name_enc) = param.get(Param::SetLongitude) {
let name_r = percent_decode_str(name_enc)
.decode_utf8()
.expect("invalid name");
name = to_cstring(name_r);
dc_normalize_name(name);
name = normalize_name(name_r).strdup();
}
invitenumber = param
.get(Param::ProfileImage)
.map(|s| to_cstring(s))
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
auth = param
.get(Param::Auth)
.map(|s| to_cstring(s))
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
grpid = param
.get(Param::GroupId)
.map(|s| to_cstring(s))
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
if !grpid.is_null() {
if let Some(grpname_enc) = param.get(Param::GroupName) {
let grpname_r = percent_decode_str(grpname_enc)
.decode_utf8()
.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),
) == 0i32
{
let lines: *mut carray = dc_split_into_lines(qr);
let mut i: libc::c_int = 0i32;
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;
let lines = dc_split_into_lines(qr);
for &key in &lines {
dc_trim(key);
let mut value: *mut libc::c_char = strchr(key, ':' as i32);
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,
);
dc_normalize_name(name);
name = normalize_name(as_str(name)).strdup();
}
}
i += 1
}
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);
free(addr as *mut libc::c_void);
addr = temp;
temp = dc_addr_normalize(addr);
temp = addr_normalize(as_str(addr)).strdup();
free(addr as *mut libc::c_void);
addr = temp;
if !dc_may_be_valid_addr(addr) {
if !may_be_valid_addr(as_str(addr)) {
(*qr_parsed).state = 400i32;
(*qr_parsed).text1 = dc_strdup(
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 let Some(peerstate) = peerstate {
(*qr_parsed).state = 210i32;
let addr_ptr = if let Some(ref addr) = peerstate.addr {
to_cstring(addr)
} else {
std::ptr::null()
};
(*qr_parsed).id = dc_add_or_lookup_contact(
let addr = peerstate
.addr
.as_ref()
.map(|s| s.as_str())
.unwrap_or_else(|| "");
(*qr_parsed).id = Contact::add_or_lookup(
context,
0 as *const libc::c_char,
addr_ptr,
0x80i32,
0 as *mut libc::c_int,
);
free(addr_ptr as *mut _);
"",
addr,
Origin::UnhandledQrScan,
)
.map(|(id, _)| id)
.unwrap_or_default();
dc_create_or_lookup_nchat_by_contact_id(
context,
(*qr_parsed).id,
@@ -290,26 +285,28 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
} else {
(*qr_parsed).state = 200i32
}
(*qr_parsed).id = dc_add_or_lookup_contact(
(*qr_parsed).id = Contact::add_or_lookup(
context,
name,
addr,
0x80i32,
0 as *mut libc::c_int,
);
as_str(name),
as_str(addr),
Origin::UnhandledQrScan,
)
.map(|(id, _)| id)
.unwrap_or_default();
(*qr_parsed).fingerprint = dc_strdup(fingerprint);
(*qr_parsed).invitenumber = dc_strdup(invitenumber);
(*qr_parsed).auth = dc_strdup(auth)
}
} else if !addr.is_null() {
(*qr_parsed).state = 320i32;
(*qr_parsed).id = dc_add_or_lookup_contact(
(*qr_parsed).id = Contact::add_or_lookup(
context,
name,
addr,
0x80i32,
0 as *mut libc::c_int,
as_str(name),
as_str(addr),
Origin::UnhandledQrScan,
)
.map(|(id, _)| id)
.unwrap_or_default();
} else if strstr(
qr,
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 crate::constants::*;
use crate::contact::*;
use crate::context::Context;
use crate::dc_array::*;
use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_job::*;
use crate::dc_location::*;
use crate::dc_mimeparser::*;
@@ -38,7 +38,7 @@ pub unsafe fn dc_receive_imf(
let mut current_block: u64;
/* the function returns the number of created messages in the database */
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 from_id: uint32_t = 0 as uint32_t;
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 insert_msg_id: uint32_t = 0 as uint32_t;
let mut i: size_t;
let mut icnt: size_t;
/* Message-ID from the header */
let mut rfc724_mid = 0 as *mut libc::c_char;
let mut sort_timestamp = 0;
@@ -105,7 +103,7 @@ pub unsafe fn dc_receive_imf(
dc_add_or_lookup_contacts_by_mailbox_list(
context,
(*fld_from).frm_mb_list,
0x10,
Origin::IncomingUnknownFrom,
from_list,
&mut check_self,
);
@@ -116,7 +114,8 @@ pub unsafe fn dc_receive_imf(
}
} else if dc_array_get_cnt(from_list) >= 1 {
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);
}
@@ -129,18 +128,18 @@ pub unsafe fn dc_receive_imf(
context,
(*fld_to).to_addr_list,
if 0 == incoming {
0x4000
} else if incoming_origin >= 0x100 {
0x400
Origin::OutgoingTo
} else if incoming_origin.is_verified() {
Origin::IncomingTo
} else {
0x40
Origin::IncomingUnknownTo
},
to_ids,
&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");
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;
@@ -149,11 +148,11 @@ pub unsafe fn dc_receive_imf(
context,
(*fld_cc).cc_addr_list,
if 0 == incoming {
0x2000
} else if incoming_origin >= 0x100 {
0x200
Origin::OutgoingCc
} else if incoming_origin.is_verified() {
Origin::IncomingCc
} else {
0x20
Origin::IncomingUnknownCc
},
to_ids,
0 as *mut libc::c_int,
@@ -255,7 +254,7 @@ pub unsafe fn dc_receive_imf(
if chat_id == 0 as libc::c_uint {
let create_blocked: libc::c_int = if 0 != test_normal_chat_id
&& test_normal_chat_id_blocked == 0
|| incoming_origin >= 0x7fffffff
|| incoming_origin.is_start_new_chat()
{
0
} else {
@@ -287,7 +286,7 @@ pub unsafe fn dc_receive_imf(
}
if chat_id == 0 as libc::c_uint {
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
} else {
2
@@ -311,16 +310,20 @@ pub unsafe fn dc_receive_imf(
} else if 0
!= 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!(
context,
0,
"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
} else {
0x100
Origin::IncomingReplyTo
}
}
}
@@ -329,8 +332,8 @@ pub unsafe fn dc_receive_imf(
chat_id = 3 as uint32_t
}
if 0 != chat_id_blocked && state == 10 {
if incoming_origin < 0x100 && msgrmsg == 0 {
state = 13
if !incoming_origin.is_verified() && msgrmsg == 0 {
state = 13;
}
}
} else {
@@ -355,12 +358,13 @@ pub unsafe fn dc_receive_imf(
}
}
if chat_id == 0 as libc::c_uint && 0 != allow_creation {
let create_blocked_1: libc::c_int =
if 0 != msgrmsg && !dc_is_contact_blocked(context, to_id) {
0
} else {
2
};
let create_blocked_1: libc::c_int = if 0 != msgrmsg
&& !Contact::is_blocked_load(context, to_id)
{
0
} else {
2
};
dc_create_or_lookup_nchat_by_contact_id(
context,
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(
"INSERT INTO msgs \
@@ -452,23 +456,23 @@ pub unsafe fn dc_receive_imf(
current_block = 2756754640271984560;
break;
}
let part = carray_get(mime_parser.parts, i as libc::c_uint) as *mut dc_mimepart_t;
if !(0 != (*part).is_meta) {
let part = &mut mime_parser.parts[i];
if part.is_meta == 0 {
if !mime_parser.location_kml.is_none()
&& icnt == 1
&& !(*part).msg.is_null()
&& !part.msg.is_null()
&& (strcmp(
(*part).msg,
part.msg,
b"-location-\x00" as *const u8 as *const libc::c_char,
) == 0
|| *(*part).msg.offset(0isize) as libc::c_int == 0)
|| *part.msg.offset(0isize) as libc::c_int == 0)
{
hidden = 1;
if state == 10 {
state = 13
}
}
if (*part).type_0 == 10 {
if part.type_0 == 10 {
txt_raw = dc_mprintf(
b"%s\n\n%s\x00" as *const u8 as *const libc::c_char,
if !mime_parser.subject.is_null() {
@@ -476,12 +480,12 @@ pub unsafe fn dc_receive_imf(
} else {
b"\x00" as *const u8 as *const libc::c_char
},
(*part).msg_raw,
part.msg_raw,
)
}
if 0 != mime_parser.is_system_message {
(*part).param.set_int( Param::Cmd,
part.param.set_int( Param::Cmd,
mime_parser.is_system_message,
);
}
@@ -496,11 +500,11 @@ pub unsafe fn dc_receive_imf(
sort_timestamp,
sent_timestamp,
rcvd_timestamp,
(*part).type_0,
part.type_0,
state,
msgrmsg,
if !(*part).msg.is_null() {
as_str((*part).msg)
if !part.msg.is_null() {
as_str(part.msg)
} else {
""
},
@@ -510,8 +514,8 @@ pub unsafe fn dc_receive_imf(
} else {
String::new()
},
(*part).param.to_string(),
(*part).bytes,
part.param.to_string(),
part.bytes,
hidden,
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();
@@ -588,17 +592,13 @@ pub unsafe fn dc_receive_imf(
match current_block {
16282941964262048061 => {}
_ => {
if carray_count(mime_parser.reports) > 0 as libc::c_uint {
if !mime_parser.reports.is_empty() {
let mdns_enabled = context
.sql
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1);
icnt = carray_count(mime_parser.reports) as size_t;
i = 0 as size_t;
while i < icnt {
for report_root in mime_parser.reports {
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(
report_root,
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,
) {
rr_event_to_send
.push((chat_id_0, 0));
rr_event_to_send.push((msg_id, 0));
.push((chat_id_0, msg_id));
}
mdn_consumed = (msg_id
!= 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 {
@@ -771,7 +769,7 @@ pub unsafe fn dc_receive_imf(
context,
chat_id,
from_id,
mime_parser.message_kml.unwrap().locations,
&mime_parser.message_kml.unwrap().locations,
1,
);
if 0 != newest_location_id && 0 == hidden {
@@ -784,28 +782,34 @@ pub unsafe fn dc_receive_imf(
if !mime_parser.location_kml.is_none()
&& 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()
&& !contact.is_null()
&& !(*contact).addr.is_null()
&& strcasecmp(
(*contact).addr,
mime_parser.location_kml.as_ref().unwrap().addr,
) == 0
{
let newest_location_id = dc_save_locations(
context,
chat_id,
from_id,
mime_parser.location_kml.as_ref().unwrap().locations,
0,
);
if newest_location_id != 0 && hidden == 0 && !location_id_written {
dc_set_msg_location_id(context, insert_msg_id, newest_location_id);
if !mime_parser.location_kml.as_ref().unwrap().addr.is_null() {
if let Ok(contact) = Contact::get_by_id(context, from_id) {
if !contact.get_addr().is_empty()
&& contact.get_addr().to_lowercase()
== as_str(mime_parser.location_kml.as_ref().unwrap().addr)
.to_lowercase()
{
let newest_location_id = dc_save_locations(
context,
chat_id,
from_id,
&mime_parser.location_kml.as_ref().unwrap().locations,
0,
);
if newest_location_id != 0
&& hidden == 0
&& !location_id_written
{
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 {
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 {
let fld_message_id: *mut mailimf_message_id = (*field).fld_data.fld_message_id;
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() {
@@ -1015,9 +1025,8 @@ unsafe fn create_or_lookup_group(
if !optional_field.is_null() {
X_MrRemoveFromGrp = (*optional_field).fld_value;
mime_parser.is_system_message = 5;
let left_group: libc::c_int =
(dc_lookup_contact_id_by_addr(context, X_MrRemoveFromGrp)
== from_id as libc::c_uint) as libc::c_int;
let left_group = (Contact::lookup_id_by_addr(context, as_str(X_MrRemoveFromGrp))
== from_id as u32) as libc::c_int;
better_msg = context.stock_system_msg(
if 0 != left_group {
StockMessage::MsgGroupLeft
@@ -1126,7 +1135,7 @@ unsafe fn create_or_lookup_group(
&& !grpname.is_null()
&& X_MrRemoveFromGrp.is_null()
&& (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*/
/*re-create explicitly left groups only if ourself is re-added*/
@@ -1208,20 +1217,15 @@ unsafe fn create_or_lookup_group(
{
ok = 1
} else {
let mut i_0: libc::c_int = 0;
while (i_0 as libc::c_uint) < carray_count(mime_parser.parts) {
let part: *mut dc_mimepart_t =
carray_get(mime_parser.parts, i_0 as libc::c_uint)
as *mut dc_mimepart_t;
if (*part).type_0 == 20 {
grpimage = (*part)
for part in &mut mime_parser.parts {
if part.type_0 == 20 {
grpimage = part
.param
.get(Param::File)
.map(|s| to_cstring(s))
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
ok = 1
}
i_0 += 1
}
}
if 0 != ok {
@@ -1261,17 +1265,20 @@ unsafe fn create_or_lookup_group(
params![chat_id as i32],
)
.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);
}
if from_id > 9 {
if !dc_addr_equals_contact(context, &self_addr, from_id as u32)
&& (skip.is_null()
|| !dc_addr_equals_contact(
context,
to_string(skip),
from_id as u32,
))
if !Contact::addr_equals_contact(
context,
&self_addr,
from_id as u32,
) && (skip.is_null()
|| !Contact::addr_equals_contact(
context,
to_string(skip),
from_id as u32,
))
{
dc_add_to_chat_contacts_table(
context,
@@ -1283,9 +1290,13 @@ unsafe fn create_or_lookup_group(
i = 0;
while i < to_ids_cnt {
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()
|| !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);
}
@@ -1414,10 +1425,12 @@ unsafe fn create_or_lookup_adhoc_group(
{
grpname = dc_strdup(mime_parser.subject)
} else {
grpname = to_cstring(context.stock_string_repl_int(
StockMessage::Member,
dc_array_get_cnt(member_ids) as libc::c_int,
));
grpname = context
.stock_string_repl_int(
StockMessage::Member,
dc_array_get_cnt(member_ids) as libc::c_int,
)
.strdup();
}
chat_id =
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 result = Sha256::digest(bytes);
let result_hex = hex::encode(&result[..8]);
unsafe { to_cstring(result_hex) as *const _ }
unsafe { result_hex.strdup() as *const _ }
}
#[allow(non_snake_case)]
@@ -1554,7 +1567,7 @@ unsafe fn search_chat_ids_by_contact_ids(
i += 1
}
if !(dc_array_get_cnt(contact_ids) == 0) {
dc_array_sort_ids(contact_ids);
(*contact_ids).sort_ids();
contact_ids_str =
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,
failure_reason: *mut *mut libc::c_char,
) -> libc::c_int {
let contact = dc_contact_new(context);
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);
};
let cleanup = || {
dc_contact_unref(contact);
let contact = match Contact::load_from_db(context, from_id) {
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 {
verify_fail("This message is not encrypted".into());
cleanup();
return 0;
}
@@ -1636,18 +1644,18 @@ unsafe fn check_verified_properties(
// this check is skipped for SELF as there is no proper SELF-peerstate
// and results in group-splits otherwise.
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());
cleanup();
return 0;
}
if let Some(peerstate) = peerstate {
if !peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures) {
verify_fail("The message was sent with non-verified encryption.".into());
cleanup();
return 0;
}
}
@@ -1669,7 +1677,6 @@ unsafe fn check_verified_properties(
);
if rows.is_err() {
cleanup();
return 0;
}
for (to_addr, mut is_verified) in rows.unwrap().into_iter() {
@@ -1690,7 +1697,7 @@ unsafe fn check_verified_properties(
context,
0,
"{} has verfied {}.",
as_str((*contact).addr),
contact.get_addr(),
to_addr,
);
let fp = peerstate.gossip_key_fingerprint.clone();
@@ -1706,7 +1713,6 @@ unsafe fn check_verified_properties(
"{} is not a member of this verified group",
to_addr
));
cleanup();
return 0;
}
}
@@ -1714,14 +1720,13 @@ unsafe fn check_verified_properties(
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();
if !(msg.len() > 0) && carray_count((*mime_parser).parts) > 0 {
let mut part: *mut dc_mimepart_t =
carray_get(mime_parser.parts, 0 as libc::c_uint) as *mut dc_mimepart_t;
if msg.len() > 0 && !mime_parser.parts.is_empty() {
let part = &mut mime_parser.parts[0];
if (*part).type_0 == 10 {
free((*part).msg as *mut libc::c_void);
(*part).msg = to_cstring(msg);
free(part.msg as *mut libc::c_void);
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(
context: &Context,
adr_list: *const mailimf_address_list,
origin: libc::c_int,
origin: Origin,
ids: *mut dc_array_t,
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(
context: &Context,
mb_list: *const mailimf_mailbox_list,
origin: libc::c_int,
origin: Origin,
ids: *mut dc_array_t,
check_self: *mut libc::c_int,
) {
@@ -1976,7 +1981,7 @@ unsafe fn add_or_lookup_contact_by_addr(
context: &Context,
display_name_enc: *const libc::c_char,
addr_spec: *const libc::c_char,
origin: libc::c_int,
origin: Origin,
ids: *mut dc_array_t,
mut check_self: *mut libc::c_int,
) {
@@ -1994,7 +1999,7 @@ unsafe fn add_or_lookup_contact_by_addr(
.get_config(context, "configured_addr")
.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;
}
@@ -2002,20 +2007,15 @@ unsafe fn add_or_lookup_contact_by_addr(
return;
}
/* 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() {
display_name_dec = dc_decode_header_words(display_name_enc);
dc_normalize_name(display_name_dec);
let tmp = as_str(dc_decode_header_words(display_name_enc));
display_name_dec = normalize_name(&tmp);
}
/*can be NULL*/
let row_id = dc_add_or_lookup_contact(
context,
display_name_dec,
addr_spec,
origin,
0 as *mut libc::c_int,
);
free(display_name_dec as *mut libc::c_void);
let row_id = Contact::add_or_lookup(context, display_name_dec, as_str(addr_spec), origin)
.map(|(id, _)| id)
.unwrap_or_default();
if 0 != row_id {
if !dc_array_search_id(ids, row_id, 0 as *mut size_t) {
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) {
let current_block: u64;
let mut is_valid = false;
let mut bak: libc::c_char;
let buf_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;
loop {
if !(0 != *p) {
current_block = 13425230902034816933;
is_valid = true;
break;
}
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 {
p = strstr(p, b"-->\x00" as *const u8 as *const libc::c_char);
if p.is_null() {
current_block = 7627180618761592946;
break;
}
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),
'c' as i32 as libc::c_char,
);
current_block = 7627180618761592946;
break;
}
} 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 {
/* unclosed doctype */
current_block = 7627180618761592946;
break;
} else if *p as libc::c_int == '[' as i32 {
p = strstr(p, b"]>\x00" as *const u8 as *const libc::c_char);
if p.is_null() {
/* unclosed inline doctype */
current_block = 7627180618761592946;
break;
} else {
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);
if p.is_null() {
/* unclosed processing instruction */
current_block = 7627180618761592946;
break;
} else {
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);
if p.is_null() {
/* unclosed start-tag or end-tag */
current_block = 7627180618761592946;
break;
} else {
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)
}
}
match current_block {
13425230902034816933 => {
call_text_cb(
saxparser,
last_text_start,
p.wrapping_offset_from(last_text_start) as size_t,
'&' as i32 as libc::c_char,
);
}
_ => {}
if is_valid {
call_text_cb(
saxparser,
last_text_start,
p.wrapping_offset_from(last_text_start) as size_t,
'&' as i32 as libc::c_char,
);
}
do_free_attr(attr.as_mut_ptr(), free_attr.as_mut_ptr());
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::constants::*;
use crate::contact::*;
use crate::context::Context;
use crate::dc_array::*;
use crate::dc_chat::*;
use crate::dc_configure::*;
use crate::dc_contact::*;
use crate::dc_e2ee::*;
use crate::dc_lot::*;
use crate::dc_mimeparser::*;
@@ -40,17 +40,17 @@ pub unsafe fn dc_get_securejoin_qr(
let mut chat = 0 as *mut Chat;
let mut group_name = 0 as *mut libc::c_char;
let mut group_name_urlencoded = 0 as *mut libc::c_char;
let mut qr = None;
let mut qr: Option<String> = None;
dc_ensure_secret_key_exists(context);
invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id);
if invitenumber.is_null() {
invitenumber = dc_create_id();
invitenumber = dc_create_id().strdup();
dc_token_save(context, DC_TOKEN_INVITENUMBER, group_chat_id, invitenumber);
}
auth = dc_token_lookup(context, DC_TOKEN_AUTH, group_chat_id);
if auth.is_null() {
auth = dc_create_id();
auth = dc_create_id().strdup();
dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth);
}
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);
if let Some(qr) = qr {
to_cstring(qr)
qr.strdup()
} else {
std::ptr::null_mut()
}
@@ -263,11 +263,8 @@ unsafe fn send_handshake_msg(
grpid: *const libc::c_char,
) {
let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context);
(*msg).type_0 = DC_MSG_TEXT;
(*msg).text = dc_mprintf(
b"Secure-Join: %s\x00" as *const u8 as *const libc::c_char,
step,
);
(*msg).type_0 = Viewtype::Text;
(*msg).text = Some(format!("Secure-Join: {}", to_string(step)));
(*msg).hidden = 1;
(*msg).param.set_int(Param::Cmd, 7);
if step.is_null() {
@@ -318,30 +315,23 @@ unsafe fn fingerprint_equals_sender(
return 0;
}
let mut fingerprint_equal: libc::c_int = 0i32;
let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id);
let contact: *mut dc_contact_t = dc_contact_new(context);
let contacts = dc_get_chat_contacts(context, contact_chat_id);
if !(dc_array_get_cnt(contacts) != 1) {
if !dc_contact_load_from_db(
contact,
&context.sql,
dc_array_get_id(contacts, 0i32 as size_t),
) {
if let Ok(contact) = Contact::load_from_db(context, dc_array_get_id(contacts, 0)) {
if let Some(peerstate) = Peerstate::from_addr(context, &context.sql, contact.get_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;
}
}
} else {
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);
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 grpid: *mut libc::c_char = 0 as *mut libc::c_char;
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) {
step = lookup_field(mimeparser, "Secure-Join");
if !step.is_null() {
@@ -575,7 +565,11 @@ pub unsafe fn dc_handle_securejoin_handshake(
);
current_block = 4378276786830486580;
} else {
dc_scaleup_contact_origin(context, contact_id, 0x1000000i32);
Contact::scaleup_origin_by_id(
context,
contact_id,
Origin::SecurejoinInvited,
);
info!(context, 0, "Auth verified.",);
secure_connection_established(context, contact_chat_id);
context.call_cb(
@@ -702,16 +696,23 @@ pub unsafe fn dc_handle_securejoin_handshake(
);
current_block = 4378276786830486580;
} else {
dc_scaleup_contact_origin(context, contact_id, 0x2000000i32);
Contact::scaleup_origin_by_id(
context,
contact_id,
Origin::SecurejoinJoined,
);
context.call_cb(
Event::CONTACTS_CHANGED,
0i32 as uintptr_t,
0i32 as uintptr_t,
);
if 0 != join_vg {
if 0 == dc_addr_equals_self(
if !addr_equals_self(
context,
lookup_field(mimeparser, "Chat-Group-Member-Added"),
as_str(lookup_field(
mimeparser,
"Chat-Group-Member-Added",
)),
) {
info!(
context,
@@ -759,22 +760,26 @@ pub unsafe fn dc_handle_securejoin_handshake(
==== Alice - the inviter side ====
==== Step 8 in "Out-of-band verified groups" protocol ====
============================================================ */
contact = dc_get_contact(context, contact_id);
if contact.is_null() || 0 == dc_contact_is_verified(contact) {
if let Ok(contact) = Contact::get_by_id(context, contact_id) {
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.",);
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 {
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(auth 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) {
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 msg = CString::new(context.stock_string_repl_str(
StockMessage::ContactVerified,
if !contact.is_null() {
as_str((*contact).addr)
} else {
"?"
},
))
.unwrap();
let contact = Contact::get_by_id(context, contact_id);
let addr = if let Ok(ref contact) = contact {
contact.get_addr()
} else {
"?"
};
let msg =
CString::new(context.stock_string_repl_str(StockMessage::ContactVerified, addr)).unwrap();
dc_add_device_msg(context, contact_chat_id, msg.as_ptr());
context.call_cb(
Event::CHAT_MODIFIED,
contact_chat_id 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 {
@@ -847,11 +849,11 @@ unsafe fn could_not_establish_secure_connection(
details: *const libc::c_char,
) {
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(
StockMessage::ContactNotVerified,
if !contact.is_null() {
as_str((*contact).addr)
if let Ok(ref contact) = contact {
contact.get_addr()
} else {
"?"
},
@@ -859,7 +861,6 @@ unsafe fn could_not_establish_secure_connection(
let msg_c = CString::new(msg.as_str()).unwrap();
dc_add_device_msg(context, contact_chat_id, msg_c.as_ptr());
error!(context, 0, "{} ({})", msg, as_str(details));
dc_contact_unref(contact);
}
unsafe fn mark_peer_as_verified(

View File

@@ -1,6 +1,5 @@
use crate::dc_dehtml::*;
use crate::dc_tools::*;
use crate::types::*;
use crate::x::*;
#[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(
&mut self,
in_unterminated: *const libc::c_char,
@@ -27,6 +29,10 @@ impl dc_simplify_t {
is_html: libc::c_int,
is_msgrmsg: libc::c_int,
) -> *mut libc::c_char {
if in_bytes <= 0 {
return "".strdup();
}
/* create a copy of the given buffer */
let mut out: *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 `>`
... 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 */
let lines: *mut carray = dc_split_into_lines(buf_terminated);
let mut l: libc::c_int;
let mut l_first: libc::c_int = 0i32;
/* 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 lines = dc_split_into_lines(buf_terminated);
let mut l_first: usize = 0;
let mut l_last = lines.len();
let mut line: *mut libc::c_char;
let mut footer_mark: libc::c_int = 0i32;
l = l_first;
while l <= l_last {
line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char;
for l in l_first..l_last {
line = lines[l];
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
{
@@ -97,20 +99,15 @@ impl dc_simplify_t {
self.is_cut_at_end = 1i32
}
if 0 != footer_mark {
l_last = l - 1i32;
l_last = l;
/* done */
break;
} else {
l += 1
}
}
if l_last - l_first + 1i32 >= 3i32 {
let line0: *mut libc::c_char =
carray_get(lines, l_first as libc::c_uint) as *mut libc::c_char;
let line1: *mut libc::c_char =
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 l_last > l_first + 2 {
let line0: *mut libc::c_char = lines[l_first];
let line1: *mut libc::c_char = lines[l_first + 1];
let line2: *mut libc::c_char = lines[l_first + 2];
if strcmp(
line0,
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
{
self.is_forwarded = 1i32;
l_first += 3i32
l_first += 3
}
}
l = l_first;
while l <= l_last {
line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char;
for l in l_first..l_last {
line = lines[l];
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
{
l_last = l - 1i32;
l_last = l;
self.is_cut_at_end = 1i32;
/* done */
break;
} else {
l += 1
}
}
if 0 == is_msgrmsg {
let mut l_lastQuotedLine: libc::c_int = -1i32;
l = l_last;
while l >= l_first {
line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char;
let mut l_lastQuotedLine = None;
for l in (l_first..l_last).rev() {
line = lines[l];
if is_plain_quote(line) {
l_lastQuotedLine = l
l_lastQuotedLine = Some(l)
} else if !is_empty_line(line) {
break;
}
l -= 1
}
if l_lastQuotedLine != -1i32 {
l_last = l_lastQuotedLine - 1i32;
if l_lastQuotedLine.is_some() {
l_last = l_lastQuotedLine.unwrap();
self.is_cut_at_end = 1i32;
if l_last > 0i32 {
if is_empty_line(carray_get(lines, l_last as libc::c_uint) as *mut libc::c_char)
{
if l_last > 1 {
if is_empty_line(lines[l_last - 1]) {
l_last -= 1
}
}
if l_last > 0i32 {
line = carray_get(lines, l_last as libc::c_uint) as *mut libc::c_char;
if l_last > 1 {
line = lines[l_last - 1];
if is_quoted_headline(line) {
l_last -= 1
}
@@ -169,17 +160,16 @@ impl dc_simplify_t {
}
}
if 0 == is_msgrmsg {
let mut l_lastQuotedLine_0: libc::c_int = -1i32;
let mut hasQuotedHeadline: libc::c_int = 0i32;
l = l_first;
while l <= l_last {
line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char;
let mut l_lastQuotedLine_0 = None;
let mut hasQuotedHeadline = 0;
for l in l_first..l_last {
line = lines[l];
if is_plain_quote(line) {
l_lastQuotedLine_0 = l
l_lastQuotedLine_0 = Some(l)
} else if !is_empty_line(line) {
if is_quoted_headline(line)
&& 0 == hasQuotedHeadline
&& l_lastQuotedLine_0 == -1i32
&& l_lastQuotedLine_0.is_none()
{
hasQuotedHeadline = 1i32
} else {
@@ -187,10 +177,9 @@ impl dc_simplify_t {
break;
}
}
l += 1
}
if l_lastQuotedLine_0 != -1i32 {
l_first = l_lastQuotedLine_0 + 1i32;
if l_lastQuotedLine_0.is_some() {
l_first = l_lastQuotedLine_0.unwrap() + 1;
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 */
let mut pending_linebreaks: libc::c_int = 0i32;
let mut content_lines_added: libc::c_int = 0i32;
l = l_first;
while l <= l_last {
line = carray_get(lines, l as libc::c_uint) as *mut libc::c_char;
for l in l_first..l_last {
line = lines[l];
if is_empty_line(line) {
pending_linebreaks += 1
} else {
@@ -222,33 +210,16 @@ impl dc_simplify_t {
content_lines_added += 1;
pending_linebreaks = 1i32
}
l += 1
}
if 0 != self.is_cut_at_end && (0 == self.is_cut_at_begin || 0 != content_lines_added) {
ret += " [...]";
}
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
*/

View File

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

View File

@@ -42,7 +42,7 @@ pub fn dc_token_lookup(
params![namespc as i32, foreign_id as i32],
0,
)
.map(|s| unsafe { to_cstring(s) })
.map(|s| unsafe { s.strdup() })
.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
no references to Context and other "larger" classes here. */
// for carray etc.
/* ** library-private **********************************************************/
/* math tools */
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 */
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) {
let raw = to_cstring(to_string(in_0).to_lowercase());
assert_eq!(strlen(in_0), strlen(raw));
memcpy(in_0 as *mut _, raw as *const _, strlen(in_0));
free(raw as *mut _);
let raw = CString::yolo(to_string(in_0).to_lowercase());
assert_eq!(strlen(in_0), strlen(raw.as_ptr()));
memcpy(in_0 as *mut _, raw.as_ptr() as *const _, strlen(in_0));
}
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 raw = hex::encode_upper(buf);
to_cstring(raw)
raw.strdup()
}
/* 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 */
#[allow(non_snake_case)]
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() {
return;
}
@@ -280,7 +279,6 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) {
ix = p1len;
's_36: loop {
if !(i < ix) {
current_block = 13550086250199790493;
break;
}
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
{
/* U+d800 to U+dfff */
current_block = 2775201239069267972;
OK_TO_CONTINUE = false;
break;
} else if c & 0xf0i32 == 0xe0i32 {
n = 2i32
@@ -302,7 +300,7 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) {
} else {
//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 */
current_block = 2775201239069267972;
OK_TO_CONTINUE = false;
break;
}
j = 0i32;
@@ -310,25 +308,22 @@ pub unsafe fn dc_replace_bad_utf8_chars(buf: *mut libc::c_char) {
/* n bytes matching 10bbbbbb follow ? */
i += 1;
if i == ix || *p1.offset(i as isize) as libc::c_int & 0xc0i32 != 0x80i32 {
current_block = 2775201239069267972;
OK_TO_CONTINUE = false;
break 's_36;
}
j += 1
}
i += 1
}
match current_block {
13550086250199790493 => return,
_ => {
while 0 != *p1 {
if *p1 as libc::c_int > 0x7fi32 {
*p1 = '_' as i32 as libc::c_uchar
}
p1 = p1.offset(1isize)
if OK_TO_CONTINUE == false {
while 0 != *p1 {
if *p1 as libc::c_int > 0x7fi32 {
*p1 = '_' as i32 as libc::c_uchar
}
return;
p1 = p1.offset(1isize)
}
};
return;
}
}
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*/
pub unsafe fn dc_split_into_lines(buf_terminated: *const libc::c_char) -> *mut carray {
let lines: *mut carray = carray_new(1024i32 as libc::c_uint);
pub unsafe fn dc_split_into_lines(buf_terminated: *const libc::c_char) -> Vec<*mut libc::c_char> {
let mut lines = Vec::new();
let mut line_chars = 0;
let mut p1: *const libc::c_char = buf_terminated;
let mut line_start: *const libc::c_char = p1;
let mut l_indx: libc::c_uint = 0i32 as libc::c_uint;
while 0 != *p1 {
if *p1 as libc::c_int == '\n' as i32 {
carray_add(
lines,
strndup(line_start, line_chars) as *mut libc::c_void,
&mut l_indx,
);
lines.push(strndup(line_start, line_chars));
p1 = p1.offset(1isize);
line_start = p1;
line_chars = 0;
} else {
p1 = p1.offset(1isize);
line_chars = line_chars.wrapping_add(1)
line_chars += 1;
}
}
carray_add(
lines,
strndup(line_start, line_chars) as *mut libc::c_void,
&mut l_indx,
);
lines.push(strndup(line_start, line_chars));
lines
}
pub unsafe fn dc_free_splitted_lines(lines: *mut carray) {
if !lines.is_null() {
let mut i: libc::c_int;
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);
};
pub unsafe fn dc_free_splitted_lines(lines: Vec<*mut libc::c_char>) {
for s in lines {
free(s as *mut libc::c_void);
}
}
/* 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(
@@ -561,32 +539,32 @@ pub unsafe fn dc_str_to_clist(
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 {
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 str_len: libc::c_int = strlen(str_lower) as libc::c_int;
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
******************************************************************************/
/* the return value must be free()'d */
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 {
pub fn dc_timestamp_to_str(wanted: i64) -> String {
let ts = chrono::Utc.timestamp(wanted, 0);
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 */
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:
- 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.
@@ -744,39 +716,26 @@ pub unsafe fn dc_create_id() -> *mut libc::c_char {
encode_66bits_as_base64(buf[0usize], buf[1usize], buf[2usize])
}
/* ******************************************************************************
* generate Message-IDs
******************************************************************************/
unsafe fn encode_66bits_as_base64(v1: uint32_t, v2: uint32_t, fill: uint32_t) -> *mut libc::c_char {
/* encode 66 bits as a base64 string. 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 are 10 characters (grpid+msgid):
hex: 64 bit, 4 bits/character, length = 64/4 = 16 characters
base64: 64 bit, 6 bits/character, length = 64/6 = 11 characters (plus 2 additional bits) */
let ret: *mut libc::c_char = malloc(12) as *mut libc::c_char;
assert!(!ret.is_null());
/// Encode 66 bits as a base64 string.
/// 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
/// are 10 characters (grpid+msgid):
/// hex: 64 bit, 4 bits/character, length = 64/4 = 16 characters
/// base64: 64 bit, 6 bits/character, length = 64/6 = 11 characters (plus 2 additional bits)
/// Only the lower 2 bits of `fill` are used.
fn encode_66bits_as_base64(v1: u32, v2: u32, fill: u32) -> String {
use byteorder::{BigEndian, WriteBytesExt};
static mut CHARS: [libc::c_char; 65] = [
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,
113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
45, 95, 0,
];
*ret.offset(0isize) = CHARS[(v1 >> 26i32 & 0x3fi32 as libc::c_uint) as usize];
*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];
*ret.offset(3isize) = CHARS[(v1 >> 8i32 & 0x3fi32 as libc::c_uint) as usize];
*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
let mut wrapped_writer = Vec::new();
{
let mut enc = base64::write::EncoderWriter::new(&mut wrapped_writer, base64::URL_SAFE);
enc.write_u32::<BigEndian>(v1).unwrap();
enc.write_u32::<BigEndian>(v2).unwrap();
enc.write_u8(((fill & 0x3) as u8) << 6).unwrap();
enc.finish().unwrap();
}
assert_eq!(wrapped_writer.pop(), Some('A' as u8)); // Remove last "A"
String::from_utf8(wrapped_writer).unwrap()
}
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
- 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 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 mut at_hostname: *const libc::c_char = strchr(from_addr, '@' as i32);
if at_hostname.is_null() {
@@ -830,7 +789,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid(
at_hostname,
)
} else {
rand1 = dc_create_id();
rand1 = dc_create_id().strdup();
ret = dc_mprintf(
b"Mr.%s.%s%s\x00" as *const u8 as *const libc::c_char,
rand1,
@@ -844,52 +803,49 @@ pub unsafe fn dc_create_outgoing_rfc724_mid(
ret
}
pub unsafe fn dc_extract_grpid_from_rfc724_mid(mid: *const libc::c_char) -> *mut libc::c_char {
/* 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;
let mut grpid: *mut libc::c_char = 0 as *mut libc::c_char;
let p1: *mut libc::c_char;
let grpid_len: libc::c_int;
if !(mid.is_null()
|| strlen(mid) < 8
|| *mid.offset(0isize) as libc::c_int != 'G' as i32
|| *mid.offset(1isize) as libc::c_int != 'r' as i32
|| *mid.offset(2isize) as libc::c_int != '.' as i32)
{
grpid = dc_strdup(&*mid.offset(3isize));
p1 = strchr(grpid, '.' as i32);
if !p1.is_null() {
*p1 = 0i32 as libc::c_char;
grpid_len = strlen(grpid) as libc::c_int;
if !(grpid_len != 11i32 && grpid_len != 16i32) {
/* strict length comparison, the 'Gr.' magic is weak enough */
success = 1i32
/// Extract the group id (grpid) from a message id (mid)
///
/// # Arguments
///
/// * `mid` - A string that holds the message id
///
/// # Examples
///
/// ```
/// use deltachat::dc_tools::dc_extract_grpid_from_rfc724_mid;
/// let mid = "Gr.12345678901.morerandom@domain.de";
/// let grpid = dc_extract_grpid_from_rfc724_mid(mid);
/// assert_eq!(grpid, Some("12345678901"));
/// ```
pub fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> {
if mid.len() < 9 || !mid.starts_with("Gr.") {
return None;
}
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);
grpid = 0 as *mut libc::c_char
}
return if 0 != success {
grpid
} else {
0 as *mut libc::c_char
};
None
}
pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut libc::c_char {
if !list.is_null() {
let mut cur: *mut clistiter = (*list).first;
while !cur.is_null() {
let mid: *const libc::c_char = (if !cur.is_null() {
(*cur).data
let mid = if !cur.is_null() {
as_str((*cur).data as *const libc::c_char)
} 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() {
return grpid;
""
};
if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(mid) {
return grpid.strdup();
}
cur = if !cur.is_null() {
(*cur).next
@@ -1080,6 +1036,26 @@ pub unsafe fn dc_get_filemeta(
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)]
pub unsafe fn dc_get_abs_path(
context: &Context,
@@ -1110,137 +1086,79 @@ pub unsafe fn dc_get_abs_path(
pathNfilename_abs
}
#[allow(non_snake_case)]
pub unsafe fn dc_file_exist(context: &Context, pathNfilename: *const libc::c_char) -> 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
pub fn dc_file_exist(context: &Context, path: *const libc::c_char) -> libc::c_int {
dc_get_abs_path_safe(context, as_path(path)).exists() as libc::c_int
}
#[allow(non_snake_case)]
pub unsafe fn dc_get_filebytes(context: &Context, pathNfilename: *const libc::c_char) -> uint64_t {
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
if pathNfilename_abs.is_null() {
return 0;
pub fn dc_get_filebytes(context: &Context, path: *const libc::c_char) -> uint64_t {
let path_abs = dc_get_abs_path_safe(context, as_path(path));
match fs::metadata(&path_abs) {
Ok(meta) => meta.len() as uint64_t,
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 unsafe fn dc_delete_file(context: &Context, pathNfilename: *const libc::c_char) -> libc::c_int {
let mut success: libc::c_int = 0i32;
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
if pathNfilename_abs.is_null() {
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)
pub fn dc_delete_file(context: &Context, path: *const libc::c_char) -> libc::c_int {
let path = as_path(path);
let path_abs = dc_get_abs_path_safe(context, path);
let res = if path_abs.is_file() {
fs::remove_file(path_abs)
} else {
fs::remove_dir_all(p)
fs::remove_dir_all(path_abs)
};
match res {
Ok(_) => {
success = 1;
}
Ok(_) => 1,
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 unsafe fn dc_copy_file(
pub fn dc_copy_file(
context: &Context,
src: *const libc::c_char,
dest: *const libc::c_char,
) -> libc::c_int {
let mut success = 0;
let src_abs = dc_get_abs_path(context, src);
let dest_abs = dc_get_abs_path(context, dest);
if src_abs.is_null() || dest_abs.is_null() {
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;
}
let src = as_path(src);
let dest = as_path(dest);
let src_abs = dc_get_abs_path_safe(context, src);
let dest_abs = dc_get_abs_path_safe(context, dest);
match fs::copy(&src_abs, &dest_abs) {
Ok(_) => 1,
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 unsafe fn dc_create_folder(
context: &Context,
pathNfilename: *const libc::c_char,
) -> libc::c_int {
let mut success = 0;
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
{
let p = std::path::Path::new(as_str(pathNfilename_abs));
if !p.exists() {
match fs::create_dir_all(p) {
Ok(_) => {
success = 1;
}
Err(_err) => {
warn!(
context,
0,
"Cannot create directory \"{}\".",
as_str(pathNfilename),
);
}
pub fn dc_create_folder(context: &Context, path: *const libc::c_char) -> libc::c_int {
let path = as_path(path);
let path_abs = dc_get_abs_path_safe(context, path);
if !path_abs.exists() {
match fs::create_dir_all(path_abs) {
Ok(_) => 1,
Err(_err) => {
warn!(
context,
0,
"Cannot create directory \"{}\".",
path.display(),
);
0
}
} else {
success = 1;
}
} else {
1
}
free(pathNfilename_abs as *mut libc::c_void);
success
}
#[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
}
#[allow(non_snake_case)]
pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef<str>, buf: &[u8]) -> bool {
let pathNfilename_abs = unsafe {
let n = to_cstring(pathNfilename.as_ref());
let res = dc_get_abs_path(context, n);
free(n as *mut _);
res
};
if pathNfilename_abs.is_null() {
return false;
}
let p = as_str(pathNfilename_abs);
let success = if let Err(_err) = fs::write(p, buf) {
pub fn dc_write_file_safe<P: AsRef<std::path::Path>>(
context: &Context,
path: P,
buf: &[u8],
) -> bool {
let path_abs = dc_get_abs_path_safe(context, &path);
if let Err(_err) = fs::write(&path_abs, buf) {
warn!(
context,
0,
"Cannot write {} bytes to \"{}\".",
buf.len(),
pathNfilename.as_ref(),
path.as_ref().display(),
);
false
} else {
true
};
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
success
}
}
#[allow(non_snake_case)]
@@ -1306,36 +1213,20 @@ pub unsafe fn dc_read_file(
}
}
#[allow(non_snake_case)]
pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef<str>) -> Option<Vec<u8>> {
let pathNfilename_abs = unsafe {
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) {
pub fn dc_read_file_safe<P: AsRef<std::path::Path>>(context: &Context, path: P) -> Option<Vec<u8>> {
let path_abs = dc_get_abs_path_safe(context, &path);
match fs::read(&path_abs) {
Ok(bytes) => Some(bytes),
Err(_err) => {
warn!(
context,
0,
"Cannot read \"{}\" or file is empty.",
pathNfilename.as_ref(),
path.as_ref().display()
);
None
}
};
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
res
}
}
#[allow(non_snake_case)]
@@ -1545,10 +1436,49 @@ fn os_str_to_c_string_unicode(
}
}
/// Needs to free the result after use!
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");
dc_strdup(cstr.as_ref().as_ptr())
/// Convenience methods/associated functions for working with [CString]
///
/// This is helps transitioning from unsafe code.
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 {
@@ -1987,11 +1917,28 @@ mod tests {
#[test]
fn test_dc_create_id() {
unsafe {
let buf = dc_create_id();
assert_eq!(strlen(buf), 11);
free(buf as *mut libc::c_void);
}
let buf = dc_create_id();
assert_eq!(buf.len(), 11);
}
#[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]
@@ -2090,4 +2037,53 @@ mod tests {
let ptr = some_path.as_ptr();
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::sync::{Arc, Condvar, Mutex, RwLock};
use std::time::{Duration, SystemTime};
@@ -5,10 +6,9 @@ use std::time::{Duration, SystemTime};
use crate::constants::*;
use crate::context::Context;
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::types::*;
use crate::x::free;
pub const DC_IMAP_SEEN: usize = 0x0001;
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) {
let key = format!("imap.mailbox.{}", folder.as_ref());
let val1 = unsafe {
let key_c = to_cstring(key);
let val = (self.get_config)(context, key_c, 0 as *const libc::c_char);
free(key_c as *mut _);
val
};
if val1.is_null() {
return (0, 0);
if let Some(entry) = (self.get_config)(context, &key) {
// 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),
)
} 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 {
@@ -853,10 +843,8 @@ impl Imap {
.expect("missing message id");
if 0 == unsafe {
let message_id_c = to_cstring(message_id);
let res = (self.precheck_imf)(context, message_id_c, folder.as_ref(), cur_uid);
free(message_id_c as *mut _);
res
let message_id_c = CString::yolo(message_id);
(self.precheck_imf)(context, message_id_c.as_ptr(), folder.as_ref(), cur_uid)
} {
// check passed, go fetch the rest
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 val = format!("{}:{}", uidvalidity, lastseenuid);
unsafe {
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 _);
};
(self.set_config)(context, &key, Some(&val));
}
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.
pub fn to_asc_c(&self, header: Option<(&str, &str)>) -> *mut libc::c_char {
/// Each header line must be terminated by `\r\n`
pub fn to_asc(&self, header: Option<(&str, &str)>) -> String {
let headers = header.map(|(key, value)| {
let mut m = BTreeMap::new();
m.insert(key.to_string(), value.to_string());
m
});
let buf = self
.to_armored_string(headers.as_ref())
.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()) }
self.to_armored_string(headers.as_ref())
.expect("failed to serialize key")
}
pub fn write_asc_to_file(&self, file: *const libc::c_char, context: &Context) -> bool {
@@ -239,15 +233,16 @@ impl Key {
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
== unsafe {
dc_write_file(
context,
file,
file_content as *const libc::c_void,
strlen(file_content),
file_content_c.as_ptr() as *const libc::c_void,
file_content_c.as_bytes().len(),
)
} {
error!(context, 0, "Cannot write key to {}", to_string(file));
@@ -256,8 +251,6 @@ impl Key {
true
};
unsafe { free(file_content as *mut libc::c_void) };
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]
extern crate failure_derive;
@@ -8,6 +8,9 @@ extern crate num_derive;
extern crate smallvec;
#[macro_use]
extern crate rusqlite;
extern crate strum;
#[macro_use]
extern crate strum_macros;
#[macro_use]
mod log;
@@ -18,10 +21,10 @@ pub mod aheader;
pub mod chatlist;
pub mod config;
pub mod constants;
pub mod contact;
pub mod context;
pub mod imap;
pub mod key;
pub mod keyhistory;
pub mod keyring;
pub mod oauth2;
pub mod param;
@@ -36,7 +39,6 @@ pub mod x;
pub mod dc_array;
pub mod dc_chat;
pub mod dc_configure;
pub mod dc_contact;
pub mod dc_dehtml;
pub mod dc_e2ee;
pub mod dc_imex;

View File

@@ -7,10 +7,9 @@ macro_rules! info {
#[allow(unused_unsafe)]
unsafe {
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,
formatted_c as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void);
formatted_c.as_ptr() as libc::uintptr_t);
}};
}
@@ -23,10 +22,9 @@ macro_rules! warn {
#[allow(unused_unsafe)]
unsafe {
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,
formatted_c as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void) ;
formatted_c.as_ptr() as libc::uintptr_t);
}};
}
@@ -39,10 +37,9 @@ macro_rules! error {
#[allow(unused_unsafe)]
unsafe {
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,
formatted_c as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void);
formatted_c.as_ptr() as libc::uintptr_t);
}};
}
@@ -55,9 +52,8 @@ macro_rules! log_event {
#[allow(unused_unsafe)]
unsafe {
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,
formatted_c as libc::uintptr_t);
libc::free(formatted_c as *mut libc::c_void);
formatted_c.as_ptr() as libc::uintptr_t);
}};
}

View File

@@ -166,7 +166,6 @@ impl<'a> Peerstate<'a> {
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;";
Self::from_stmt(context, query, &[addr])
}
@@ -191,6 +190,11 @@ impl<'a> Peerstate<'a> {
context
.sql
.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);
res.addr = Some(row.get(0)?);
@@ -198,13 +202,34 @@ impl<'a> Peerstate<'a> {
res.last_seen_autocrypt = row.get(2)?;
res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
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
.get(4)
.ok()
@@ -217,7 +242,8 @@ impl<'a> Peerstate<'a> {
.get(9)
.ok()
.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
} else if vk == res.public_key {
VerifiedKey::Public
@@ -422,6 +448,7 @@ impl<'a> Peerstate<'a> {
&self.addr,
],
).is_ok();
assert_eq!(success, true);
} else if self.to_save == Some(ToSave::Timestamps) {
success = sql::execute(
self.context,
@@ -462,16 +489,11 @@ mod tests {
use super::*;
use pretty_assertions::assert_eq;
use std::ffi::CStr;
use tempfile::{tempdir, TempDir};
use crate::context::*;
use crate::dc_tools::to_cstring;
use crate::x::free;
use tempfile::TempDir;
#[test]
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 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);
}
#[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
#[allow(dead_code)]
struct TestContext {
ctx: Context,
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::x::*;
// TODO should return bool /rtn
pub unsafe fn dc_split_armored_data(
buf: *mut libc::c_char,
ret_headerline: *mut *const libc::c_char,
ret_setupcodebegin: *mut *const libc::c_char,
ret_preferencrypt: *mut *const libc::c_char,
ret_base64: *mut *const libc::c_char,
) -> libc::c_int {
let mut success: libc::c_int = 0i32;
) -> bool {
let mut success = false;
let mut line_chars: size_t = 0i32 as size_t;
let mut line: *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() {
*ret_base64 = base64
}
success = 1i32
success = true;
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,3 @@
use crate::types::*;
pub use libc::{
calloc, exit, free, malloc, memcmp, memcpy, memmove, memset, realloc, strcat, strchr, strcmp,
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" {
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
pub fn dc_mprintf(format: *const libc::c_char, _: ...) -> *mut libc::c_char;