Compare commits

...

12 Commits

Author SHA1 Message Date
B. Petersen
c63fbf199a display failed messages 2019-11-02 00:34:14 +01:00
B. Petersen
ec8dbddcfb tweak ffi documentation wrt certificate checks 2019-11-01 18:06:01 +01:00
B. Petersen
bc699f17d9 avoid usage of get_subtitle() in repl-tool, remove dc_chat_get_subtitle() from documentation. 2019-11-01 13:19:47 +01:00
B. Petersen
832df41130 target comments of @hpk42 and @flub 2019-11-01 00:46:48 +01:00
B. Petersen
5709681076 streamline as_path_unicode(), delete unused as_str() and as_str_safe() 2019-11-01 00:46:48 +01:00
B. Petersen
858baf0c2c prefer to_opt_string_lossy() over as_opt_str() as the latter pancis on non-wellformatted utf-8, delete as_opt_str() 2019-11-01 00:46:48 +01:00
B. Petersen
e4b3e23769 prefer to_string_lossy() over as_str() as the latter pancis on non-wellformatted utf-8 2019-11-01 00:46:48 +01:00
holger krekel
8ce05796da ensure that especially qr tests are rerun 2019-10-31 23:31:09 +01:00
holger krekel
7f8c6d8cca some more display refinements 2019-10-31 23:31:09 +01:00
holger krekel
75ba040531 more error logging with file operations in general 2019-10-31 23:31:09 +01:00
Floris Bruynooghe
faa78e1c04 At least log the error 2019-10-31 22:38:32 +01:00
Floris Bruynooghe
b264d3be3c Be more accepting in creating blobs from existing names
This is an additional fix for #768 aka
commit eac8ad8369
2019-10-31 20:05:09 +01:00
11 changed files with 156 additions and 106 deletions

View File

@@ -43,8 +43,8 @@ if [ -n "$TESTS" ]; then
# we split out qr-tests run to minimize likelyness of flaky tests
# (some qr tests are pretty heavy in terms of send/received
# messages and rust's imap code likely has concurrency problems)
tox --workdir "$TOXWORKDIR" -e py37 -- -k "not qr"
tox --workdir "$TOXWORKDIR" -e py37 -- -k "qr"
tox --workdir "$TOXWORKDIR" -e py37 -- --reruns 3 -k "not qr"
tox --workdir "$TOXWORKDIR" -e py37 -- --reruns 3 -k "qr"
unset DCC_PY_LIVECONFIG
tox --workdir "$TOXWORKDIR" -p4 -e lint,py35,py36,doc
tox --workdir "$TOXWORKDIR" -e auditwheels

View File

@@ -338,6 +338,8 @@ char* dc_get_blobdir (const dc_context_t* context);
* - `send_pw` = SMTP-password, guessed if left out
* - `send_port` = SMTP-port, guessed if left out
* - `server_flags` = IMAP-/SMTP-flags as a combination of @ref DC_LP flags, guessed if left out
* - `imap_certificate_checks` = how to check IMAP certificates, one of the @ref DC_CERTCK flags, defaults to #DC_CERTCK_AUTO (0)
* - `smtp_certificate_checks` = how to check SMTP certificates, one of the @ref DC_CERTCK flags, defaults to #DC_CERTCK_AUTO (0)
* - `displayname` = Own name to use when sending messages. MUAs are allowed to spread this way eg. using CC, defaults to empty
* - `selfstatus` = Own status to display eg. in email footers, defaults to a standard text
* - `selfavatar` = File containing avatar. Will be copied to blob directory.
@@ -2610,8 +2612,6 @@ int dc_chat_get_type (const dc_chat_t* chat);
*
* To change the name, use dc_set_chat_name()
*
* See also: dc_chat_get_subtitle()
*
* @memberof dc_chat_t
* @param chat The chat object.
* @return Chat name as a string. Must be released using dc_str_unref() after usage. Never NULL.
@@ -2619,13 +2619,13 @@ int dc_chat_get_type (const dc_chat_t* chat);
char* dc_chat_get_name (const dc_chat_t* chat);
/**
/*
* Get a subtitle for a chat. The subtitle is eg. the email-address or the
* number of group members.
*
* See also: dc_chat_get_name()
* Deprecated function. Subtitles should be created in the ui
* where plural forms and other specials can be handled more gracefully.
*
* @memberof dc_chat_t
* @param chat The chat object to calulate the subtitle for.
* @return Subtitle as a string. Must be released using dc_str_unref() after usage. Never NULL.
*/
@@ -3894,7 +3894,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
*
* These constants configure TLS certificate checks for IMAP and SMTP connections.
*
* These constants are set via dc_set_config
* These constants are set via dc_set_config()
* using keys "imap_certificate_checks" and "smtp_certificate_checks".
*
* @addtogroup DC_CERTCK
@@ -3907,8 +3907,8 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
#define DC_CERTCK_AUTO 0
/**
* Strictly check TLS certificates.
* Require that both the certificate and hostname are valid.
* Strictly check TLS certificates;
* require that both the certificate and hostname are valid.
*/
#define DC_CERTCK_STRICT 1

