mirror of
https://github.com/chatmail/core.git
synced 2026-05-02 04:46:29 +03:00
refactor: remove x module and delete deadcode
This commit is contained in:
committed by
holger krekel
parent
b85f59798c
commit
05f9f454c3
@@ -24,7 +24,9 @@ use num_traits::{FromPrimitive, ToPrimitive};
|
|||||||
|
|
||||||
use deltachat::contact::Contact;
|
use deltachat::contact::Contact;
|
||||||
use deltachat::context::Context;
|
use deltachat::context::Context;
|
||||||
use deltachat::dc_tools::{as_path, as_str, dc_strdup, to_string, OsStrExt, StrExt};
|
use deltachat::dc_tools::{
|
||||||
|
as_path, as_str, dc_strdup, to_string, to_string_lossy, OsStrExt, StrExt,
|
||||||
|
};
|
||||||
use deltachat::*;
|
use deltachat::*;
|
||||||
|
|
||||||
// as C lacks a good and portable error handling,
|
// as C lacks a good and portable error handling,
|
||||||
@@ -186,7 +188,7 @@ pub unsafe extern "C" fn dc_context_new(
|
|||||||
let os_name = if os_name.is_null() {
|
let os_name = if os_name.is_null() {
|
||||||
String::from("DcFFI")
|
String::from("DcFFI")
|
||||||
} else {
|
} else {
|
||||||
dc_tools::to_string_lossy(os_name)
|
to_string_lossy(os_name)
|
||||||
};
|
};
|
||||||
let ffi_ctx = ContextWrapper {
|
let ffi_ctx = ContextWrapper {
|
||||||
cb,
|
cb,
|
||||||
@@ -735,7 +737,7 @@ pub unsafe extern "C" fn dc_send_text_msg(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
let ffi_context = &*context;
|
let ffi_context = &*context;
|
||||||
let text_to_send = dc_tools::to_string_lossy(text_to_send);
|
let text_to_send = to_string_lossy(text_to_send);
|
||||||
ffi_context
|
ffi_context
|
||||||
.with_inner(|ctx| {
|
.with_inner(|ctx| {
|
||||||
chat::send_text_msg(ctx, chat_id, text_to_send)
|
chat::send_text_msg(ctx, chat_id, text_to_send)
|
||||||
@@ -2861,7 +2863,7 @@ fn as_opt_str<'a>(s: *const libc::c_char) -> Option<&'a str> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(dc_tools::as_str(s))
|
Some(as_str(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod providers;
|
pub mod providers;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::ffi::CString;
|
use std::path::Path;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ use deltachat::message::{self, Message, MessageState};
|
|||||||
use deltachat::peerstate::*;
|
use deltachat::peerstate::*;
|
||||||
use deltachat::qr::*;
|
use deltachat::qr::*;
|
||||||
use deltachat::sql;
|
use deltachat::sql;
|
||||||
use deltachat::x::*;
|
|
||||||
use deltachat::Event;
|
use deltachat::Event;
|
||||||
|
use libc::free;
|
||||||
|
|
||||||
/// Reset database tables. This function is called from Core cmdline.
|
/// Reset database tables. This function is called from Core cmdline.
|
||||||
/// Argument is a bitmask, executing single or multiple actions in one call.
|
/// Argument is a bitmask, executing single or multiple actions in one call.
|
||||||
@@ -94,24 +94,20 @@ pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dc_poke_eml_file(context: &Context, filename: *const libc::c_char) -> libc::c_int {
|
fn dc_poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(), Error> {
|
||||||
/* mainly for testing, may be called by dc_import_spec() */
|
let data = dc_read_file(context, filename)?;
|
||||||
let mut success: libc::c_int = 0i32;
|
|
||||||
let mut data: *mut libc::c_char = ptr::null_mut();
|
|
||||||
let mut data_bytes = 0;
|
|
||||||
if !(dc_read_file(
|
|
||||||
context,
|
|
||||||
filename,
|
|
||||||
&mut data as *mut *mut libc::c_char as *mut *mut libc::c_void,
|
|
||||||
&mut data_bytes,
|
|
||||||
) == 0i32)
|
|
||||||
{
|
|
||||||
dc_receive_imf(context, data, data_bytes, "import", 0, 0);
|
|
||||||
success = 1;
|
|
||||||
}
|
|
||||||
free(data as *mut libc::c_void);
|
|
||||||
|
|
||||||
success
|
unsafe {
|
||||||
|
dc_receive_imf(
|
||||||
|
context,
|
||||||
|
data.as_ptr() as *const _,
|
||||||
|
data.len(),
|
||||||
|
"import",
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Import a file to the database.
|
/// Import a file to the database.
|
||||||
@@ -130,16 +126,16 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
|||||||
|
|
||||||
let ok_to_continue;
|
let ok_to_continue;
|
||||||
let mut success: libc::c_int = 0;
|
let mut success: libc::c_int = 0;
|
||||||
let real_spec: *mut libc::c_char;
|
let real_spec: String;
|
||||||
let mut suffix: *mut libc::c_char = ptr::null_mut();
|
let mut suffix: *mut libc::c_char = ptr::null_mut();
|
||||||
let mut read_cnt: libc::c_int = 0;
|
let mut read_cnt: libc::c_int = 0;
|
||||||
|
|
||||||
/* if `spec` is given, remember it for later usage; if it is not given, try to use the last one */
|
/* if `spec` is given, remember it for later usage; if it is not given, try to use the last one */
|
||||||
if !spec.is_null() {
|
if !spec.is_null() {
|
||||||
real_spec = dc_strdup(spec);
|
real_spec = to_string(spec);
|
||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.set_config(context, "import_spec", Some(as_str(real_spec)))
|
.set_config(context, "import_spec", Some(&real_spec))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ok_to_continue = true;
|
ok_to_continue = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -150,27 +146,24 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
|||||||
} else {
|
} else {
|
||||||
ok_to_continue = true;
|
ok_to_continue = true;
|
||||||
}
|
}
|
||||||
real_spec = rs.unwrap_or_default().strdup();
|
real_spec = rs.unwrap_or_default();
|
||||||
}
|
}
|
||||||
if ok_to_continue {
|
if ok_to_continue {
|
||||||
let ok_to_continue2;
|
let ok_to_continue2;
|
||||||
suffix = dc_get_filesuffix_lc(as_str(real_spec));
|
suffix = dc_get_filesuffix_lc(&real_spec);
|
||||||
if !suffix.is_null() && strcmp(suffix, b"eml\x00" as *const u8 as *const libc::c_char) == 0
|
if !suffix.is_null()
|
||||||
|
&& libc::strcmp(suffix, b"eml\x00" as *const u8 as *const libc::c_char) == 0
|
||||||
{
|
{
|
||||||
if 0 != dc_poke_eml_file(context, real_spec) {
|
if dc_poke_eml_file(context, &real_spec).is_ok() {
|
||||||
read_cnt += 1
|
read_cnt += 1
|
||||||
}
|
}
|
||||||
ok_to_continue2 = true;
|
ok_to_continue2 = true;
|
||||||
} else {
|
} else {
|
||||||
/* import a directory */
|
/* import a directory */
|
||||||
let dir_name = std::path::Path::new(as_str(real_spec));
|
let dir_name = std::path::Path::new(&real_spec);
|
||||||
let dir = std::fs::read_dir(dir_name);
|
let dir = std::fs::read_dir(dir_name);
|
||||||
if dir.is_err() {
|
if dir.is_err() {
|
||||||
error!(
|
error!(context, "Import: Cannot open directory \"{}\".", &real_spec,);
|
||||||
context,
|
|
||||||
"Import: Cannot open directory \"{}\".",
|
|
||||||
as_str(real_spec),
|
|
||||||
);
|
|
||||||
ok_to_continue2 = false;
|
ok_to_continue2 = false;
|
||||||
} else {
|
} else {
|
||||||
let dir = dir.unwrap();
|
let dir = dir.unwrap();
|
||||||
@@ -182,10 +175,9 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
|||||||
let name_f = entry.file_name();
|
let name_f = entry.file_name();
|
||||||
let name = name_f.to_string_lossy();
|
let name = name_f.to_string_lossy();
|
||||||
if name.ends_with(".eml") {
|
if name.ends_with(".eml") {
|
||||||
let path_plus_name = format!("{}/{}", as_str(real_spec), name);
|
let path_plus_name = format!("{}/{}", &real_spec, name);
|
||||||
info!(context, "Import: {}", path_plus_name);
|
info!(context, "Import: {}", path_plus_name);
|
||||||
let path_plus_name_c = CString::yolo(path_plus_name);
|
if dc_poke_eml_file(context, path_plus_name).is_ok() {
|
||||||
if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
|
|
||||||
read_cnt += 1
|
read_cnt += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,9 +188,7 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
|||||||
if ok_to_continue2 {
|
if ok_to_continue2 {
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
"Import: {} items read from \"{}\".",
|
"Import: {} items read from \"{}\".", read_cnt, &real_spec
|
||||||
read_cnt,
|
|
||||||
as_str(real_spec)
|
|
||||||
);
|
);
|
||||||
if read_cnt > 0 {
|
if read_cnt > 0 {
|
||||||
context.call_cb(Event::MsgsChanged {
|
context.call_cb(Event::MsgsChanged {
|
||||||
@@ -210,7 +200,6 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(real_spec as *mut libc::c_void);
|
|
||||||
free(suffix as *mut libc::c_void);
|
free(suffix as *mut libc::c_void);
|
||||||
success
|
success
|
||||||
}
|
}
|
||||||
@@ -1017,7 +1006,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
"fileinfo" => {
|
"fileinfo" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <file> missing.");
|
ensure!(!arg1.is_empty(), "Argument <file> missing.");
|
||||||
|
|
||||||
if let Some(buf) = dc_read_file_safe(context, &arg1) {
|
if let Ok(buf) = dc_read_file(context, &arg1) {
|
||||||
let (width, height) = dc_get_filemeta(&buf)?;
|
let (width, height) = dc_get_filemeta(&buf)?;
|
||||||
println!("width={}, height={}", width, height);
|
println!("width={}, height={}", width, height);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -23,11 +23,9 @@ use std::sync::{Arc, Mutex, RwLock};
|
|||||||
use deltachat::config;
|
use deltachat::config;
|
||||||
use deltachat::configure::*;
|
use deltachat::configure::*;
|
||||||
use deltachat::context::*;
|
use deltachat::context::*;
|
||||||
use deltachat::dc_tools::*;
|
|
||||||
use deltachat::job::*;
|
use deltachat::job::*;
|
||||||
use deltachat::oauth2::*;
|
use deltachat::oauth2::*;
|
||||||
use deltachat::securejoin::*;
|
use deltachat::securejoin::*;
|
||||||
use deltachat::x::*;
|
|
||||||
use deltachat::Event;
|
use deltachat::Event;
|
||||||
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
||||||
use rustyline::config::OutputStreamType;
|
use rustyline::config::OutputStreamType;
|
||||||
@@ -441,11 +439,6 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
|||||||
let mut args = line.splitn(2, ' ');
|
let mut args = line.splitn(2, ' ');
|
||||||
let arg0 = args.next().unwrap_or_default();
|
let arg0 = args.next().unwrap_or_default();
|
||||||
let arg1 = args.next().unwrap_or_default();
|
let arg1 = args.next().unwrap_or_default();
|
||||||
let arg1_c = if arg1.is_empty() {
|
|
||||||
std::ptr::null()
|
|
||||||
} else {
|
|
||||||
arg1.strdup()
|
|
||||||
};
|
|
||||||
|
|
||||||
match arg0 {
|
match arg0 {
|
||||||
"connect" => {
|
"connect" => {
|
||||||
@@ -521,8 +514,6 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
|||||||
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
free(arg1_c as *mut _);
|
|
||||||
|
|
||||||
Ok(ExitResult::Continue)
|
Ok(ExitResult::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use libc::free;
|
||||||
use quick_xml;
|
use quick_xml;
|
||||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||||
|
|
||||||
@@ -5,7 +6,6 @@ use crate::constants::*;
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
use crate::login_param::LoginParam;
|
use crate::login_param::LoginParam;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
use super::read_autoconf_file;
|
use super::read_autoconf_file;
|
||||||
/* ******************************************************************************
|
/* ******************************************************************************
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
use libc::free;
|
||||||
use quick_xml;
|
use quick_xml;
|
||||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||||
|
|
||||||
@@ -5,8 +8,6 @@ use crate::constants::*;
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
use crate::login_param::LoginParam;
|
use crate::login_param::LoginParam;
|
||||||
use crate::x::*;
|
|
||||||
use std::ptr;
|
|
||||||
|
|
||||||
use super::read_autoconf_file;
|
use super::read_autoconf_file;
|
||||||
/* ******************************************************************************
|
/* ******************************************************************************
|
||||||
@@ -46,7 +47,7 @@ pub unsafe fn outlk_autodiscover(
|
|||||||
ok_to_continue = true;
|
ok_to_continue = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
memset(
|
libc::memset(
|
||||||
&mut outlk_ad as *mut outlk_autodiscover_t as *mut libc::c_void,
|
&mut outlk_ad as *mut outlk_autodiscover_t as *mut libc::c_void,
|
||||||
0,
|
0,
|
||||||
::std::mem::size_of::<outlk_autodiscover_t>(),
|
::std::mem::size_of::<outlk_autodiscover_t>(),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::ffi::CString;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
use libc::{free, strcmp, strlen, strstr};
|
||||||
use mmime::mailmime_content::*;
|
use mmime::mailmime_content::*;
|
||||||
use mmime::mmapstring::*;
|
use mmime::mmapstring::*;
|
||||||
use mmime::other::*;
|
use mmime::other::*;
|
||||||
@@ -23,7 +24,6 @@ use crate::param::*;
|
|||||||
use crate::pgp::*;
|
use crate::pgp::*;
|
||||||
use crate::sql::{self, Sql};
|
use crate::sql::{self, Sql};
|
||||||
use crate::stock::StockMessage;
|
use crate::stock::StockMessage;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
// import/export and tools
|
// import/export and tools
|
||||||
// param1 is a directory where the keys are written to
|
// param1 is a directory where the keys are written to
|
||||||
@@ -276,7 +276,7 @@ pub unsafe fn dc_continue_key_transfer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(filename) = msg.get_file(context) {
|
if let Some(filename) = msg.get_file(context) {
|
||||||
if let Some(buf) = dc_read_file_safe(context, filename) {
|
if let Ok(buf) = dc_read_file(context, filename) {
|
||||||
norm_sc = dc_normalize_setup_code(context, setup_code);
|
norm_sc = dc_normalize_setup_code(context, setup_code);
|
||||||
if norm_sc.is_null() {
|
if norm_sc.is_null() {
|
||||||
warn!(context, "Cannot normalize Setup Code.",);
|
warn!(context, "Cannot normalize Setup Code.",);
|
||||||
@@ -767,8 +767,8 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool {
|
|||||||
} else {
|
} else {
|
||||||
info!(context, "EXPORTing filename={}", name);
|
info!(context, "EXPORTing filename={}", name);
|
||||||
let curr_pathNfilename = context.get_blobdir().join(entry.file_name());
|
let curr_pathNfilename = context.get_blobdir().join(entry.file_name());
|
||||||
if let Some(buf) =
|
if let Ok(buf) =
|
||||||
dc_read_file_safe(context, &curr_pathNfilename)
|
dc_read_file(context, &curr_pathNfilename)
|
||||||
{
|
{
|
||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
@@ -874,7 +874,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
|||||||
free(buf.cast());
|
free(buf.cast());
|
||||||
buf = ptr::null_mut();
|
buf = ptr::null_mut();
|
||||||
|
|
||||||
if let Some(buf_r) = dc_read_file_safe(context, &path_plus_name) {
|
if let Ok(buf_r) = dc_read_file(context, &path_plus_name) {
|
||||||
buf = buf_r.as_ptr() as *mut _;
|
buf = buf_r.as_ptr() as *mut _;
|
||||||
std::mem::forget(buf_r);
|
std::mem::forget(buf_r);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::path::Path;
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use chrono::TimeZone;
|
use chrono::TimeZone;
|
||||||
|
use libc::{free, strcmp, strlen};
|
||||||
use mmime::clist::*;
|
use mmime::clist::*;
|
||||||
use mmime::mailimf_types::*;
|
use mmime::mailimf_types::*;
|
||||||
use mmime::mailimf_types_helper::*;
|
use mmime::mailimf_types_helper::*;
|
||||||
@@ -25,7 +26,6 @@ use crate::location;
|
|||||||
use crate::message::{self, Message};
|
use crate::message::{self, Message};
|
||||||
use crate::param::*;
|
use crate::param::*;
|
||||||
use crate::stock::StockMessage;
|
use crate::stock::StockMessage;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum Loaded {
|
pub enum Loaded {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use std::ptr;
|
|||||||
|
|
||||||
use charset::Charset;
|
use charset::Charset;
|
||||||
use deltachat_derive::{FromSql, ToSql};
|
use deltachat_derive::{FromSql, ToSql};
|
||||||
|
use libc::{strcmp, strlen, strncmp};
|
||||||
use mmime::clist::*;
|
use mmime::clist::*;
|
||||||
use mmime::mailimf::*;
|
use mmime::mailimf::*;
|
||||||
use mmime::mailimf_types::*;
|
use mmime::mailimf_types::*;
|
||||||
@@ -25,7 +26,6 @@ use crate::error::Error;
|
|||||||
use crate::location;
|
use crate::location;
|
||||||
use crate::param::*;
|
use crate::param::*;
|
||||||
use crate::stock::StockMessage;
|
use crate::stock::StockMessage;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MimeParser<'a> {
|
pub struct MimeParser<'a> {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::ffi::CString;
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use itertools::join;
|
use itertools::join;
|
||||||
|
use libc::{free, strcmp, strlen};
|
||||||
use mmime::clist::*;
|
use mmime::clist::*;
|
||||||
use mmime::mailimf::*;
|
use mmime::mailimf::*;
|
||||||
use mmime::mailimf_types::*;
|
use mmime::mailimf_types::*;
|
||||||
@@ -28,7 +29,6 @@ use crate::peerstate::*;
|
|||||||
use crate::securejoin::handle_securejoin_handshake;
|
use crate::securejoin::handle_securejoin_handshake;
|
||||||
use crate::sql;
|
use crate::sql;
|
||||||
use crate::stock::StockMessage;
|
use crate::stock::StockMessage;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
enum CreateEvent {
|
enum CreateEvent {
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ use std::ffi::CString;
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use charset::Charset;
|
use charset::Charset;
|
||||||
|
use libc::{free, strlen};
|
||||||
use mmime::mailmime_decode::*;
|
use mmime::mailmime_decode::*;
|
||||||
use mmime::mmapstring::*;
|
use mmime::mmapstring::*;
|
||||||
use mmime::other::*;
|
use mmime::other::*;
|
||||||
use percent_encoding::{percent_decode, utf8_percent_encode, AsciiSet, CONTROLS};
|
use percent_encoding::{percent_decode, utf8_percent_encode, AsciiSet, CONTROLS};
|
||||||
|
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode non-ascii-strings as `=?UTF-8?Q?Bj=c3=b6rn_Petersen?=`.
|
* Encode non-ascii-strings as `=?UTF-8?Q?Bj=c3=b6rn_Petersen?=`.
|
||||||
@@ -336,6 +336,8 @@ unsafe fn print_hex(target: *mut libc::c_char, cur: *const libc::c_char) {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use libc::{strcmp, strncmp};
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
505
src/dc_tools.rs
505
src/dc_tools.rs
@@ -9,16 +9,15 @@ use std::time::SystemTime;
|
|||||||
use std::{fmt, fs, ptr};
|
use std::{fmt, fs, ptr};
|
||||||
|
|
||||||
use chrono::{Local, TimeZone};
|
use chrono::{Local, TimeZone};
|
||||||
use libc::uintptr_t;
|
use libc::{free, memcpy, strcpy, strlen, strstr, uintptr_t};
|
||||||
use mmime::clist::*;
|
use mmime::clist::*;
|
||||||
use mmime::mailimf_types::*;
|
use mmime::mailimf_types::*;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
|
pub(crate) fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
|
||||||
0 != v && 0 == v & (v - 1)
|
0 != v && 0 == v & (v - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +42,7 @@ pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
|||||||
ret = strdup(s);
|
ret = strdup(s);
|
||||||
assert!(!ret.is_null());
|
assert!(!ret.is_null());
|
||||||
} else {
|
} else {
|
||||||
ret = calloc(1, 1) as *mut libc::c_char;
|
ret = libc::calloc(1, 1) as *mut libc::c_char;
|
||||||
assert!(!ret.is_null());
|
assert!(!ret.is_null());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,21 +50,7 @@ pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Duplicates a string, returns null if given string is null
|
/// Duplicates a string, returns null if given string is null
|
||||||
///
|
pub(crate) unsafe fn dc_strdup_keep_null(s: *const libc::c_char) -> *mut libc::c_char {
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use deltachat::dc_tools::{dc_strdup_keep_null, to_string};
|
|
||||||
/// use std::ffi::{CStr};
|
|
||||||
///
|
|
||||||
/// unsafe {
|
|
||||||
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
|
||||||
/// let str_a_copy = dc_strdup_keep_null(str_a);
|
|
||||||
/// assert_eq!(to_string(str_a_copy), "foobar");
|
|
||||||
/// assert_ne!(str_a, str_a_copy);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub unsafe fn dc_strdup_keep_null(s: *const libc::c_char) -> *mut libc::c_char {
|
|
||||||
if !s.is_null() {
|
if !s.is_null() {
|
||||||
dc_strdup(s)
|
dc_strdup(s)
|
||||||
} else {
|
} else {
|
||||||
@@ -73,7 +58,7 @@ pub unsafe fn dc_strdup_keep_null(s: *const libc::c_char) -> *mut libc::c_char {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_atoi_null_is_0(s: *const libc::c_char) -> libc::c_int {
|
pub(crate) fn dc_atoi_null_is_0(s: *const libc::c_char) -> libc::c_int {
|
||||||
if !s.is_null() {
|
if !s.is_null() {
|
||||||
as_str(s).parse().unwrap_or_default()
|
as_str(s).parse().unwrap_or_default()
|
||||||
} else {
|
} else {
|
||||||
@@ -81,20 +66,6 @@ pub unsafe fn dc_atoi_null_is_0(s: *const libc::c_char) -> libc::c_int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_str_replace(
|
|
||||||
haystack: *mut *mut libc::c_char,
|
|
||||||
needle: *const libc::c_char,
|
|
||||||
replacement: *const libc::c_char,
|
|
||||||
) {
|
|
||||||
let haystack_s = to_string(*haystack);
|
|
||||||
let needle_s = to_string(needle);
|
|
||||||
let replacement_s = to_string(replacement);
|
|
||||||
|
|
||||||
free(*haystack as *mut libc::c_void);
|
|
||||||
|
|
||||||
*haystack = haystack_s.replace(&needle_s, &replacement_s).strdup();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn dc_ltrim(buf: *mut libc::c_char) {
|
unsafe fn dc_ltrim(buf: *mut libc::c_char) {
|
||||||
let mut len: libc::size_t;
|
let mut len: libc::size_t;
|
||||||
let mut cur: *const libc::c_uchar;
|
let mut cur: *const libc::c_uchar;
|
||||||
@@ -106,7 +77,7 @@ unsafe fn dc_ltrim(buf: *mut libc::c_char) {
|
|||||||
len = len.wrapping_sub(1)
|
len = len.wrapping_sub(1)
|
||||||
}
|
}
|
||||||
if buf as *const libc::c_uchar != cur {
|
if buf as *const libc::c_uchar != cur {
|
||||||
memmove(
|
libc::memmove(
|
||||||
buf as *mut libc::c_void,
|
buf as *mut libc::c_void,
|
||||||
cur as *const libc::c_void,
|
cur as *const libc::c_void,
|
||||||
len.wrapping_add(1),
|
len.wrapping_add(1),
|
||||||
@@ -137,28 +108,13 @@ unsafe fn dc_rtrim(buf: *mut libc::c_char) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_trim(buf: *mut libc::c_char) {
|
pub(crate) unsafe fn dc_trim(buf: *mut libc::c_char) {
|
||||||
dc_ltrim(buf);
|
dc_ltrim(buf);
|
||||||
dc_rtrim(buf);
|
dc_rtrim(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the result must be free()'d */
|
|
||||||
pub unsafe fn dc_null_terminate(
|
|
||||||
in_0: *const libc::c_char,
|
|
||||||
bytes: libc::c_int,
|
|
||||||
) -> *mut libc::c_char {
|
|
||||||
let out: *mut libc::c_char = malloc(bytes as usize + 1) as *mut libc::c_char;
|
|
||||||
assert!(!out.is_null());
|
|
||||||
if !in_0.is_null() && bytes > 0 {
|
|
||||||
strncpy(out, in_0, bytes as usize);
|
|
||||||
}
|
|
||||||
*out.offset(bytes as isize) = 0 as libc::c_char;
|
|
||||||
|
|
||||||
out
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove all \r characters from string */
|
/* remove all \r characters from string */
|
||||||
pub unsafe fn dc_remove_cr_chars(buf: *mut libc::c_char) {
|
pub(crate) unsafe fn dc_remove_cr_chars(buf: *mut libc::c_char) {
|
||||||
/* search for first `\r` */
|
/* search for first `\r` */
|
||||||
let mut p1: *const libc::c_char = buf;
|
let mut p1: *const libc::c_char = buf;
|
||||||
while 0 != *p1 {
|
while 0 != *p1 {
|
||||||
@@ -179,84 +135,9 @@ pub unsafe fn dc_remove_cr_chars(buf: *mut libc::c_char) {
|
|||||||
*p2 = 0 as libc::c_char;
|
*p2 = 0 as 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 mut OK_TO_CONTINUE = true;
|
|
||||||
if buf.is_null() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* force unsigned - otherwise the `> ' '` comparison will fail */
|
|
||||||
let mut p1: *mut libc::c_uchar = buf as *mut libc::c_uchar;
|
|
||||||
let p1len: libc::c_int = strlen(buf) as libc::c_int;
|
|
||||||
let mut c: libc::c_int;
|
|
||||||
let mut i: libc::c_int;
|
|
||||||
let ix: libc::c_int;
|
|
||||||
let mut n: libc::c_int;
|
|
||||||
let mut j: libc::c_int;
|
|
||||||
i = 0;
|
|
||||||
ix = p1len;
|
|
||||||
's_36: loop {
|
|
||||||
if !(i < ix) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
c = *p1.offset(i as isize) as libc::c_int;
|
|
||||||
if c > 0 && c <= 0x7f {
|
|
||||||
n = 0
|
|
||||||
} else if c & 0xe0 == 0xc0 {
|
|
||||||
n = 1
|
|
||||||
} else if c == 0xed
|
|
||||||
&& i < ix - 1
|
|
||||||
&& *p1.offset((i + 1) as isize) as libc::c_int & 0xa0 == 0xa0
|
|
||||||
{
|
|
||||||
/* U+d800 to U+dfff */
|
|
||||||
OK_TO_CONTINUE = false;
|
|
||||||
break;
|
|
||||||
} else if c & 0xf0 == 0xe0 {
|
|
||||||
n = 2
|
|
||||||
} else if c & 0xf8 == 0xf0 {
|
|
||||||
n = 3
|
|
||||||
} 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 */
|
|
||||||
OK_TO_CONTINUE = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
j = 0;
|
|
||||||
while j < n && i < ix {
|
|
||||||
/* n bytes matching 10bbbbbb follow ? */
|
|
||||||
i += 1;
|
|
||||||
if i == ix || *p1.offset(i as isize) as libc::c_int & 0xc0 != 0x80 {
|
|
||||||
OK_TO_CONTINUE = false;
|
|
||||||
break 's_36;
|
|
||||||
}
|
|
||||||
j += 1
|
|
||||||
}
|
|
||||||
i += 1
|
|
||||||
}
|
|
||||||
if OK_TO_CONTINUE == false {
|
|
||||||
while 0 != *p1 {
|
|
||||||
if *p1 as libc::c_int > 0x7f {
|
|
||||||
*p1 = '_' as i32 as libc::c_uchar
|
|
||||||
}
|
|
||||||
p1 = p1.offset(1isize)
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shortens a string to a specified length and adds "..." or "[...]" to the end of
|
/// Shortens a string to a specified length and adds "..." or "[...]" to the end of
|
||||||
/// the shortened string.
|
/// the shortened string.
|
||||||
///
|
pub(crate) fn dc_truncate(buf: &str, approx_chars: usize, do_unwrap: bool) -> Cow<str> {
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// use deltachat::dc_tools::dc_truncate;
|
|
||||||
///
|
|
||||||
/// let s = "this is a little test string";
|
|
||||||
/// assert_eq!(dc_truncate(s, 16, false), "this is a [...]");
|
|
||||||
/// assert_eq!(dc_truncate(s, 16, true), "this is a ...");
|
|
||||||
/// ```
|
|
||||||
pub fn dc_truncate(buf: &str, approx_chars: usize, do_unwrap: bool) -> Cow<str> {
|
|
||||||
let ellipse = if do_unwrap { "..." } else { "[...]" };
|
let ellipse = if do_unwrap { "..." } else { "[...]" };
|
||||||
|
|
||||||
let count = buf.chars().count();
|
let count = buf.chars().count();
|
||||||
@@ -278,7 +159,7 @@ pub fn dc_truncate(buf: &str, approx_chars: usize, do_unwrap: bool) -> Cow<str>
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub unsafe fn dc_truncate_n_unwrap_str(
|
pub(crate) unsafe fn dc_truncate_n_unwrap_str(
|
||||||
buf: *mut libc::c_char,
|
buf: *mut libc::c_char,
|
||||||
approx_characters: libc::c_int,
|
approx_characters: libc::c_int,
|
||||||
do_unwrap: libc::c_int,
|
do_unwrap: libc::c_int,
|
||||||
@@ -337,7 +218,7 @@ unsafe fn dc_utf8_strnlen(s: *const libc::c_char, n: libc::size_t) -> libc::size
|
|||||||
j
|
j
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_str_from_clist(
|
pub(crate) unsafe fn dc_str_from_clist(
|
||||||
list: *const clist,
|
list: *const clist,
|
||||||
delimiter: *const libc::c_char,
|
delimiter: *const libc::c_char,
|
||||||
) -> *mut libc::c_char {
|
) -> *mut libc::c_char {
|
||||||
@@ -369,7 +250,7 @@ pub unsafe fn dc_str_from_clist(
|
|||||||
res.strdup()
|
res.strdup()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_str_to_clist(
|
pub(crate) unsafe fn dc_str_to_clist(
|
||||||
str: *const libc::c_char,
|
str: *const libc::c_char,
|
||||||
delimiter: *const libc::c_char,
|
delimiter: *const libc::c_char,
|
||||||
) -> *mut clist {
|
) -> *mut clist {
|
||||||
@@ -408,7 +289,7 @@ const COLORS: [u32; 16] = [
|
|||||||
0x39b249, 0xbb243b, 0x964078, 0x66874f, 0x308ab9, 0x127ed0, 0xbe450c,
|
0x39b249, 0xbb243b, 0x964078, 0x66874f, 0x308ab9, 0x127ed0, 0xbe450c,
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn dc_str_to_color(s: impl AsRef<str>) -> u32 {
|
pub(crate) fn dc_str_to_color(s: impl AsRef<str>) -> u32 {
|
||||||
let str_lower = s.as_ref().to_lowercase();
|
let str_lower = s.as_ref().to_lowercase();
|
||||||
let mut checksum = 0;
|
let mut checksum = 0;
|
||||||
let bytes = str_lower.as_bytes();
|
let bytes = str_lower.as_bytes();
|
||||||
@@ -422,8 +303,9 @@ pub fn dc_str_to_color(s: impl AsRef<str>) -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* clist tools */
|
/* clist tools */
|
||||||
|
|
||||||
/* calls free() for each item content */
|
/* calls free() for each item content */
|
||||||
pub unsafe fn clist_free_content(haystack: *const clist) {
|
pub(crate) unsafe fn clist_free_content(haystack: *const clist) {
|
||||||
let mut iter = (*haystack).first;
|
let mut iter = (*haystack).first;
|
||||||
|
|
||||||
while !iter.is_null() {
|
while !iter.is_null() {
|
||||||
@@ -437,7 +319,7 @@ pub unsafe fn clist_free_content(haystack: *const clist) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn clist_search_string_nocase(
|
pub(crate) unsafe fn clist_search_string_nocase(
|
||||||
haystack: *const clist,
|
haystack: *const clist,
|
||||||
needle: *const libc::c_char,
|
needle: *const libc::c_char,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
@@ -448,7 +330,7 @@ pub unsafe fn clist_search_string_nocase(
|
|||||||
|
|
||||||
/* date/time tools */
|
/* date/time tools */
|
||||||
/* the result is UTC or DC_INVALID_TIMESTAMP */
|
/* the result is UTC or DC_INVALID_TIMESTAMP */
|
||||||
pub unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
|
pub(crate) unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
|
||||||
let sec = (*date_time).dt_sec;
|
let sec = (*date_time).dt_sec;
|
||||||
let min = (*date_time).dt_min;
|
let min = (*date_time).dt_min;
|
||||||
let hour = (*date_time).dt_hour;
|
let hour = (*date_time).dt_hour;
|
||||||
@@ -482,13 +364,13 @@ pub fn dc_timestamp_to_str(wanted: i64) -> String {
|
|||||||
ts.format("%Y.%m.%d %H:%M:%S").to_string()
|
ts.format("%Y.%m.%d %H:%M:%S").to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_gm2local_offset() -> i64 {
|
pub(crate) fn dc_gm2local_offset() -> i64 {
|
||||||
let lt = Local::now();
|
let lt = Local::now();
|
||||||
((lt.offset().local_minus_utc() / (60 * 60)) * 100) as i64
|
((lt.offset().local_minus_utc() / (60 * 60)) * 100) as i64
|
||||||
}
|
}
|
||||||
|
|
||||||
/* timesmearing */
|
/* timesmearing */
|
||||||
pub fn dc_smeared_time(context: &Context) -> i64 {
|
pub(crate) fn dc_smeared_time(context: &Context) -> i64 {
|
||||||
/* function returns a corrected time(NULL) */
|
/* function returns a corrected time(NULL) */
|
||||||
let mut now = time();
|
let mut now = time();
|
||||||
let ts = *context.last_smeared_timestamp.clone().read().unwrap();
|
let ts = *context.last_smeared_timestamp.clone().read().unwrap();
|
||||||
@@ -499,7 +381,7 @@ pub fn dc_smeared_time(context: &Context) -> i64 {
|
|||||||
now
|
now
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_create_smeared_timestamp(context: &Context) -> i64 {
|
pub(crate) fn dc_create_smeared_timestamp(context: &Context) -> i64 {
|
||||||
let now = time();
|
let now = time();
|
||||||
let mut ret = now;
|
let mut ret = now;
|
||||||
|
|
||||||
@@ -514,7 +396,7 @@ pub fn dc_create_smeared_timestamp(context: &Context) -> i64 {
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_create_smeared_timestamps(context: &Context, count: usize) -> i64 {
|
pub(crate) fn dc_create_smeared_timestamps(context: &Context, count: usize) -> i64 {
|
||||||
/* get a range to timestamps that can be used uniquely */
|
/* get a range to timestamps that can be used uniquely */
|
||||||
let now = time();
|
let now = time();
|
||||||
let start = now + (if count < 5 { count } else { 5 }) as i64 - count as i64;
|
let start = now + (if count < 5 { count } else { 5 }) as i64 - count as i64;
|
||||||
@@ -528,7 +410,7 @@ pub fn dc_create_smeared_timestamps(context: &Context, count: usize) -> i64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Message-ID tools */
|
/* Message-ID tools */
|
||||||
pub fn dc_create_id() -> String {
|
pub(crate) fn dc_create_id() -> String {
|
||||||
/* generate an id. the generated ID should be as short and as unique as possible:
|
/* generate an id. the generated ID should be as short and as unique as possible:
|
||||||
- short, because it may also used as part of Message-ID headers or in QR codes
|
- short, because it may also used as part of Message-ID headers or in QR codes
|
||||||
- unique as two IDs generated on two devices should not be the same. However, collisions are not world-wide but only by the few contacts.
|
- unique as two IDs generated on two devices should not be the same. However, collisions are not world-wide but only by the few contacts.
|
||||||
@@ -568,7 +450,7 @@ fn encode_66bits_as_base64(v1: u32, v2: u32, fill: u32) -> String {
|
|||||||
String::from_utf8(wrapped_writer).unwrap()
|
String::from_utf8(wrapped_writer).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_create_incoming_rfc724_mid(
|
pub(crate) fn dc_create_incoming_rfc724_mid(
|
||||||
message_timestamp: i64,
|
message_timestamp: i64,
|
||||||
contact_id_from: u32,
|
contact_id_from: u32,
|
||||||
contact_ids_to: &Vec<u32>,
|
contact_ids_to: &Vec<u32>,
|
||||||
@@ -590,7 +472,7 @@ pub fn dc_create_incoming_rfc724_mid(
|
|||||||
/// - this function is called for all outgoing messages.
|
/// - this function is called for all outgoing messages.
|
||||||
/// - the message ID should be globally unique
|
/// - the message ID should be globally unique
|
||||||
/// - do not add a counter or any private data as this leaks information unncessarily
|
/// - do not add a counter or any private data as this leaks information unncessarily
|
||||||
pub fn dc_create_outgoing_rfc724_mid(grpid: Option<&str>, from_addr: &str) -> String {
|
pub(crate) fn dc_create_outgoing_rfc724_mid(grpid: Option<&str>, from_addr: &str) -> String {
|
||||||
let hostname = from_addr
|
let hostname = from_addr
|
||||||
.find('@')
|
.find('@')
|
||||||
.map(|k| &from_addr[k..])
|
.map(|k| &from_addr[k..])
|
||||||
@@ -606,16 +488,7 @@ pub fn dc_create_outgoing_rfc724_mid(grpid: Option<&str>, from_addr: &str) -> St
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `mid` - A string that holds the message id
|
/// * `mid` - A string that holds the message id
|
||||||
///
|
pub(crate) fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> {
|
||||||
/// # 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.") {
|
if mid.len() < 9 || !mid.starts_with("Gr.") {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -632,7 +505,9 @@ pub fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut libc::c_char {
|
pub(crate) unsafe fn dc_extract_grpid_from_rfc724_mid_list(
|
||||||
|
list: *const clist,
|
||||||
|
) -> *mut libc::c_char {
|
||||||
if !list.is_null() {
|
if !list.is_null() {
|
||||||
let mut cur: *mut clistiter = (*list).first;
|
let mut cur: *mut clistiter = (*list).first;
|
||||||
while !cur.is_null() {
|
while !cur.is_null() {
|
||||||
@@ -656,7 +531,7 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut
|
|||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_ensure_no_slash_safe(path: &str) -> &str {
|
pub(crate) fn dc_ensure_no_slash_safe(path: &str) -> &str {
|
||||||
if path.ends_with('/') || path.ends_with('\\') {
|
if path.ends_with('/') || path.ends_with('\\') {
|
||||||
return &path[..path.len() - 1];
|
return &path[..path.len() - 1];
|
||||||
}
|
}
|
||||||
@@ -671,14 +546,6 @@ fn validate_filename(filename: &str) -> String {
|
|||||||
.replace(':', "-")
|
.replace(':', "-")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_get_filename(path_filename: impl AsRef<str>) -> *mut libc::c_char {
|
|
||||||
if let Some(p) = Path::new(path_filename.as_ref()).file_name() {
|
|
||||||
p.to_string_lossy().strdup()
|
|
||||||
} else {
|
|
||||||
ptr::null_mut()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// the returned suffix is lower-case
|
// the returned suffix is lower-case
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub unsafe fn dc_get_filesuffix_lc(path_filename: impl AsRef<str>) -> *mut libc::c_char {
|
pub unsafe fn dc_get_filesuffix_lc(path_filename: impl AsRef<str>) -> *mut libc::c_char {
|
||||||
@@ -700,7 +567,7 @@ pub fn dc_get_filemeta(buf: &[u8]) -> Result<(u32, u32), Error> {
|
|||||||
///
|
///
|
||||||
/// If `path` starts with "$BLOBDIR", replaces it with the blobdir path.
|
/// If `path` starts with "$BLOBDIR", replaces it with the blobdir path.
|
||||||
/// Otherwise, returns path as is.
|
/// Otherwise, returns path as is.
|
||||||
pub fn dc_get_abs_path<P: AsRef<std::path::Path>>(
|
pub(crate) fn dc_get_abs_path<P: AsRef<std::path::Path>>(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
path: P,
|
path: P,
|
||||||
) -> std::path::PathBuf {
|
) -> std::path::PathBuf {
|
||||||
@@ -712,11 +579,11 @@ pub fn dc_get_abs_path<P: AsRef<std::path::Path>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_file_exist(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
pub(crate) fn dc_file_exist(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
||||||
dc_get_abs_path(context, &path).exists()
|
dc_get_abs_path(context, &path).exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_get_filebytes(context: &Context, path: impl AsRef<std::path::Path>) -> u64 {
|
pub(crate) fn dc_get_filebytes(context: &Context, path: impl AsRef<std::path::Path>) -> u64 {
|
||||||
let path_abs = dc_get_abs_path(context, &path);
|
let path_abs = dc_get_abs_path(context, &path);
|
||||||
match fs::metadata(&path_abs) {
|
match fs::metadata(&path_abs) {
|
||||||
Ok(meta) => meta.len() as u64,
|
Ok(meta) => meta.len() as u64,
|
||||||
@@ -724,7 +591,7 @@ pub fn dc_get_filebytes(context: &Context, path: impl AsRef<std::path::Path>) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
pub(crate) fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
||||||
let path_abs = dc_get_abs_path(context, &path);
|
let path_abs = dc_get_abs_path(context, &path);
|
||||||
if !path_abs.is_file() {
|
if !path_abs.is_file() {
|
||||||
warn!(
|
warn!(
|
||||||
@@ -744,7 +611,7 @@ pub fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path>) -> b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_copy_file(
|
pub(crate) fn dc_copy_file(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
src: impl AsRef<std::path::Path>,
|
src: impl AsRef<std::path::Path>,
|
||||||
dest: impl AsRef<std::path::Path>,
|
dest: impl AsRef<std::path::Path>,
|
||||||
@@ -765,7 +632,7 @@ pub fn dc_copy_file(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
pub(crate) fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
||||||
let path_abs = dc_get_abs_path(context, &path);
|
let path_abs = dc_get_abs_path(context, &path);
|
||||||
if !path_abs.exists() {
|
if !path_abs.exists() {
|
||||||
match fs::create_dir_all(path_abs) {
|
match fs::create_dir_all(path_abs) {
|
||||||
@@ -785,7 +652,7 @@ pub fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Path>) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write a the given content to provied file path.
|
/// Write a the given content to provied file path.
|
||||||
pub fn dc_write_file(context: &Context, path: impl AsRef<Path>, buf: &[u8]) -> bool {
|
pub(crate) fn dc_write_file(context: &Context, path: impl AsRef<Path>, buf: &[u8]) -> bool {
|
||||||
let path_abs = dc_get_abs_path(context, &path);
|
let path_abs = dc_get_abs_path(context, &path);
|
||||||
if let Err(_err) = fs::write(&path_abs, buf) {
|
if let Err(_err) = fs::write(&path_abs, buf) {
|
||||||
warn!(
|
warn!(
|
||||||
@@ -800,42 +667,26 @@ pub fn dc_write_file(context: &Context, path: impl AsRef<Path>, buf: &[u8]) -> b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
pub fn dc_read_file<P: AsRef<std::path::Path>>(
|
||||||
pub unsafe fn dc_read_file(
|
|
||||||
context: &Context,
|
context: &Context,
|
||||||
pathNfilename: *const libc::c_char,
|
path: P,
|
||||||
buf: *mut *mut libc::c_void,
|
) -> Result<Vec<u8>, Error> {
|
||||||
buf_bytes: *mut libc::size_t,
|
|
||||||
) -> libc::c_int {
|
|
||||||
if pathNfilename.is_null() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if let Some(mut bytes) = dc_read_file_safe(context, as_str(pathNfilename)) {
|
|
||||||
*buf = &mut bytes[..] as *mut _ as *mut libc::c_void;
|
|
||||||
*buf_bytes = bytes.len();
|
|
||||||
std::mem::forget(bytes);
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(context, &path);
|
let path_abs = dc_get_abs_path(context, &path);
|
||||||
|
|
||||||
match fs::read(&path_abs) {
|
match fs::read(&path_abs) {
|
||||||
Ok(bytes) => Some(bytes),
|
Ok(bytes) => Ok(bytes),
|
||||||
Err(_err) => {
|
Err(err) => {
|
||||||
warn!(
|
warn!(
|
||||||
context,
|
context,
|
||||||
"Cannot read \"{}\" or file is empty.",
|
"Cannot read \"{}\" or file is empty.",
|
||||||
path.as_ref().display()
|
path.as_ref().display()
|
||||||
);
|
);
|
||||||
None
|
Err(err.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_get_fine_path_filename(
|
pub(crate) fn dc_get_fine_path_filename(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
folder: impl AsRef<Path>,
|
folder: impl AsRef<Path>,
|
||||||
desired_filename_suffix: impl AsRef<str>,
|
desired_filename_suffix: impl AsRef<str>,
|
||||||
@@ -880,7 +731,7 @@ pub fn dc_get_fine_path_filename(
|
|||||||
panic!("Something is really wrong, you need to clean up your disk");
|
panic!("Something is really wrong, you need to clean up your disk");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_is_blobdir_path(context: &Context, path: impl AsRef<str>) -> bool {
|
pub(crate) fn dc_is_blobdir_path(context: &Context, path: impl AsRef<str>) -> bool {
|
||||||
context
|
context
|
||||||
.get_blobdir()
|
.get_blobdir()
|
||||||
.to_str()
|
.to_str()
|
||||||
@@ -900,7 +751,7 @@ fn dc_make_rel_path(context: &Context, path: &mut String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_make_rel_and_copy(context: &Context, path: &mut String) -> bool {
|
pub(crate) fn dc_make_rel_and_copy(context: &Context, path: &mut String) -> bool {
|
||||||
if dc_is_blobdir_path(context, &path) {
|
if dc_is_blobdir_path(context, &path) {
|
||||||
dc_make_rel_path(context, path);
|
dc_make_rel_path(context, path);
|
||||||
return true;
|
return true;
|
||||||
@@ -1148,7 +999,7 @@ fn as_path_unicode<'a>(s: *const libc::c_char) -> &'a std::path::Path {
|
|||||||
std::path::Path::new(as_str(s))
|
std::path::Path::new(as_str(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn time() -> i64 {
|
pub(crate) fn time() -> i64 {
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -1220,36 +1071,64 @@ impl FromStr for EmailAddress {
|
|||||||
|
|
||||||
/// Utility to check if a in the binary represantion of listflags
|
/// Utility to check if a in the binary represantion of listflags
|
||||||
/// the bit at position bitindex is 1.
|
/// the bit at position bitindex is 1.
|
||||||
///
|
pub(crate) fn listflags_has(listflags: u32, bitindex: usize) -> bool {
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::convert::TryInto;
|
|
||||||
/// use deltachat::dc_tools::listflags_has;
|
|
||||||
/// use deltachat::constants::{DC_GCL_ADD_SELF, DC_GCL_VERIFIED_ONLY};
|
|
||||||
/// let listflags: u32 = 0x1101;
|
|
||||||
/// assert!(listflags_has(listflags, 0x1) == true);
|
|
||||||
/// assert!(listflags_has(listflags, 0x10) == false);
|
|
||||||
/// assert!(listflags_has(listflags, 0x100) == true);
|
|
||||||
/// assert!(listflags_has(listflags, 0x1000) == true);
|
|
||||||
/// let listflags: u32 = (DC_GCL_ADD_SELF | DC_GCL_VERIFIED_ONLY).try_into().unwrap();
|
|
||||||
/// assert!(listflags_has(listflags, DC_GCL_VERIFIED_ONLY) == true);
|
|
||||||
/// assert!(listflags_has(listflags, DC_GCL_ADD_SELF) == true);
|
|
||||||
/// let listflags: u32 = DC_GCL_VERIFIED_ONLY.try_into().unwrap();
|
|
||||||
/// assert!(listflags_has(listflags, DC_GCL_ADD_SELF) == false);
|
|
||||||
/// ```
|
|
||||||
pub fn listflags_has(listflags: u32, bitindex: usize) -> bool {
|
|
||||||
let listflags = listflags as usize;
|
let listflags = listflags as usize;
|
||||||
(listflags & bitindex) == bitindex
|
(listflags & bitindex) == bitindex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||||
|
if s.is_null() {
|
||||||
|
return std::ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let slen = strlen(s);
|
||||||
|
let result = libc::malloc(slen + 1);
|
||||||
|
if result.is_null() {
|
||||||
|
return std::ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(result, s as *const _, slen + 1);
|
||||||
|
result as *mut _
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn strndup(s: *const libc::c_char, n: libc::c_ulong) -> *mut libc::c_char {
|
||||||
|
if s.is_null() {
|
||||||
|
return std::ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let end = std::cmp::min(n as usize, unsafe { strlen(s) });
|
||||||
|
unsafe {
|
||||||
|
let result = libc::malloc(end + 1);
|
||||||
|
memcpy(result, s as *const _, end);
|
||||||
|
std::ptr::write_bytes(result.offset(end as isize), b'\x00', 1);
|
||||||
|
|
||||||
|
result as *mut _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn strcasecmp(s1: *const libc::c_char, s2: *const libc::c_char) -> libc::c_int {
|
||||||
|
let s1 = std::ffi::CStr::from_ptr(s1)
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_lowercase();
|
||||||
|
let s2 = std::ffi::CStr::from_ptr(s2)
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_lowercase();
|
||||||
|
if s1 == s2 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use libc::strcmp;
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
|
use crate::constants::*;
|
||||||
use crate::test_utils::*;
|
use crate::test_utils::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1348,23 +1227,6 @@ mod tests {
|
|||||||
assert_eq!("1.22", format!("{}", 1.22));
|
assert_eq!("1.22", format!("{}", 1.22));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dc_str_replace() {
|
|
||||||
unsafe {
|
|
||||||
let mut str: *mut libc::c_char = strdup(b"aaa\x00" as *const u8 as *const libc::c_char);
|
|
||||||
dc_str_replace(
|
|
||||||
&mut str,
|
|
||||||
b"a\x00" as *const u8 as *const libc::c_char,
|
|
||||||
b"ab\x00" as *const u8 as *const libc::c_char,
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
|
||||||
"ababab"
|
|
||||||
);
|
|
||||||
free(str as *mut libc::c_void);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dc_truncate_1() {
|
fn test_dc_truncate_1() {
|
||||||
let s = "this is a little test string";
|
let s = "this is a little test string";
|
||||||
@@ -1420,45 +1282,6 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dc_null_terminate_1() {
|
|
||||||
unsafe {
|
|
||||||
let str: *mut libc::c_char =
|
|
||||||
dc_null_terminate(b"abcxyz\x00" as *const u8 as *const libc::c_char, 3);
|
|
||||||
assert_eq!(
|
|
||||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
|
||||||
"abc"
|
|
||||||
);
|
|
||||||
free(str as *mut libc::c_void);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dc_null_terminate_2() {
|
|
||||||
unsafe {
|
|
||||||
let str: *mut libc::c_char =
|
|
||||||
dc_null_terminate(b"abcxyz\x00" as *const u8 as *const libc::c_char, 0);
|
|
||||||
assert_eq!(
|
|
||||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
|
||||||
""
|
|
||||||
);
|
|
||||||
free(str as *mut libc::c_void);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dc_null_terminate_3() {
|
|
||||||
unsafe {
|
|
||||||
let str: *mut libc::c_char =
|
|
||||||
dc_null_terminate(0 as *const u8 as *const libc::c_char, 0);
|
|
||||||
assert_eq!(
|
|
||||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
|
||||||
""
|
|
||||||
);
|
|
||||||
free(str as *mut libc::c_void);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dc_str_to_clist_1() {
|
fn test_dc_str_to_clist_1() {
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -1517,63 +1340,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dc_replace_bad_utf8_chars_1() {
|
|
||||||
unsafe {
|
|
||||||
let buf1 = strdup(b"ol\xc3\xa1 mundo <>\"\'& \xc3\xa4\xc3\x84\xc3\xb6\xc3\x96\xc3\xbc\xc3\x9c\xc3\x9f foo\xc3\x86\xc3\xa7\xc3\x87 \xe2\x99\xa6&noent;\x00" as *const u8 as *const libc::c_char);
|
|
||||||
let buf2 = strdup(buf1);
|
|
||||||
|
|
||||||
dc_replace_bad_utf8_chars(buf2);
|
|
||||||
|
|
||||||
assert_eq!(strcmp(buf1, buf2), 0);
|
|
||||||
|
|
||||||
free(buf1 as *mut libc::c_void);
|
|
||||||
free(buf2 as *mut libc::c_void);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dc_replace_bad_utf8_chars_2() {
|
|
||||||
unsafe {
|
|
||||||
let buf1 = strdup(b"ISO-String with Ae: \xc4\x00" as *const u8 as *const libc::c_char);
|
|
||||||
let buf2 = strdup(buf1);
|
|
||||||
|
|
||||||
dc_replace_bad_utf8_chars(buf2);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
CStr::from_ptr(buf2 as *const libc::c_char)
|
|
||||||
.to_str()
|
|
||||||
.unwrap(),
|
|
||||||
"ISO-String with Ae: _"
|
|
||||||
);
|
|
||||||
|
|
||||||
free(buf1 as *mut libc::c_void);
|
|
||||||
free(buf2 as *mut libc::c_void);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dc_replace_bad_utf8_chars_3() {
|
|
||||||
unsafe {
|
|
||||||
let buf1 = strdup(b"\x00" as *const u8 as *const libc::c_char);
|
|
||||||
let buf2 = strdup(buf1);
|
|
||||||
|
|
||||||
dc_replace_bad_utf8_chars(buf2);
|
|
||||||
|
|
||||||
assert_eq!(*buf2.offset(0), 0);
|
|
||||||
|
|
||||||
free(buf1 as *mut libc::c_void);
|
|
||||||
free(buf2 as *mut libc::c_void);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dc_replace_bad_utf8_chars_4() {
|
|
||||||
unsafe {
|
|
||||||
dc_replace_bad_utf8_chars(ptr::null_mut());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dc_create_id() {
|
fn test_dc_create_id() {
|
||||||
let buf = dc_create_id();
|
let buf = dc_create_id();
|
||||||
@@ -1809,4 +1575,85 @@ mod tests {
|
|||||||
dc_make_rel_path(&t.ctx, &mut foo);
|
dc_make_rel_path(&t.ctx, &mut foo);
|
||||||
assert_eq!(foo, format!("$BLOBDIR{}foo", std::path::MAIN_SEPARATOR));
|
assert_eq!(foo, format!("$BLOBDIR{}foo", std::path::MAIN_SEPARATOR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strndup() {
|
||||||
|
unsafe {
|
||||||
|
let res = strndup(b"helloworld\x00" as *const u8 as *const libc::c_char, 4);
|
||||||
|
assert_eq!(
|
||||||
|
to_string(res),
|
||||||
|
to_string(b"hell\x00" as *const u8 as *const libc::c_char)
|
||||||
|
);
|
||||||
|
assert_eq!(strlen(res), 4);
|
||||||
|
free(res as *mut _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_file_handling() {
|
||||||
|
let t = dummy_context();
|
||||||
|
let context = &t.ctx;
|
||||||
|
|
||||||
|
if dc_file_exist(context, "$BLOBDIR/foobar")
|
||||||
|
|| dc_file_exist(context, "$BLOBDIR/dada")
|
||||||
|
|| dc_file_exist(context, "$BLOBDIR/foobar.dadada")
|
||||||
|
|| dc_file_exist(context, "$BLOBDIR/foobar-folder")
|
||||||
|
{
|
||||||
|
dc_delete_file(context, "$BLOBDIR/foobar");
|
||||||
|
dc_delete_file(context, "$BLOBDIR/dada");
|
||||||
|
dc_delete_file(context, "$BLOBDIR/foobar.dadada");
|
||||||
|
dc_delete_file(context, "$BLOBDIR/foobar-folder");
|
||||||
|
}
|
||||||
|
assert!(dc_write_file(context, "$BLOBDIR/foobar", b"content"));
|
||||||
|
assert!(dc_file_exist(context, "$BLOBDIR/foobar",));
|
||||||
|
assert!(!dc_file_exist(context, "$BLOBDIR/foobarx"));
|
||||||
|
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/foobar"), 7);
|
||||||
|
|
||||||
|
let abs_path = context
|
||||||
|
.get_blobdir()
|
||||||
|
.join("foobar")
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
assert!(dc_is_blobdir_path(context, &abs_path));
|
||||||
|
assert!(dc_is_blobdir_path(context, "$BLOBDIR/fofo",));
|
||||||
|
assert!(!dc_is_blobdir_path(context, "/BLOBDIR/fofo",));
|
||||||
|
assert!(dc_file_exist(context, &abs_path));
|
||||||
|
|
||||||
|
assert!(dc_copy_file(context, "$BLOBDIR/foobar", "$BLOBDIR/dada",));
|
||||||
|
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/dada",), 7);
|
||||||
|
|
||||||
|
let buf = dc_read_file(context, "$BLOBDIR/dada").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(buf.len(), 7);
|
||||||
|
assert_eq!(&buf, b"content");
|
||||||
|
|
||||||
|
assert!(dc_delete_file(context, "$BLOBDIR/foobar"));
|
||||||
|
assert!(dc_delete_file(context, "$BLOBDIR/dada"));
|
||||||
|
assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder"));
|
||||||
|
assert!(dc_file_exist(context, "$BLOBDIR/foobar-folder",));
|
||||||
|
assert!(!dc_delete_file(context, "$BLOBDIR/foobar-folder"));
|
||||||
|
let fn0 = dc_get_fine_path_filename(context, "$BLOBDIR", "foobar.dadada");
|
||||||
|
assert_eq!(fn0, PathBuf::from("$BLOBDIR/foobar.dadada"));
|
||||||
|
|
||||||
|
assert!(dc_write_file(context, &fn0, b"content"));
|
||||||
|
let fn1 = dc_get_fine_path_filename(context, "$BLOBDIR", "foobar.dadada");
|
||||||
|
assert_eq!(fn1, PathBuf::from("$BLOBDIR/foobar-1.dadada"));
|
||||||
|
|
||||||
|
assert!(dc_delete_file(context, &fn0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_listflags_has() {
|
||||||
|
let listflags: u32 = 0x1101;
|
||||||
|
assert!(listflags_has(listflags, 0x1) == true);
|
||||||
|
assert!(listflags_has(listflags, 0x10) == false);
|
||||||
|
assert!(listflags_has(listflags, 0x100) == true);
|
||||||
|
assert!(listflags_has(listflags, 0x1000) == true);
|
||||||
|
let listflags: u32 = (DC_GCL_ADD_SELF | DC_GCL_VERIFIED_ONLY).try_into().unwrap();
|
||||||
|
assert!(listflags_has(listflags, DC_GCL_VERIFIED_ONLY) == true);
|
||||||
|
assert!(listflags_has(listflags, DC_GCL_ADD_SELF) == true);
|
||||||
|
let listflags: u32 = DC_GCL_VERIFIED_ONLY.try_into().unwrap();
|
||||||
|
assert!(listflags_has(listflags, DC_GCL_ADD_SELF) == false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use std::ffi::CStr;
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use libc::{free, strcmp, strlen, strncmp};
|
||||||
use mmime::clist::*;
|
use mmime::clist::*;
|
||||||
use mmime::mailimf::*;
|
use mmime::mailimf::*;
|
||||||
use mmime::mailimf_types::*;
|
use mmime::mailimf_types::*;
|
||||||
@@ -30,7 +31,6 @@ use crate::keyring::*;
|
|||||||
use crate::peerstate::*;
|
use crate::peerstate::*;
|
||||||
use crate::pgp::*;
|
use crate::pgp::*;
|
||||||
use crate::securejoin::handle_degrade_event;
|
use crate::securejoin::handle_degrade_event;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct E2eeHelper {
|
pub struct E2eeHelper {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ use crate::login_param::LoginParam;
|
|||||||
use crate::message::{self, Message, MessageState};
|
use crate::message::{self, Message, MessageState};
|
||||||
use crate::param::*;
|
use crate::param::*;
|
||||||
use crate::sql;
|
use crate::sql;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
/// Thread IDs
|
/// Thread IDs
|
||||||
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)]
|
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)]
|
||||||
@@ -140,7 +139,7 @@ impl Job {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(filename) = self.param.get(Param::File) {
|
if let Some(filename) = self.param.get(Param::File) {
|
||||||
if let Some(body) = dc_read_file_safe(context, filename) {
|
if let Ok(body) = dc_read_file(context, filename) {
|
||||||
if let Some(recipients) = self.param.get(Param::Recipients) {
|
if let Some(recipients) = self.param.get(Param::Recipients) {
|
||||||
let recipients_list = recipients
|
let recipients_list = recipients
|
||||||
.split("\x1e")
|
.split("\x1e")
|
||||||
@@ -670,7 +669,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
|||||||
mimefactory.msg.param.set_int(Param::Width, 0);
|
mimefactory.msg.param.set_int(Param::Width, 0);
|
||||||
mimefactory.msg.param.set_int(Param::Height, 0);
|
mimefactory.msg.param.set_int(Param::Height, 0);
|
||||||
|
|
||||||
if let Some(buf) = dc_read_file_safe(context, pathNfilename) {
|
if let Ok(buf) = dc_read_file(context, pathNfilename) {
|
||||||
if let Ok((width, height)) = dc_get_filemeta(&buf) {
|
if let Ok((width, height)) = dc_get_filemeta(&buf) {
|
||||||
mimefactory.msg.param.set_int(Param::Width, width as i32);
|
mimefactory.msg.param.set_int(Param::Width, width as i32);
|
||||||
mimefactory.msg.param.set_int(Param::Height, height as i32);
|
mimefactory.msg.param.set_int(Param::Height, height as i32);
|
||||||
@@ -1047,7 +1046,7 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &MimeFactory) ->
|
|||||||
success = 1;
|
success = 1;
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
free(recipients.cast());
|
libc::free(recipients.cast());
|
||||||
}
|
}
|
||||||
success
|
success
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ pub mod qr;
|
|||||||
mod smtp;
|
mod smtp;
|
||||||
pub mod sql;
|
pub mod sql;
|
||||||
mod stock;
|
mod stock;
|
||||||
pub mod x;
|
|
||||||
|
|
||||||
pub mod dc_array;
|
pub mod dc_array;
|
||||||
mod dc_dehtml;
|
mod dc_dehtml;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use deltachat_derive::{FromSql, ToSql};
|
use deltachat_derive::{FromSql, ToSql};
|
||||||
|
use libc::{free, strcmp};
|
||||||
use phf::phf_map;
|
use phf::phf_map;
|
||||||
|
|
||||||
use crate::chat::{self, Chat};
|
use crate::chat::{self, Chat};
|
||||||
@@ -18,7 +19,6 @@ use crate::param::*;
|
|||||||
use crate::pgp::*;
|
use crate::pgp::*;
|
||||||
use crate::sql;
|
use crate::sql;
|
||||||
use crate::stock::StockMessage;
|
use crate::stock::StockMessage;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
/// In practice, the user additionally cuts the string himself pixel-accurate.
|
/// In practice, the user additionally cuts the string himself pixel-accurate.
|
||||||
const SUMMARY_CHARACTERS: usize = 160;
|
const SUMMARY_CHARACTERS: usize = 160;
|
||||||
@@ -351,7 +351,7 @@ impl Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(filename) = self.get_file(context) {
|
if let Some(filename) = self.get_file(context) {
|
||||||
if let Some(mut buf) = dc_read_file_safe(context, filename) {
|
if let Ok(mut buf) = dc_read_file(context, filename) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// just a pointer inside buf, MUST NOT be free()'d
|
// just a pointer inside buf, MUST NOT be free()'d
|
||||||
let mut buf_headerline = ptr::null();
|
let mut buf_headerline = ptr::null();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::convert::TryInto;
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
use libc::{strchr, strlen, strncmp, strspn, strstr};
|
||||||
use pgp::composed::{
|
use pgp::composed::{
|
||||||
Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey,
|
Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey,
|
||||||
SignedSecretKey, SubkeyParamsBuilder,
|
SignedSecretKey, SubkeyParamsBuilder,
|
||||||
@@ -15,7 +16,6 @@ use crate::dc_tools::*;
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::key::*;
|
use crate::key::*;
|
||||||
use crate::keyring::*;
|
use crate::keyring::*;
|
||||||
use crate::x::*;
|
|
||||||
|
|
||||||
pub unsafe fn dc_split_armored_data(
|
pub unsafe fn dc_split_armored_data(
|
||||||
buf: *mut libc::c_char,
|
buf: *mut libc::c_char,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use crate::contact::*;
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
use crate::events::Event;
|
use crate::events::Event;
|
||||||
use libc::free;
|
|
||||||
|
|
||||||
/// Stock strings
|
/// Stock strings
|
||||||
///
|
///
|
||||||
@@ -133,7 +132,7 @@ impl Context {
|
|||||||
Cow::Borrowed(id.fallback())
|
Cow::Borrowed(id.fallback())
|
||||||
} else {
|
} else {
|
||||||
let ret = to_string(ptr);
|
let ret = to_string(ptr);
|
||||||
unsafe { free(ptr as *mut libc::c_void) };
|
unsafe { libc::free(ptr as *mut libc::c_void) };
|
||||||
Cow::Owned(ret)
|
Cow::Owned(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,19 +15,21 @@ if __name__ == "__main__":
|
|||||||
unsafe = s.count("unsafe")
|
unsafe = s.count("unsafe")
|
||||||
free = s.count("free(")
|
free = s.count("free(")
|
||||||
gotoblocks = s.count("ok_to_continue") + s.count('OK_TO_CONTINUE')
|
gotoblocks = s.count("ok_to_continue") + s.count('OK_TO_CONTINUE')
|
||||||
filestats.append((fn, unsafe, free, gotoblocks))
|
chars = s.count("c_char") + s.count("CStr")
|
||||||
|
filestats.append((fn, unsafe, free, gotoblocks, chars))
|
||||||
|
|
||||||
sum_unsafe, sum_free, sum_gotoblocks = 0, 0, 0
|
sum_unsafe, sum_free, sum_gotoblocks, sum_chars = 0, 0, 0, 0
|
||||||
|
|
||||||
for fn, unsafe, free, gotoblocks in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
|
for fn, unsafe, free, gotoblocks, chars in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
|
||||||
print("{0: <30} unsafe: {1: >3} free: {2: >3} ok_to_continue: {3: >3}".format(str(fn), unsafe, free, gotoblocks))
|
print("{0: <25} unsafe: {1: >3} free: {2: >3} ok_to_cont: {3: >3} chars: {4: >3}".format(str(fn), unsafe, free, gotoblocks, chars))
|
||||||
sum_unsafe += unsafe
|
sum_unsafe += unsafe
|
||||||
sum_free += free
|
sum_free += free
|
||||||
sum_gotoblocks += gotoblocks
|
sum_gotoblocks += gotoblocks
|
||||||
|
sum_chars += chars
|
||||||
|
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print("total unsafe:", sum_unsafe)
|
print("total unsafe:", sum_unsafe)
|
||||||
print("total free:", sum_free)
|
print("total free:", sum_free)
|
||||||
print("total ok_to_continue:", sum_gotoblocks)
|
print("total ok_to_continue:", sum_gotoblocks)
|
||||||
|
print("total c_chars:", sum_chars)
|
||||||
|
|||||||
67
src/x.rs
67
src/x.rs
@@ -1,67 +0,0 @@
|
|||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub unsafe fn strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
|
||||||
if s.is_null() {
|
|
||||||
return std::ptr::null_mut();
|
|
||||||
}
|
|
||||||
|
|
||||||
let slen = strlen(s);
|
|
||||||
let result = malloc(slen + 1);
|
|
||||||
if result.is_null() {
|
|
||||||
return std::ptr::null_mut();
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(result, s as *const _, slen + 1);
|
|
||||||
result as *mut _
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn strndup(s: *const libc::c_char, n: libc::c_ulong) -> *mut libc::c_char {
|
|
||||||
if s.is_null() {
|
|
||||||
return std::ptr::null_mut();
|
|
||||||
}
|
|
||||||
|
|
||||||
let end = std::cmp::min(n as usize, unsafe { strlen(s) });
|
|
||||||
unsafe {
|
|
||||||
let result = malloc(end + 1);
|
|
||||||
memcpy(result, s as *const _, end);
|
|
||||||
std::ptr::write_bytes(result.offset(end as isize), b'\x00', 1);
|
|
||||||
|
|
||||||
result as *mut _
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) unsafe fn strcasecmp(s1: *const libc::c_char, s2: *const libc::c_char) -> libc::c_int {
|
|
||||||
let s1 = std::ffi::CStr::from_ptr(s1)
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_lowercase();
|
|
||||||
let s2 = std::ffi::CStr::from_ptr(s2)
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_lowercase();
|
|
||||||
if s1 == s2 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::dc_tools::to_string;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_strndup() {
|
|
||||||
unsafe {
|
|
||||||
let res = strndup(b"helloworld\x00" as *const u8 as *const libc::c_char, 4);
|
|
||||||
assert_eq!(
|
|
||||||
to_string(res),
|
|
||||||
to_string(b"hell\x00" as *const u8 as *const libc::c_char)
|
|
||||||
);
|
|
||||||
assert_eq!(strlen(res), 4);
|
|
||||||
free(res as *mut _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
//! Stress some functions for testing; if used as a lib, this file is obsolete.
|
//! Stress some functions for testing; if used as a lib, this file is obsolete.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use tempfile::{tempdir, TempDir};
|
|
||||||
|
|
||||||
use deltachat::chat::{self, Chat};
|
use deltachat::chat::{self, Chat};
|
||||||
use deltachat::config;
|
use deltachat::config;
|
||||||
use deltachat::contact::*;
|
use deltachat::contact::*;
|
||||||
@@ -15,9 +12,9 @@ use deltachat::dc_tools::*;
|
|||||||
use deltachat::keyring::*;
|
use deltachat::keyring::*;
|
||||||
use deltachat::oauth2::*;
|
use deltachat::oauth2::*;
|
||||||
use deltachat::pgp::*;
|
use deltachat::pgp::*;
|
||||||
use deltachat::x::*;
|
|
||||||
use deltachat::Event;
|
use deltachat::Event;
|
||||||
use libc;
|
use libc::{free, strcmp, strdup, strlen, strncmp};
|
||||||
|
use tempfile::{tempdir, TempDir};
|
||||||
|
|
||||||
/* some data used for testing
|
/* some data used for testing
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -30,68 +27,6 @@ static mut S_EM_SETUPFILE: *const libc::c_char =
|
|||||||
as *const u8 as *const libc::c_char;
|
as *const u8 as *const libc::c_char;
|
||||||
|
|
||||||
unsafe fn stress_functions(context: &Context) {
|
unsafe fn stress_functions(context: &Context) {
|
||||||
if dc_file_exist(context, "$BLOBDIR/foobar")
|
|
||||||
|| dc_file_exist(context, "$BLOBDIR/dada")
|
|
||||||
|| dc_file_exist(context, "$BLOBDIR/foobar.dadada")
|
|
||||||
|| dc_file_exist(context, "$BLOBDIR/foobar-folder")
|
|
||||||
{
|
|
||||||
dc_delete_file(context, "$BLOBDIR/foobar");
|
|
||||||
dc_delete_file(context, "$BLOBDIR/dada");
|
|
||||||
dc_delete_file(context, "$BLOBDIR/foobar.dadada");
|
|
||||||
dc_delete_file(context, "$BLOBDIR/foobar-folder");
|
|
||||||
}
|
|
||||||
assert!(dc_write_file(context, "$BLOBDIR/foobar", b"content"));
|
|
||||||
assert!(dc_file_exist(context, "$BLOBDIR/foobar",));
|
|
||||||
assert!(!dc_file_exist(context, "$BLOBDIR/foobarx"));
|
|
||||||
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/foobar"), 7);
|
|
||||||
|
|
||||||
let abs_path = context
|
|
||||||
.get_blobdir()
|
|
||||||
.join("foobar")
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
assert!(dc_is_blobdir_path(context, &abs_path));
|
|
||||||
assert!(dc_is_blobdir_path(context, "$BLOBDIR/fofo",));
|
|
||||||
assert!(!dc_is_blobdir_path(context, "/BLOBDIR/fofo",));
|
|
||||||
assert!(dc_file_exist(context, &abs_path));
|
|
||||||
|
|
||||||
assert!(dc_copy_file(context, "$BLOBDIR/foobar", "$BLOBDIR/dada",));
|
|
||||||
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/dada",), 7);
|
|
||||||
|
|
||||||
let mut buf: *mut libc::c_void = ptr::null_mut();
|
|
||||||
let mut buf_bytes: libc::size_t = 0;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
dc_read_file(
|
|
||||||
context,
|
|
||||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
|
||||||
&mut buf,
|
|
||||||
&mut buf_bytes,
|
|
||||||
),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
assert_eq!(buf_bytes, 7);
|
|
||||||
assert_eq!(
|
|
||||||
std::str::from_utf8(std::slice::from_raw_parts(buf as *const u8, buf_bytes)).unwrap(),
|
|
||||||
"content"
|
|
||||||
);
|
|
||||||
|
|
||||||
free(buf as *mut _);
|
|
||||||
assert!(dc_delete_file(context, "$BLOBDIR/foobar"));
|
|
||||||
assert!(dc_delete_file(context, "$BLOBDIR/dada"));
|
|
||||||
assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder"));
|
|
||||||
assert!(dc_file_exist(context, "$BLOBDIR/foobar-folder",));
|
|
||||||
assert!(!dc_delete_file(context, "$BLOBDIR/foobar-folder"));
|
|
||||||
let fn0 = dc_get_fine_path_filename(context, "$BLOBDIR", "foobar.dadada");
|
|
||||||
assert_eq!(fn0, PathBuf::from("$BLOBDIR/foobar.dadada"));
|
|
||||||
|
|
||||||
assert!(dc_write_file(context, &fn0, b"content"));
|
|
||||||
let fn1 = dc_get_fine_path_filename(context, "$BLOBDIR", "foobar.dadada");
|
|
||||||
assert_eq!(fn1, PathBuf::from("$BLOBDIR/foobar-1.dadada"));
|
|
||||||
|
|
||||||
assert!(dc_delete_file(context, &fn0));
|
|
||||||
|
|
||||||
let res = context.get_config(config::Config::SysConfigKeys).unwrap();
|
let res = context.get_config(config::Config::SysConfigKeys).unwrap();
|
||||||
|
|
||||||
assert!(!res.contains(" probably_never_a_key "));
|
assert!(!res.contains(" probably_never_a_key "));
|
||||||
|
|||||||
Reference in New Issue
Block a user