View File

@@ -2,7 +2,7 @@ extern crate deltachat_provider_database;
use std::ptr;
use deltachat::dc_tools::{as_str, StrExt};
use deltachat::dc_tools::{to_string_lossy, StrExt};
use deltachat_provider_database::StatusState;
#[no_mangle]
@@ -12,7 +12,7 @@ pub type dc_provider_t = deltachat_provider_database::Provider;
pub unsafe extern "C" fn dc_provider_new_from_domain(
domain: *const libc::c_char,
) -> *const dc_provider_t {
match deltachat_provider_database::get_provider_info(as_str(domain)) {
match deltachat_provider_database::get_provider_info(&to_string_lossy(domain)) {
Some(provider) => provider,
None => ptr::null(),
}
@@ -22,7 +22,8 @@ pub unsafe extern "C" fn dc_provider_new_from_domain(
pub unsafe extern "C" fn dc_provider_new_from_email(
email: *const libc::c_char,
) -> *const dc_provider_t {
let domain = deltachat_provider_database::get_domain_from_email(as_str(email));
let email = to_string_lossy(email);
let domain = deltachat_provider_database::get_domain_from_email(&email);
match deltachat_provider_database::get_provider_info(domain) {
Some(provider) => provider,
None => ptr::null(),

View File

@@ -517,15 +517,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
for i in (0..cnt).rev() {
let chat = Chat::load_from_db(context, chatlist.get_chat_id(i))?;
let temp_subtitle = chat.get_subtitle(context);
let temp_name = chat.get_name();
info!(
context,
"{}#{}: {} [{}] [{} fresh]",
"{}#{}: {} [{} fresh]",
chat_prefix(&chat),
chat.get_id(),
temp_name,
temp_subtitle,
chat::get_fresh_msg_cnt(context, chat.get_id()),
);
let lot = chatlist.get_summary(context, i, Some(&chat));
@@ -583,7 +581,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let sel_chat = sel_chat.as_ref().unwrap();
let msglist = chat::get_chat_msgs(context, sel_chat.get_id(), 0x1, None);
let temp2 = sel_chat.get_subtitle(context);
let members = chat::get_chat_contacts(context, sel_chat.id);
let temp2 = if sel_chat.get_type() == Chattype::Single && members.len() >= 1 {
let contact = Contact::get_by_id(context, members[0])?;
contact.get_addr().to_string()
} else {
format!("{} member(s)", members.len())
};
let temp_name = sel_chat.get_name();
info!(
context,

View File

@@ -1,3 +1,4 @@
use std::ffi::OsStr;
use std::fmt;
use std::fs;
use std::io::Write;
@@ -145,6 +146,9 @@ impl<'a> BlobObject<'a> {
.as_ref()
.strip_prefix(context.get_blobdir())
.map_err(|_| BlobError::new_wrong_blobdir(context.get_blobdir(), path.as_ref()))?;
if !BlobObject::is_acceptible_blob_name(&rel_path) {
return Err(BlobError::new_wrong_name(path.as_ref()));
}
let name = rel_path
.to_str()
.ok_or_else(|| BlobError::new_wrong_name(path.as_ref()))?;
@@ -171,8 +175,7 @@ impl<'a> BlobObject<'a> {
true => name.splitn(2, '/').last().unwrap().to_string(),
false => name,
};
let (stem, ext) = BlobObject::sanitise_name(name.clone());
if format!("{}{}", stem, ext) != name.as_ref() {
if !BlobObject::is_acceptible_blob_name(&name) {
return Err(BlobError::new_wrong_name(name));
}
Ok(BlobObject {
@@ -266,6 +269,28 @@ impl<'a> BlobObject<'a> {
_ => (stem, format!(".{}", ext).to_lowercase()),
}
}
/// Checks whether a name is a valid blob name.
///
/// This is slightly less strict than stanitise_name, presumably
/// someone already created a file with such a name so we just
/// ensure it's not actually a path in disguise is actually utf-8.
fn is_acceptible_blob_name(name: impl AsRef<OsStr>) -> bool {
let uname = match name.as_ref().to_str() {
Some(name) => name,
None => return false,
};
if uname.find('/').is_some() {
return false;
}
if uname.find('\\').is_some() {
return false;
}
if uname.find('\0').is_some() {
return false;
}
true
}
}
impl<'a> fmt::Display for BlobObject<'a> {
@@ -615,4 +640,14 @@ mod tests {
"$BLOBDIR/autocrypt-setup-message-4137848473.html"
);
}
#[test]
fn test_is_blob_name() {
assert!(BlobObject::is_acceptible_blob_name("foo"));
assert!(BlobObject::is_acceptible_blob_name("foo.txt"));
assert!(BlobObject::is_acceptible_blob_name("f".repeat(128)));
assert!(!BlobObject::is_acceptible_blob_name("foo/bar"));
assert!(!BlobObject::is_acceptible_blob_name("foo\\bar"));
assert!(!BlobObject::is_acceptible_blob_name("foo\x00bar"));
}
}

View File

@@ -117,18 +117,30 @@ impl<'a> MimeParser<'a> {
);
if r == MAILIMF_NO_ERROR as libc::c_int && !self.mimeroot.is_null() {
let (encrypted, signatures, gossipped_addr) =
e2ee::try_decrypt(self.context, self.mimeroot)?;
self.encrypted = encrypted;
self.signatures = signatures;
self.gossipped_addr = gossipped_addr;
match e2ee::try_decrypt(self.context, self.mimeroot) {
Ok((encrypted, signatures, gossipped_addr)) => {
self.encrypted = encrypted;
self.signatures = signatures;
self.gossipped_addr = gossipped_addr;
}
Err(err) => {
// continue with the current, still encrypted, mime tree.
// unencrypted parts will be replaced by an error message
// that is added as "the message" to the chat then.
//
// if we just return here, the header is missing
// and the caller cannot display the message
// and try to assign the message to a chat
warn!(self.context, "decryption failed: {}", err);
}
}
self.parse_mime_recursive(self.mimeroot);
if let Some(field) = self.lookup_field("Subject") {
if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
let subj = (*(*field).fld_data.fld_subject).sbj_value;
self.subject = as_opt_str(subj).map(dc_decode_header_words);
self.subject = to_opt_string_lossy(subj).map(|x| dc_decode_header_words(&x));
}
}
@@ -630,7 +642,7 @@ impl<'a> MimeParser<'a> {
self.context,
"Cannot convert {} bytes from \"{}\" to \"utf-8\".",
decoded_data.len(),
as_str(charset),
to_string_lossy(charset),
);
}
}
@@ -729,8 +741,10 @@ impl<'a> MimeParser<'a> {
if !(*mime).mm_content_type.is_null()
&& !(*(*mime).mm_content_type).ct_subtype.is_null()
{
desired_filename =
format!("file.{}", as_str((*(*mime).mm_content_type).ct_subtype));
desired_filename = format!(
"file.{}",
to_string_lossy((*(*mime).mm_content_type).ct_subtype)
);
} else {
return false;
}
@@ -850,7 +864,8 @@ impl<'a> MimeParser<'a> {
}) as *mut mailimf_mailbox;
if !mb.is_null() {
let from_addr_norm = addr_normalize(as_str((*mb).mb_addr_spec));
let from_addr = to_string_lossy((*mb).mb_addr_spec);
let from_addr_norm = addr_normalize(&from_addr);
let recipients = wrapmime::mailimf_get_recipients(self.header_root);
if recipients.len() == 1 && recipients.contains(from_addr_norm) {
sender_equals_recipient = true;
@@ -989,15 +1004,16 @@ unsafe fn mailmime_get_mime_type(mime: *mut Mailmime) -> (libc::c_int, Viewtype,
}
}
let raw_mime = reconcat_mime(Some("text"), as_opt_str((*c).ct_subtype));
let raw_mime = reconcat_mime(Some("text"), to_opt_string_lossy((*c).ct_subtype));
(DC_MIMETYPE_FILE, Viewtype::File, Some(raw_mime))
}
MAILMIME_DISCRETE_TYPE_IMAGE => {
let subtype = as_opt_str((*c).ct_subtype);
let msg_type = match subtype {
let subtype = to_opt_string_lossy((*c).ct_subtype);
let msg_type = match subtype.as_ref().map(|x| x.as_str()) {
Some("gif") => Viewtype::Gif,
Some("svg+xml") => {
let raw_mime = reconcat_mime(Some("image"), as_opt_str((*c).ct_subtype));
let raw_mime =
reconcat_mime(Some("image"), to_opt_string_lossy((*c).ct_subtype));
return (DC_MIMETYPE_FILE, Viewtype::File, Some(raw_mime));
}
_ => Viewtype::Image,
@@ -1007,11 +1023,11 @@ unsafe fn mailmime_get_mime_type(mime: *mut Mailmime) -> (libc::c_int, Viewtype,
(DC_MIMETYPE_IMAGE, msg_type, Some(raw_mime))
}
MAILMIME_DISCRETE_TYPE_AUDIO => {
let raw_mime = reconcat_mime(Some("audio"), as_opt_str((*c).ct_subtype));
let raw_mime = reconcat_mime(Some("audio"), to_opt_string_lossy((*c).ct_subtype));
(DC_MIMETYPE_AUDIO, Viewtype::Audio, Some(raw_mime))
}
MAILMIME_DISCRETE_TYPE_VIDEO => {
let raw_mime = reconcat_mime(Some("video"), as_opt_str((*c).ct_subtype));
let raw_mime = reconcat_mime(Some("video"), to_opt_string_lossy((*c).ct_subtype));
(DC_MIMETYPE_VIDEO, Viewtype::Video, Some(raw_mime))
}
_ => {
@@ -1022,13 +1038,15 @@ unsafe fn mailmime_get_mime_type(mime: *mut Mailmime) -> (libc::c_int, Viewtype,
b"autocrypt-setup\x00" as *const u8 as *const libc::c_char,
) == 0i32
{
let raw_mime = reconcat_mime(None, as_opt_str((*c).ct_subtype));
let raw_mime = reconcat_mime(None, to_opt_string_lossy((*c).ct_subtype));
return (DC_MIMETYPE_AC_SETUP_FILE, Viewtype::File, Some(raw_mime));
}
let raw_mime = reconcat_mime(
as_opt_str((*(*(*c).ct_type).tp_data.tp_discrete_type).dt_extension),
as_opt_str((*c).ct_subtype),
to_opt_string_lossy((*(*(*c).ct_type).tp_data.tp_discrete_type).dt_extension)
.as_ref()
.map(|x| x.as_str()),
to_opt_string_lossy((*c).ct_subtype),
);
(DC_MIMETYPE_FILE, Viewtype::File, Some(raw_mime))
@@ -1038,9 +1056,9 @@ unsafe fn mailmime_get_mime_type(mime: *mut Mailmime) -> (libc::c_int, Viewtype,
if (*(*(*c).ct_type).tp_data.tp_composite_type).ct_type
== MAILMIME_COMPOSITE_TYPE_MULTIPART as libc::c_int
{
let subtype = as_opt_str((*c).ct_subtype);
let subtype = to_opt_string_lossy((*c).ct_subtype);
let mime_type = match subtype {
let mime_type = match subtype.as_ref().map(|x| x.as_str()) {
Some("alternative") => DC_MIMETYPE_MP_ALTERNATIVE,
Some("related") => DC_MIMETYPE_MP_RELATED,
Some("encrypted") => {
@@ -1075,9 +1093,9 @@ unsafe fn mailmime_get_mime_type(mime: *mut Mailmime) -> (libc::c_int, Viewtype,
}
}
fn reconcat_mime(typ: Option<&str>, subtype: Option<&str>) -> String {
fn reconcat_mime(typ: Option<&str>, subtype: Option<String>) -> String {
let typ = typ.unwrap_or("application");
let subtype = subtype.unwrap_or("octet-stream");
let subtype = subtype.unwrap_or("octet-stream".to_string());
format!("{}/{}", typ, subtype)
}

View File

@@ -65,12 +65,12 @@ pub unsafe fn dc_receive_imf(
let mut mime_parser = MimeParser::new(context);
if let Err(err) = mime_parser.parse(imf_raw) {
error!(context, "dc_receive_imf parse error: {}", err);
warn!(context, "dc_receive_imf parse error: {}", err);
};
if mime_parser.header.is_empty() {
// Error - even adding an empty record won't help as we do not know the message ID
info!(context, "No header.");
warn!(context, "No header.");
return;
}
@@ -808,9 +808,9 @@ unsafe fn handle_reports(
&& !of_org_msgid.is_null()
&& !(*of_org_msgid).fld_value.is_null()
{
if let Ok(rfc724_mid) = wrapmime::parse_message_id(as_str(
(*of_org_msgid).fld_value,
)) {
if let Ok(rfc724_mid) = wrapmime::parse_message_id(
&to_string_lossy((*of_org_msgid).fld_value),
) {
if let Some((chat_id, msg_id)) = message::mdn_from_ext(
context,
from_id,
@@ -993,7 +993,7 @@ unsafe fn create_or_lookup_group(
let fld_message_id = (*field).fld_data.fld_message_id;
if !fld_message_id.is_null() {
if let Some(extracted_grpid) =
dc_extract_grpid_from_rfc724_mid(as_str((*fld_message_id).mid_value))
dc_extract_grpid_from_rfc724_mid(&to_string_lossy((*fld_message_id).mid_value))
{
grpid = extracted_grpid.to_string();
} else {
@@ -1731,7 +1731,7 @@ fn is_known_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) -> li
LEFT JOIN chats c ON m.chat_id=c.id \
WHERE m.rfc724_mid=? \
AND m.chat_id>9 AND c.blocked=0;",
params![as_str(rfc724_mid)],
params![to_string_lossy(rfc724_mid)],
)
.unwrap_or_default() as libc::c_int
}
@@ -1783,11 +1783,7 @@ unsafe fn is_msgrmsg_rfc724_mid_in_list(context: &Context, mid_list: *const clis
while !cur.is_null() {
if 0 != is_msgrmsg_rfc724_mid(
context,
if !cur.is_null() {
as_str((*cur).data as *const libc::c_char)
} else {
""
},
&to_string_lossy((*cur).data as *const libc::c_char),
) {
return 1;
}
@@ -1923,7 +1919,7 @@ unsafe fn add_or_lookup_contact_by_addr(
.get_config(Config::ConfiguredAddr)
.unwrap_or_default();
if addr_cmp(self_addr, as_str(addr_spec)) {
if addr_cmp(self_addr, to_string_lossy(addr_spec)) {
*check_self = 1;
}
@@ -1933,13 +1929,18 @@ unsafe fn add_or_lookup_contact_by_addr(
/* add addr_spec if missing, update otherwise */
let mut display_name_dec = "".to_string();
if !display_name_enc.is_null() {
let tmp = dc_decode_header_words(as_str(display_name_enc));
let tmp = dc_decode_header_words(&to_string_lossy(display_name_enc));
display_name_dec = normalize_name(&tmp);
}
/*can be NULL*/
let row_id = Contact::add_or_lookup(context, display_name_dec, as_str(addr_spec), origin)
.map(|(id, _)| id)
.unwrap_or_default();
let row_id = Contact::add_or_lookup(
context,
display_name_dec,
to_string_lossy(addr_spec),
origin,
)
.map(|(id, _)| id)
.unwrap_or_default();
if 0 != row_id && !ids.contains(&row_id) {
ids.push(row_id);
};

View File

@@ -82,7 +82,7 @@ pub(crate) fn dc_str_from_clist(list: *const clist, delimiter: &str) -> String {
if !res.is_empty() {
res += delimiter;
}
res += as_str(rfc724_mid as *const libc::c_char);
res += &to_string_lossy(rfc724_mid as *const libc::c_char);
}
}
res
@@ -303,9 +303,9 @@ pub(crate) fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut
if !list.is_null() {
unsafe {
for cur in (*list).into_iter() {
let mid = as_str(cur as *const libc::c_char);
let mid = to_string_lossy(cur as *const libc::c_char);
if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(mid) {
if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(&mid) {
return grpid.strdup();
}
}
@@ -420,8 +420,8 @@ pub(crate) fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path
context.call_cb(Event::DeletedBlobFile(dpath));
true
}
Err(_err) => {
warn!(context, "Cannot delete \"{}\".", dpath);
Err(err) => {
warn!(context, "Cannot delete \"{}\": {}", dpath, err);
false
}
}
@@ -436,12 +436,13 @@ pub(crate) fn dc_copy_file(
let dest_abs = dc_get_abs_path(context, &dest);
match fs::copy(&src_abs, &dest_abs) {
Ok(_) => true,
Err(_) => {
Err(err) => {
error!(
context,
"Cannot copy \"{}\" to \"{}\".",
"Cannot copy \"{}\" to \"{}\": {}",
src.as_ref().display(),
dest.as_ref().display(),
err
);
false
}
@@ -453,11 +454,12 @@ pub(crate) fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Pa
if !path_abs.exists() {
match fs::create_dir_all(path_abs) {
Ok(_) => true,
Err(_err) => {
Err(err) => {
warn!(
context,
"Cannot create directory \"{}\".",
"Cannot create directory \"{}\": {}",
path.as_ref().display(),
err
);
false
}
@@ -470,12 +472,13 @@ pub(crate) fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Pa
/// Write a the given content to provied file path.
pub(crate) fn dc_write_file(context: &Context, path: impl AsRef<Path>, buf: &[u8]) -> bool {
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!(
context,
"Cannot write {} bytes to \"{}\".",
"Cannot write {} bytes to \"{}\": {}",
buf.len(),
path.as_ref().display(),
err
);
false
} else {
@@ -494,8 +497,9 @@ pub fn dc_read_file<P: AsRef<std::path::Path>>(
Err(err) => {
warn!(
context,
"Cannot read \"{}\" or file is empty.",
path.as_ref().display()
"Cannot read \"{}\" or file is empty: {}",
path.as_ref().display(),
err
);
Err(err.into())
}
@@ -513,8 +517,9 @@ pub fn dc_open_file<P: AsRef<std::path::Path>>(
Err(err) => {
warn!(
context,
"Cannot read \"{}\" or file is empty.",
path.as_ref().display()
"Cannot read \"{}\" or file is empty: {}",
path.as_ref().display(),
err
);
Err(err.into())
}
@@ -704,27 +709,6 @@ pub fn to_opt_string_lossy(s: *const libc::c_char) -> Option<String> {
Some(to_string_lossy(s))
}
pub fn as_str<'a>(s: *const libc::c_char) -> &'a str {
as_str_safe(s).unwrap_or_else(|err| panic!("{}", err))
}
/// Converts a C string to either a Rust `&str` or `None` if it is a null pointer.
pub fn as_opt_str<'a>(s: *const libc::c_char) -> Option<&'a str> {
if s.is_null() {
return None;
}
Some(as_str(s))
}
fn as_str_safe<'a>(s: *const libc::c_char) -> Result<&'a str, Error> {
assert!(!s.is_null(), "cannot be used on null pointers");
let cstr = unsafe { CStr::from_ptr(s) };
cstr.to_str()
.map_err(|err| format_err!("Non utf8 string: '{:?}' ({:?})", cstr.to_bytes(), err))
}
/// Convert a C `*char` pointer to a [std::path::Path] slice.
///
/// This converts a `*libc::c_char` pointer to a [Path] slice. This
@@ -761,7 +745,11 @@ pub fn as_path<'a>(s: *const libc::c_char) -> &'a std::path::Path {
#[allow(dead_code)]
fn as_path_unicode<'a>(s: *const libc::c_char) -> &'a std::path::Path {
assert!(!s.is_null(), "cannot be used on null pointers");
std::path::Path::new(as_str(s))
let cstr = unsafe { CStr::from_ptr(s) };
let str = cstr.to_str().unwrap_or_else(|err| panic!("{}", err));
std::path::Path::new(str)
}
pub(crate) fn time() -> i64 {

View File

@@ -449,7 +449,7 @@ fn update_gossip_peerstates(
let optional_field = unsafe { *optional_field };
if !optional_field.fld_name.is_null()
&& as_str(optional_field.fld_name) == "Autocrypt-Gossip"
&& to_string_lossy(optional_field.fld_name) == "Autocrypt-Gossip"
{
let value = to_string_lossy(optional_field.fld_value);
let gossip_header = Aheader::from_str(&value);
@@ -655,7 +655,7 @@ fn contains_report(mime: *mut Mailmime) -> bool {
if tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int
&& ct_type == MAILMIME_COMPOSITE_TYPE_MULTIPART as libc::c_int
&& as_str(unsafe { (*mime.mm_content_type).ct_subtype }) == "report"
&& to_string_lossy(unsafe { (*mime.mm_content_type).ct_subtype }) == "report"
{
return true;
}

View File

@@ -490,7 +490,7 @@ fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
context.sql.close(context);
info!(
context,
"Backup \"{}\" to \"{}\".",
"Backup '{}' to '{}'.",
context.get_dbfile().display(),
dest_path_filename.display(),
);
@@ -499,8 +499,8 @@ fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
if !copied {
let s = dest_path_filename.to_string_lossy().to_string();
bail!(
"could not copy file from {:?} to {:?}",
context.get_dbfile(),
"could not copy file from '{}' to '{}'",
context.get_dbfile().display(),
s
);
}

View File

@@ -143,7 +143,8 @@ pub fn get_field_date(imffields: *mut mailimf_fields) -> Result<i64, Error> {
fn mailimf_get_recipients_add_addr(recipients: &mut HashSet<String>, mb: *mut mailimf_mailbox) {
if !mb.is_null() {
let addr_norm = addr_normalize(as_str(unsafe { (*mb).mb_addr_spec }));
let addr = to_string_lossy(unsafe { (*mb).mb_addr_spec });
let addr_norm = addr_normalize(&addr);
recipients.insert(addr_norm.into());
}
}
@@ -382,8 +383,8 @@ pub fn mailimf_find_first_addr(mb_list: *const mailimf_mailbox_list) -> Option<S
for cur in unsafe { (*(*mb_list).mb_list).into_iter() } {
let mb = cur as *mut mailimf_mailbox;
if !mb.is_null() && !unsafe { (*mb).mb_addr_spec.is_null() } {
let addr = unsafe { as_str((*mb).mb_addr_spec) };
return Some(addr_normalize(addr).to_string());
let addr = unsafe { to_string_lossy((*mb).mb_addr_spec) };
return Some(addr_normalize(&addr).to_string());
}
}
@@ -489,7 +490,9 @@ pub fn content_type_needs_encoding(content: *const mailmime_content) -> bool {
if (*(*content).ct_type).tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int {
let composite = (*(*content).ct_type).tp_data.tp_composite_type;
match (*composite).ct_type as u32 {
MAILMIME_COMPOSITE_TYPE_MESSAGE => as_str((*content).ct_subtype) != "rfc822",
MAILMIME_COMPOSITE_TYPE_MESSAGE => {
to_string_lossy((*content).ct_subtype) != "rfc822"
}
MAILMIME_COMPOSITE_TYPE_MULTIPART => false,
_ => false,
}