Merge branch 'refactor/remove-mprintf'

This commit is contained in:
holger krekel
2019-09-17 16:23:25 +02:00
16 changed files with 551 additions and 896 deletions

448
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,10 +5,6 @@ authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
edition = "2018" edition = "2018"
license = "MPL" license = "MPL"
[build-dependencies]
cc = "1.0.35"
pkg-config = "0.3"
[dependencies] [dependencies]
deltachat_derive = { path = "./deltachat_derive" } deltachat_derive = { path = "./deltachat_derive" }
libc = "0.2.51" libc = "0.2.51"

View File

@@ -1,38 +0,0 @@
extern crate cc;
fn link_static(lib: &str) {
println!("cargo:rustc-link-lib=static={}", lib);
}
fn link_framework(fw: &str) {
println!("cargo:rustc-link-lib=framework={}", fw);
}
fn add_search_path(p: &str) {
println!("cargo:rustc-link-search={}", p);
}
fn build_tools() {
let mut config = cc::Build::new();
config.file("misc.c").compile("libtools.a");
println!("rerun-if-changed=build.rs");
println!("rerun-if-changed=misc.h");
println!("rerun-if-changed=misc.c");
}
fn main() {
build_tools();
add_search_path("/usr/local/lib");
let target = std::env::var("TARGET").unwrap();
if target.contains("-apple") || target.contains("-darwin") {
link_framework("CoreFoundation");
link_framework("CoreServices");
link_framework("Security");
}
// local tools
link_static("tools");
}

View File

@@ -510,18 +510,14 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
} }
"export-setup" => { "export-setup" => {
let setup_code = dc_create_setup_code(context); let setup_code = dc_create_setup_code(context);
let file_name: *mut libc::c_char = dc_mprintf( let file_name = context.get_blobdir().join("autocrypt-setup-message.html");
b"%s/autocrypt-setup-message.html\x00" as *const u8 as *const libc::c_char,
context.get_blobdir(),
);
let file_content = dc_render_setup_file(context, &setup_code)?; let file_content = dc_render_setup_file(context, &setup_code)?;
std::fs::write(as_str(file_name), file_content)?; std::fs::write(&file_name, file_content)?;
println!( println!(
"Setup message written to: {}\nSetup code: {}", "Setup message written to: {}\nSetup code: {}",
as_str(file_name), file_name.display(),
&setup_code, &setup_code,
); );
free(file_name as *mut libc::c_void);
} }
"poke" => { "poke" => {
ensure!(0 != poke_spec(context, arg1_c), "Poke failed"); ensure!(0 != poke_spec(context, arg1_c), "Poke failed");

52
misc.c
View File

@@ -1,52 +0,0 @@
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include "misc.h"
static char* internal_dc_strdup(const char* s) /* strdup(NULL) is undefined, save_strdup(NULL) returns an empty string in this case */
{
char* ret = NULL;
if (s) {
if ((ret=strdup(s))==NULL) {
exit(16); /* cannot allocate (little) memory, unrecoverable error */
}
}
else {
if ((ret=(char*)calloc(1, 1))==NULL) {
exit(17); /* cannot allocate little memory, unrecoverable error */
}
}
return ret;
}
char* dc_mprintf(const char* format, ...)
{
char testbuf[1];
char* buf = NULL;
int char_cnt_without_zero = 0;
va_list argp;
va_list argp_copy;
va_start(argp, format);
va_copy(argp_copy, argp);
char_cnt_without_zero = vsnprintf(testbuf, 0, format, argp);
va_end(argp);
if (char_cnt_without_zero < 0) {
va_end(argp_copy);
return internal_dc_strdup("ErrFmt");
}
buf = malloc(char_cnt_without_zero+2 /* +1 would be enough, however, protect against off-by-one-errors */);
if (buf==NULL) {
va_end(argp_copy);
return internal_dc_strdup("ErrMem");
}
vsnprintf(buf, char_cnt_without_zero+1, format, argp_copy);
va_end(argp_copy);
return buf;
}

1
misc.h
View File

@@ -1 +0,0 @@
char* dc_mprintf (const char* format, ...); /* The result must be free()'d. */

View File

@@ -101,7 +101,6 @@ pub unsafe fn dc_imex_has_backup(
} }
pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
let mut setup_file_name: *mut libc::c_char = ptr::null_mut();
let mut msg: Message; let mut msg: Message;
if !dc_alloc_ongoing(context) { if !dc_alloc_ongoing(context) {
return std::ptr::null_mut(); return std::ptr::null_mut();
@@ -115,8 +114,7 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
.unwrap() .unwrap()
.shall_stop_ongoing .shall_stop_ongoing
{ {
if let Ok(setup_file_content) = dc_render_setup_file(context, &setup_code) { if let Ok(ref setup_file_content) = dc_render_setup_file(context, &setup_code) {
let setup_file_content_c = CString::yolo(setup_file_content.as_str());
/* encrypting may also take a while ... */ /* encrypting may also take a while ... */
if !context if !context
.running_state .running_state
@@ -125,23 +123,14 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
.unwrap() .unwrap()
.shall_stop_ongoing .shall_stop_ongoing
{ {
setup_file_name = dc_get_fine_pathNfilename( let setup_file_name =
context, dc_get_fine_path_filename(context, "$BLOBDIR", "autocrypt-setup-message.html");
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, if dc_write_file(context, &setup_file_name, setup_file_content.as_bytes()) {
b"autocrypt-setup-message.html\x00" as *const u8 as *const libc::c_char,
);
if !(setup_file_name.is_null()
|| 0 == dc_write_file(
context,
setup_file_name,
setup_file_content_c.as_ptr() as *const libc::c_void,
setup_file_content_c.as_bytes().len(),
))
{
if let Ok(chat_id) = chat::create_by_contact_id(context, 1) { if let Ok(chat_id) = chat::create_by_contact_id(context, 1) {
msg = dc_msg_new_untyped(); msg = dc_msg_new_untyped();
msg.type_0 = Viewtype::File; msg.type_0 = Viewtype::File;
msg.param.set(Param::File, as_str(setup_file_name)); msg.param
.set(Param::File, setup_file_name.to_string_lossy());
msg.param msg.param
.set(Param::MimeType, "application/autocrypt-setup"); .set(Param::MimeType, "application/autocrypt-setup");
@@ -182,7 +171,6 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
} }
} }
} }
free(setup_file_name as *mut libc::c_void);
dc_free_ongoing(context); dc_free_ongoing(context);
setup_code.strdup() setup_code.strdup()
@@ -639,7 +627,7 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
} }
let pathNfilename = context.get_blobdir().join(file_name); let pathNfilename = context.get_blobdir().join(file_name);
if dc_write_file_safe(context, &pathNfilename, &file_blob) { if dc_write_file(context, &pathNfilename, &file_blob) {
continue; continue;
} }
error!( error!(
@@ -686,13 +674,8 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool {
let res = chrono::NaiveDateTime::from_timestamp(now as i64, 0) let res = chrono::NaiveDateTime::from_timestamp(now as i64, 0)
.format("delta-chat-%Y-%m-%d.bak") .format("delta-chat-%Y-%m-%d.bak")
.to_string(); .to_string();
let buffer = CString::yolo(res);
let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer.as_ptr());
if dest_pathNfilename.is_null() {
error!(context, "Cannot get backup file name.",);
return success; let dest_path_filename = dc_get_fine_path_filename(context, as_path(dir), res);
}
sql::housekeeping(context); sql::housekeeping(context);
@@ -703,15 +686,15 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool {
context, context,
"Backup \"{}\" to \"{}\".", "Backup \"{}\" to \"{}\".",
context.get_dbfile().display(), context.get_dbfile().display(),
as_str(dest_pathNfilename), dest_path_filename.display(),
); );
if dc_copy_file(context, context.get_dbfile(), as_path(dest_pathNfilename)) { if dc_copy_file(context, context.get_dbfile(), &dest_path_filename) {
context.sql.open(&context, &context.get_dbfile(), 0); context.sql.open(&context, &context.get_dbfile(), 0);
closed = false; closed = false;
/* add all files as blobs to the database copy (this does not require the source to be locked, neigher the destination as it is used only here) */ /* add all files as blobs to the database copy (this does not require the source to be locked, neigher the destination as it is used only here) */
/*for logging only*/ /*for logging only*/
let sql = Sql::new(); let sql = Sql::new();
if sql.open(context, as_path(dest_pathNfilename), 0) { if sql.open(context, &dest_path_filename, 0) {
if !sql.table_exists("backup_blobs") { if !sql.table_exists("backup_blobs") {
if sql::execute( if sql::execute(
context, context,
@@ -820,9 +803,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool {
.set_config_int(context, "backup_time", now as i32) .set_config_int(context, "backup_time", now as i32)
.is_ok() .is_ok()
{ {
context.call_cb(Event::ImexFileWritten( context.call_cb(Event::ImexFileWritten(dest_path_filename.clone()));
as_path(dest_pathNfilename).to_path_buf(),
));
success = true; success = true;
} }
} }
@@ -840,9 +821,8 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool {
context.sql.open(&context, &context.get_dbfile(), 0); context.sql.open(&context, &context.get_dbfile(), 0);
} }
if 0 != delete_dest_file { if 0 != delete_dest_file {
dc_delete_file(context, as_path(dest_pathNfilename)); dc_delete_file(context, &dest_path_filename);
} }
free(dest_pathNfilename as *mut libc::c_void);
success success
} }
@@ -859,10 +839,8 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
(currently, the last imported key is the standard key unless it contains the string "legacy" in its name) */ (currently, the last imported key is the standard key unless it contains the string "legacy" in its name) */
let mut imported_cnt: libc::c_int = 0; let mut imported_cnt: libc::c_int = 0;
let mut suffix: *mut libc::c_char = ptr::null_mut(); let mut suffix: *mut libc::c_char = ptr::null_mut();
let mut path_plus_name: *mut libc::c_char = ptr::null_mut();
let mut set_default: libc::c_int; let mut set_default: libc::c_int;
let mut buf: *mut libc::c_char = ptr::null_mut(); let mut buf: *mut libc::c_char = ptr::null_mut();
let mut buf_bytes: libc::size_t = 0;
// a pointer inside buf, MUST NOT be free()'d // a pointer inside buf, MUST NOT be free()'d
let mut private_key: *const libc::c_char; let mut private_key: *const libc::c_char;
let mut buf2: *mut libc::c_char = ptr::null_mut(); let mut buf2: *mut libc::c_char = ptr::null_mut();
@@ -885,25 +863,21 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
{ {
continue; continue;
} }
free(path_plus_name as *mut libc::c_void); let path_plus_name = dir.join(entry.file_name());
path_plus_name = dc_mprintf( info!(context, "Checking: {}", path_plus_name.display());
b"%s/%s\x00" as *const u8 as *const libc::c_char,
dir_name, free(buf.cast());
name_c.as_ptr(),
);
info!(context, "Checking: {}", as_str(path_plus_name));
free(buf as *mut libc::c_void);
buf = ptr::null_mut(); buf = ptr::null_mut();
if 0 == dc_read_file(
context, if let Some(buf_r) = dc_read_file_safe(context, &path_plus_name) {
path_plus_name, buf = buf_r.as_ptr() as *mut _;
&mut buf as *mut *mut libc::c_char as *mut *mut libc::c_void, std::mem::forget(buf_r);
&mut buf_bytes, } else {
) || buf_bytes < 50
{
continue; continue;
} };
private_key = buf; private_key = buf;
free(buf2 as *mut libc::c_void); free(buf2 as *mut libc::c_void);
buf2 = dc_strdup(buf); buf2 = dc_strdup(buf);
if dc_split_armored_data( if dc_split_armored_data(
@@ -936,7 +910,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
info!( info!(
context, context,
"Treating \"{}\" as a legacy private key.", "Treating \"{}\" as a legacy private key.",
as_str(path_plus_name), path_plus_name.display(),
); );
set_default = 0i32 set_default = 0i32
} }
@@ -962,7 +936,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
} }
free(suffix as *mut libc::c_void); free(suffix as *mut libc::c_void);
free(path_plus_name as *mut libc::c_void);
free(buf as *mut libc::c_void); free(buf as *mut libc::c_void);
free(buf2 as *mut libc::c_void); free(buf2 as *mut libc::c_void);
@@ -1025,38 +998,31 @@ unsafe fn export_key_to_asc_file(
is_default: libc::c_int, is_default: libc::c_int,
) -> bool { ) -> bool {
let mut success = false; let mut success = false;
let file_name; let dir = as_path(dir);
if 0 != is_default {
file_name = dc_mprintf( let file_name = if 0 != is_default {
b"%s/%s-key-default.asc\x00" as *const u8 as *const libc::c_char, let name = format!(
dir, "{}-key-default.asc",
if key.is_public() { if key.is_public() { "public" } else { "private" },
b"public\x00" as *const u8 as *const libc::c_char );
} else { dir.join(name)
b"private\x00" as *const u8 as *const libc::c_char
},
)
} else { } else {
file_name = dc_mprintf( let name = format!(
b"%s/%s-key-%i.asc\x00" as *const u8 as *const libc::c_char, "{}-key-{}.asc",
dir, if key.is_public() { "public" } else { "private" },
if key.is_public() { id
b"public\x00" as *const u8 as *const libc::c_char );
} else { dir.join(name)
b"private\x00" as *const u8 as *const libc::c_char };
}, info!(context, "Exporting key {}", file_name.display());
id, dc_delete_file(context, &file_name);
)
} if !key.write_asc_to_file(&file_name, context) {
info!(context, "Exporting key {}", as_str(file_name),); error!(context, "Cannot write key to {}", file_name.display());
dc_delete_file(context, as_path(file_name));
if !key.write_asc_to_file(as_path(file_name), context) {
error!(context, "Cannot write key to {}", as_str(file_name),);
} else { } else {
context.call_cb(Event::ImexFileWritten(as_path(file_name).to_path_buf())); context.call_cb(Event::ImexFileWritten(file_name.clone()));
success = true; success = true;
} }
free(file_name as *mut libc::c_void);
success success
} }

View File

@@ -1,4 +1,4 @@
use std::ffi::CString; use std::path::Path;
use std::ptr; use std::ptr;
use chrono::TimeZone; use chrono::TimeZone;
@@ -32,7 +32,7 @@ use crate::x::*;
pub struct dc_mimefactory_t<'a> { pub struct dc_mimefactory_t<'a> {
pub from_addr: *mut libc::c_char, pub from_addr: *mut libc::c_char,
pub from_displayname: *mut libc::c_char, pub from_displayname: *mut libc::c_char,
pub selfstatus: *mut libc::c_char, pub selfstatus: Option<String>,
pub recipients_names: *mut clist, pub recipients_names: *mut clist,
pub recipients_addr: *mut clist, pub recipients_addr: *mut clist,
pub timestamp: i64, pub timestamp: i64,
@@ -57,7 +57,6 @@ impl<'a> Drop for dc_mimefactory_t<'a> {
unsafe { unsafe {
free(self.from_addr as *mut libc::c_void); free(self.from_addr as *mut libc::c_void);
free(self.from_displayname as *mut libc::c_void); free(self.from_displayname as *mut libc::c_void);
free(self.selfstatus as *mut libc::c_void);
free(self.rfc724_mid as *mut libc::c_void); free(self.rfc724_mid as *mut libc::c_void);
if !self.recipients_names.is_null() { if !self.recipients_names.is_null() {
clist_free_content(self.recipients_names); clist_free_content(self.recipients_names);
@@ -95,7 +94,7 @@ pub unsafe fn dc_mimefactory_load_msg(
let mut factory = dc_mimefactory_t { let mut factory = dc_mimefactory_t {
from_addr: ptr::null_mut(), from_addr: ptr::null_mut(),
from_displayname: ptr::null_mut(), from_displayname: ptr::null_mut(),
selfstatus: ptr::null_mut(), selfstatus: None,
recipients_names: clist_new(), recipients_names: clist_new(),
recipients_addr: clist_new(), recipients_addr: clist_new(),
timestamp: 0, timestamp: 0,
@@ -253,14 +252,16 @@ unsafe fn load_from(factory: &mut dc_mimefactory_t) {
.unwrap_or_default() .unwrap_or_default()
.strdup(); .strdup();
factory.selfstatus = context factory.selfstatus = context.sql.get_config(context, "selfstatus");
.sql
.get_config(context, "selfstatus") if factory.selfstatus.is_none() {
.unwrap_or_default() factory.selfstatus = Some(
.strdup(); factory
if factory.selfstatus.is_null() { .context
factory.selfstatus = factory.context.stock_str(StockMessage::StatusLine).strdup(); .stock_str(StockMessage::StatusLine)
}; .to_string(),
);
}
} }
pub unsafe fn dc_mimefactory_load_mdn<'a>( pub unsafe fn dc_mimefactory_load_mdn<'a>(
@@ -283,7 +284,7 @@ pub unsafe fn dc_mimefactory_load_mdn<'a>(
let mut factory = dc_mimefactory_t { let mut factory = dc_mimefactory_t {
from_addr: ptr::null_mut(), from_addr: ptr::null_mut(),
from_displayname: ptr::null_mut(), from_displayname: ptr::null_mut(),
selfstatus: ptr::null_mut(), selfstatus: None,
recipients_names: clist_new(), recipients_names: clist_new(),
recipients_addr: clist_new(), recipients_addr: clist_new(),
timestamp: 0, timestamp: 0,
@@ -342,7 +343,6 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
let mut message: *mut mailmime = ptr::null_mut(); let mut message: *mut mailmime = ptr::null_mut();
let mut message_text: *mut libc::c_char = ptr::null_mut(); let mut message_text: *mut libc::c_char = ptr::null_mut();
let mut message_text2: *mut libc::c_char = ptr::null_mut(); let mut message_text2: *mut libc::c_char = ptr::null_mut();
let mut subject_str: *mut libc::c_char = ptr::null_mut();
let mut afwd_email: libc::c_int = 0; let mut afwd_email: libc::c_int = 0;
let mut col: libc::c_int = 0; let mut col: libc::c_int = 0;
let mut success = false; let mut success = false;
@@ -369,7 +369,7 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
from, from,
mailimf_mailbox_new( mailimf_mailbox_new(
if !factory.from_displayname.is_null() { if !factory.from_displayname.is_null() {
dc_encode_header_words(factory.from_displayname) dc_encode_header_words(as_str(factory.from_displayname))
} else { } else {
ptr::null_mut() ptr::null_mut()
}, },
@@ -403,7 +403,7 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
MAILIMF_ADDRESS_MAILBOX as libc::c_int, MAILIMF_ADDRESS_MAILBOX as libc::c_int,
mailimf_mailbox_new( mailimf_mailbox_new(
if !name.is_null() { if !name.is_null() {
dc_encode_header_words(name) dc_encode_header_words(as_str(name))
} else { } else {
ptr::null_mut() ptr::null_mut()
}, },
@@ -458,17 +458,12 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
.as_ref() .as_ref()
.map(|s| format!("/{}", s)) .map(|s| format!("/{}", s))
.unwrap_or_default(); .unwrap_or_default();
let os_part = CString::new(os_part).expect("String -> CString conversion failed"); let version = get_version_str();
let version = CString::yolo(get_version_str());
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( mailimf_field_new_custom(
strdup(b"X-Mailer\x00" as *const u8 as *const libc::c_char), strdup(b"X-Mailer\x00" as *const u8 as *const libc::c_char),
dc_mprintf( format!("Delta Chat Core {}{}", version, os_part).strdup(),
b"Delta Chat Core %s%s\x00" as *const u8 as *const libc::c_char,
version.as_ptr(),
os_part.as_ptr(),
),
), ),
); );
@@ -497,7 +492,8 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
*********************************************************************/ *********************************************************************/
let chat = factory.chat.as_ref().unwrap(); let chat = factory.chat.as_ref().unwrap();
let mut meta_part: *mut mailmime = ptr::null_mut(); let mut meta_part: *mut mailmime = ptr::null_mut();
let mut placeholdertext: *mut libc::c_char = ptr::null_mut(); let mut placeholdertext = None;
if chat.typ == Chattype::VerifiedGroup { if chat.typ == Chattype::VerifiedGroup {
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
@@ -539,12 +535,11 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
chat.grpid.strdup(), chat.grpid.strdup(),
), ),
); );
let name = CString::yolo(chat.name.as_bytes());
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
mailimf_field_new_custom( mailimf_field_new_custom(
strdup(b"Chat-Group-Name\x00" as *const u8 as *const libc::c_char), strdup(b"Chat-Group-Name\x00" as *const u8 as *const libc::c_char),
dc_encode_header_words(name.as_ptr()), dc_encode_header_words(&chat.name),
), ),
); );
@@ -645,10 +640,12 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
strdup(b"v1\x00" as *const u8 as *const libc::c_char), strdup(b"v1\x00" as *const u8 as *const libc::c_char),
), ),
); );
placeholdertext = factory placeholdertext = Some(
.context factory
.stock_str(StockMessage::AcSetupMsgBody) .context
.strdup(); .stock_str(StockMessage::AcSetupMsgBody)
.to_string(),
);
} }
if command == SystemMessage::SecurejoinMessage { if command == SystemMessage::SecurejoinMessage {
let msg = &factory.msg; let msg = &factory.msg;
@@ -772,78 +769,68 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
imf_fields, imf_fields,
mailimf_field_new_custom( mailimf_field_new_custom(
strdup(b"Chat-Duration\x00" as *const u8 as *const libc::c_char), strdup(b"Chat-Duration\x00" as *const u8 as *const libc::c_char),
dc_mprintf( duration_ms.to_string().strdup(),
b"%i\x00" as *const u8 as *const libc::c_char,
duration_ms as libc::c_int,
),
), ),
); );
} }
} }
afwd_email = factory.msg.param.exists(Param::Forwarded) as libc::c_int; afwd_email = factory.msg.param.exists(Param::Forwarded) as libc::c_int;
let mut fwdhint = ptr::null_mut(); let fwdhint = if 0 != afwd_email {
if 0 != afwd_email { Some(
fwdhint = dc_strdup( "---------- Forwarded message ----------\r\nFrom: Delta Chat\r\n\r\n"
b"---------- Forwarded message ----------\r\nFrom: Delta Chat\r\n\r\n\x00" .to_string(),
as *const u8 as *const libc::c_char,
) )
} } else {
None
};
let final_text = { let final_text = {
if !placeholdertext.is_null() { if let Some(ref text) = placeholdertext {
to_string(placeholdertext) text
} else if let Some(ref text) = factory.msg.text { } else if let Some(ref text) = factory.msg.text {
text.clone() text
} else { } else {
"".into() ""
} }
}; };
let final_text = CString::yolo(final_text);
let footer: *mut libc::c_char = factory.selfstatus; let footer = factory.selfstatus.as_ref();
message_text = dc_mprintf(
b"%s%s%s%s%s\x00" as *const u8 as *const libc::c_char, message_text = format!(
if !fwdhint.is_null() { "{}{}{}{}{}",
fwdhint if let Some(ref hint) = fwdhint {
hint
} else { } else {
b"\x00" as *const u8 as *const libc::c_char ""
}, },
final_text.as_ptr(), &final_text,
if final_text != CString::yolo("") if !final_text.is_empty() && footer.is_some() {
&& !footer.is_null() "\r\n\r\n"
&& 0 != *footer.offset(0isize) as libc::c_int
{
b"\r\n\r\n\x00" as *const u8 as *const libc::c_char
} else { } else {
b"\x00" as *const u8 as *const libc::c_char ""
}, },
if !footer.is_null() && 0 != *footer.offset(0isize) as libc::c_int { if footer.is_some() { "-- \r\n" } else { "" },
b"-- \r\n\x00" as *const u8 as *const libc::c_char if let Some(footer) = footer {
} else {
b"\x00" as *const u8 as *const libc::c_char
},
if !footer.is_null() && 0 != *footer.offset(0isize) as libc::c_int {
footer footer
} else { } else {
b"\x00" as *const u8 as *const libc::c_char ""
}, },
); )
.strdup();
let text_part: *mut mailmime = build_body_text(message_text); let text_part: *mut mailmime = build_body_text(message_text);
mailmime_smart_add_part(message, text_part); mailmime_smart_add_part(message, text_part);
parts += 1; parts += 1;
free(fwdhint as *mut libc::c_void);
free(placeholdertext as *mut libc::c_void);
/* add attachment part */ /* add attachment part */
if chat::msgtype_has_file(factory.msg.type_0) { if chat::msgtype_has_file(factory.msg.type_0) {
if !is_file_size_okay(context, &factory.msg) { if !is_file_size_okay(context, &factory.msg) {
let error: *mut libc::c_char = dc_mprintf( let error = format!(
b"Message exceeds the recommended %i MB.\x00" as *const u8 "Message exceeds the recommended {} MB.",
as *const libc::c_char,
24 * 1024 * 1024 / 4 * 3 / 1000 / 1000, 24 * 1024 * 1024 / 4 * 3 / 1000 / 1000,
); )
.strdup();
set_error(factory, error); set_error(factory, error);
free(error as *mut libc::c_void); free(error.cast());
ok_to_continue = false; ok_to_continue = false;
} else { } else {
let file_part: *mut mailmime = let file_part: *mut mailmime =
@@ -958,15 +945,14 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
message_text = format!("{}\r\n", p2).strdup(); message_text = format!("{}\r\n", p2).strdup();
let human_mime_part: *mut mailmime = build_body_text(message_text); let human_mime_part: *mut mailmime = build_body_text(message_text);
mailmime_add_part(multipart, human_mime_part); mailmime_add_part(multipart, human_mime_part);
let version = CString::yolo(get_version_str()); let version = get_version_str();
message_text2 = message_text2 = format!(
dc_mprintf( "Reporting-UA: Delta Chat {}\r\nOriginal-Recipient: rfc822;{}\r\nFinal-Recipient: rfc822;{}\r\nOriginal-Message-ID: <{}>\r\nDisposition: manual-action/MDN-sent-automatically; displayed\r\n",
b"Reporting-UA: Delta Chat %s\r\nOriginal-Recipient: rfc822;%s\r\nFinal-Recipient: rfc822;%s\r\nOriginal-Message-ID: <%s>\r\nDisposition: manual-action/MDN-sent-automatically; displayed\r\n\x00" version,
as *const u8 as *const libc::c_char, as_str(factory.from_addr),
version.as_ptr(), as_str(factory.from_addr),
factory.from_addr, factory.from_addr, as_str(factory.msg.rfc724_mid)
factory.msg.rfc724_mid ).strdup();
);
let content_type_0: *mut mailmime_content = mailmime_content_new_with_str( let content_type_0: *mut mailmime_content = mailmime_content_new_with_str(
b"message/disposition-notification\x00" as *const u8 as *const libc::c_char, b"message/disposition-notification\x00" as *const u8 as *const libc::c_char,
@@ -986,17 +972,19 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
} }
if ok_to_continue { if ok_to_continue {
if factory.loaded as libc::c_uint == DC_MF_MDN_LOADED as libc::c_int as libc::c_uint { let subject_str = if factory.loaded as libc::c_uint == DC_MF_MDN_LOADED as libc::c_uint
let e = CString::new(factory.context.stock_str(StockMessage::ReadRcpt).as_ref()) {
.unwrap(); let e = factory.context.stock_str(StockMessage::ReadRcpt);
subject_str = dc_mprintf( format!("Chat: {}", e)
b"Chat: %s\x00" as *const u8 as *const libc::c_char,
e.as_ptr(),
);
} else { } else {
subject_str = to_string(get_subject(
get_subject(context, factory.chat.as_ref(), &mut factory.msg, afwd_email) context,
} factory.chat.as_ref(),
&mut factory.msg,
afwd_email,
))
};
subject = mailimf_subject_new(dc_encode_header_words(subject_str)); subject = mailimf_subject_new(dc_encode_header_words(subject_str));
mailimf_fields_add( mailimf_fields_add(
imf_fields, imf_fields,
@@ -1055,7 +1043,6 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
e2ee_helper.thanks(); e2ee_helper.thanks();
free(message_text as *mut libc::c_void); free(message_text as *mut libc::c_void);
free(message_text2 as *mut libc::c_void); free(message_text2 as *mut libc::c_void);
free(subject_str as *mut libc::c_void);
success success
} }
@@ -1073,34 +1060,17 @@ unsafe fn get_subject(
let chat = chat.unwrap(); let chat = chat.unwrap();
let ret: *mut libc::c_char; let ret: *mut libc::c_char;
let raw_subject = { let raw_subject =
dc_msg_get_summarytext_by_raw(msg.type_0, msg.text.as_ref(), &mut msg.param, 32, context) dc_msg_get_summarytext_by_raw(msg.type_0, msg.text.as_ref(), &mut msg.param, 32, context);
.strdup()
};
let fwd = if 0 != afwd_email { let fwd = if 0 != afwd_email { "Fwd: " } else { "" };
b"Fwd: \x00" as *const u8 as *const libc::c_char
} else {
b"\x00" as *const u8 as *const libc::c_char
};
if msg.param.get_cmd() == SystemMessage::AutocryptSetupMessage { if msg.param.get_cmd() == SystemMessage::AutocryptSetupMessage {
ret = context.stock_str(StockMessage::AcSetupMsgSubject).strdup() ret = context.stock_str(StockMessage::AcSetupMsgSubject).strdup()
} else if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup { } else if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup {
ret = format!( ret = format!("Chat: {}: {}{}", chat.name, fwd, raw_subject,).strdup();
"Chat: {}: {}{}",
chat.name,
to_string(fwd),
to_string(raw_subject),
)
.strdup()
} else { } else {
ret = dc_mprintf( ret = format!("Chat: {}{}", fwd, raw_subject).strdup();
b"Chat: %s%s\x00" as *const u8 as *const libc::c_char,
fwd,
raw_subject,
)
} }
free(raw_subject as *mut libc::c_void);
ret ret
} }
@@ -1152,13 +1122,12 @@ unsafe fn build_body_file(
.map(|s| s.strdup()) .map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut()); .unwrap_or_else(|| std::ptr::null_mut());
let mut filename_to_send = ptr::null_mut();
let mut filename_encoded = ptr::null_mut(); let mut filename_encoded = ptr::null_mut();
if let Some(ref path_filename) = path_filename { if let Some(ref path_filename) = path_filename {
let suffix = dc_get_filesuffix_lc(path_filename); let suffix = dc_get_filesuffix_lc(path_filename);
if msg.type_0 == Viewtype::Voice { let filename_to_send = if msg.type_0 == Viewtype::Voice {
let ts = chrono::Utc.timestamp(msg.timestamp_sort as i64, 0); let ts = chrono::Utc.timestamp(msg.timestamp_sort as i64, 0);
let suffix = if !suffix.is_null() { let suffix = if !suffix.is_null() {
@@ -1166,37 +1135,42 @@ unsafe fn build_body_file(
} else { } else {
"dat".into() "dat".into()
}; };
let res = ts ts.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix)) .to_string()
.to_string();
filename_to_send = res.strdup();
} else if msg.type_0 == Viewtype::Audio { } else if msg.type_0 == Viewtype::Audio {
filename_to_send = dc_get_filename(path_filename) Path::new(path_filename)
.file_name()
.map(|c| c.to_string_lossy().to_string())
.unwrap_or_default()
} else if msg.type_0 == Viewtype::Image || msg.type_0 == Viewtype::Gif { } else if msg.type_0 == Viewtype::Image || msg.type_0 == Viewtype::Gif {
if base_name.is_null() { if base_name.is_null() {
base_name = b"image\x00" as *const u8 as *const libc::c_char base_name = b"image\x00" as *const u8 as *const libc::c_char
} }
filename_to_send = dc_mprintf( format!(
b"%s.%s\x00" as *const u8 as *const libc::c_char, "{}.{}",
base_name, as_str(base_name),
if !suffix.is_null() { if !suffix.is_null() {
suffix as_str(suffix)
} else { } else {
b"dat\x00" as *const u8 as *const libc::c_char "dat"
}, },
) )
} else if msg.type_0 == Viewtype::Video { } else if msg.type_0 == Viewtype::Video {
filename_to_send = dc_mprintf( format!(
b"video.%s\x00" as *const u8 as *const libc::c_char, "video.{}",
if !suffix.is_null() { if !suffix.is_null() {
suffix as_str(suffix)
} else { } else {
b"dat\x00" as *const u8 as *const libc::c_char "dat"
}, },
) )
} else { } else {
filename_to_send = dc_get_filename(path_filename) Path::new(path_filename)
} .file_name()
.map(|c| c.to_string_lossy().to_string())
.unwrap_or_default()
};
if mimetype.is_null() { if mimetype.is_null() {
if suffix.is_null() { if suffix.is_null() {
mimetype = mimetype =
@@ -1219,13 +1193,13 @@ unsafe fn build_body_file(
/* create mime part, for Content-Disposition, see RFC 2183. /* create mime part, for Content-Disposition, see RFC 2183.
`Content-Disposition: attachment` seems not to make a difference to `Content-Disposition: inline` at least on tested Thunderbird and Gma'l in 2017. `Content-Disposition: attachment` seems not to make a difference to `Content-Disposition: inline` at least on tested Thunderbird and Gma'l in 2017.
But I've heard about problems with inline and outl'k, so we just use the attachment-type until we run into other problems ... */ But I've heard about problems with inline and outl'k, so we just use the attachment-type until we run into other problems ... */
needs_ext = dc_needs_ext_header(as_str(filename_to_send)); needs_ext = dc_needs_ext_header(&filename_to_send);
mime_fields = mailmime_fields_new_filename( mime_fields = mailmime_fields_new_filename(
MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int, MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int,
if needs_ext { if needs_ext {
ptr::null_mut() ptr::null_mut()
} else { } else {
dc_strdup(filename_to_send) filename_to_send.strdup()
}, },
MAILMIME_MECHANISM_BASE64 as libc::c_int, MAILMIME_MECHANISM_BASE64 as libc::c_int,
); );
@@ -1256,7 +1230,7 @@ unsafe fn build_body_file(
strdup( strdup(
b"filename*\x00" as *const u8 as *const libc::c_char, b"filename*\x00" as *const u8 as *const libc::c_char,
), ),
dc_encode_ext_header(as_str(filename_to_send)).strdup(), dc_encode_ext_header(&filename_to_send).strdup(),
), ),
); );
if !parm.is_null() { if !parm.is_null() {
@@ -1278,7 +1252,7 @@ unsafe fn build_body_file(
} }
} }
content = mailmime_content_new_with_str(mimetype); content = mailmime_content_new_with_str(mimetype);
filename_encoded = dc_encode_header_words(filename_to_send); filename_encoded = dc_encode_header_words(&filename_to_send);
clist_insert_after( clist_insert_after(
(*content).ct_parameters, (*content).ct_parameters,
(*(*content).ct_parameters).last, (*(*content).ct_parameters).last,
@@ -1293,13 +1267,12 @@ unsafe fn build_body_file(
.unwrap(); .unwrap();
mailmime_set_body_file(mime_sub, dc_strdup(abs_path.as_ptr())); mailmime_set_body_file(mime_sub, dc_strdup(abs_path.as_ptr()));
if !ret_file_name_as_sent.is_null() { if !ret_file_name_as_sent.is_null() {
*ret_file_name_as_sent = dc_strdup(filename_to_send) *ret_file_name_as_sent = filename_to_send.strdup();
} }
} }
} }
free(mimetype as *mut libc::c_void); free(mimetype as *mut libc::c_void);
free(filename_to_send as *mut libc::c_void);
free(filename_encoded as *mut libc::c_void); free(filename_encoded as *mut libc::c_void);
mime_sub mime_sub

View File

@@ -207,18 +207,14 @@ impl<'a> MimeParser<'a> {
.trim(); .trim();
if !subj.is_empty() { if !subj.is_empty() {
let subj_c = CString::yolo(subj);
for part in self.parts.iter_mut() { for part in self.parts.iter_mut() {
if part.typ == Viewtype::Text { if part.typ == Viewtype::Text {
let msg_c = part.msg.as_ref().unwrap().strdup(); let new_txt = format!(
let new_txt: *mut libc::c_char = dc_mprintf( "{} {}",
b"%s \xe2\x80\x93 %s\x00" as *const u8 as *const libc::c_char, subj,
subj_c.as_ptr(), part.msg.as_ref().expect("missing msg part")
msg_c,
); );
free(msg_c.cast()); part.msg = Some(new_txt);
part.msg = Some(to_string_lossy(new_txt));
free(new_txt.cast());
break; break;
} }
} }
@@ -311,7 +307,7 @@ impl<'a> MimeParser<'a> {
self.parts.iter_mut().rev().find(|part| !part.is_meta) self.parts.iter_mut().rev().find(|part| !part.is_meta)
} }
/* the following functions can be used only after a call to dc_mimeparser_parse() */ /* the following functions can be used only after a call to parse() */
pub fn lookup_field(&self, field_name: &str) -> Option<*mut mailimf_field> { pub fn lookup_field(&self, field_name: &str) -> Option<*mut mailimf_field> {
match self.header.get(field_name) { match self.header.get(field_name) {
@@ -805,10 +801,11 @@ impl<'a> MimeParser<'a> {
if !(*mime).mm_content_type.is_null() if !(*mime).mm_content_type.is_null()
&& !(*(*mime).mm_content_type).ct_subtype.is_null() && !(*(*mime).mm_content_type).ct_subtype.is_null()
{ {
desired_filename = dc_mprintf( desired_filename = format!(
b"file.%s\x00" as *const u8 as *const libc::c_char, "file.{}",
(*(*mime).mm_content_type).ct_subtype, as_str((*(*mime).mm_content_type).ct_subtype)
); )
.strdup();
} else { } else {
ok_to_continue = false; ok_to_continue = false;
} }
@@ -896,44 +893,32 @@ impl<'a> MimeParser<'a> {
desired_filename: *const libc::c_char, desired_filename: *const libc::c_char,
) { ) {
/* create a free file name to use */ /* create a free file name to use */
let path_n_filename = dc_get_fine_pathNfilename( let path_filename =
self.context, dc_get_fine_path_filename(self.context, "$BLOBDIR", as_str(desired_filename));
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, let bytes = std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes);
desired_filename,
);
if !path_n_filename.is_null() {
/* copy data to file */
if dc_write_file(
self.context,
path_n_filename,
decoded_data as *const libc::c_void,
decoded_data_bytes,
) != 0
{
let mut part = Part::default();
part.typ = msg_type;
part.mimetype = mime_type;
part.bytes = decoded_data_bytes as libc::c_int;
part.param.set(Param::File, as_str(path_n_filename));
part.param.set(Param::MimeType, raw_mime);
if mime_type == 80 { /* copy data to file */
assert!(!decoded_data.is_null(), "invalid image data"); if dc_write_file(self.context, &path_filename, bytes) {
let data = std::slice::from_raw_parts( let mut part = Part::default();
decoded_data as *const u8, part.typ = msg_type;
decoded_data_bytes as usize, part.mimetype = mime_type;
); part.bytes = decoded_data_bytes as libc::c_int;
part.param.set(Param::File, path_filename.to_string_lossy());
part.param.set(Param::MimeType, raw_mime);
if mime_type == 80 {
assert!(!decoded_data.is_null(), "invalid image data");
let data = std::slice::from_raw_parts(
decoded_data as *const u8,
decoded_data_bytes as usize,
);
if let Ok((width, height)) = dc_get_filemeta(data) { if let Ok((width, height)) = dc_get_filemeta(data) {
part.param.set_int(Param::Width, width as i32); part.param.set_int(Param::Width, width as i32);
part.param.set_int(Param::Height, height as i32); part.param.set_int(Param::Height, height as i32);
}
} }
self.do_add_single_part(part);
} }
self.do_add_single_part(part);
} }
free(path_n_filename as *mut libc::c_void);
} }
fn do_add_single_part(&mut self, mut part: Part) { fn do_add_single_part(&mut self, mut part: Part) {

View File

@@ -308,14 +308,10 @@ unsafe fn add_parts(
let mut rcvd_timestamp = 0; let mut rcvd_timestamp = 0;
let mut mime_in_reply_to = std::ptr::null_mut(); let mut mime_in_reply_to = std::ptr::null_mut();
let mut mime_references = std::ptr::null_mut(); let mut mime_references = std::ptr::null_mut();
let mut txt_raw = std::ptr::null_mut();
let cleanup = |mime_in_reply_to: *mut libc::c_char, let cleanup = |mime_in_reply_to: *mut libc::c_char, mime_references: *mut libc::c_char| {
mime_references: *mut libc::c_char,
txt_raw: *mut libc::c_char| {
free(mime_in_reply_to.cast()); free(mime_in_reply_to.cast());
free(mime_references.cast()); free(mime_references.cast());
free(txt_raw.cast());
}; };
// collect the rest information, CC: is added to the to-list, BCC: is ignored // collect the rest information, CC: is added to the to-list, BCC: is ignored
@@ -354,7 +350,7 @@ unsafe fn add_parts(
if rfc724_mid.is_null() { if rfc724_mid.is_null() {
rfc724_mid = dc_create_incoming_rfc724_mid(*sent_timestamp, *from_id, to_ids); rfc724_mid = dc_create_incoming_rfc724_mid(*sent_timestamp, *from_id, to_ids);
if rfc724_mid.is_null() { if rfc724_mid.is_null() {
cleanup(mime_in_reply_to, mime_references, txt_raw); cleanup(mime_in_reply_to, mime_references);
bail!("Cannot create Message-ID"); bail!("Cannot create Message-ID");
} }
} }
@@ -376,7 +372,7 @@ unsafe fn add_parts(
} }
free(old_server_folder.cast()); free(old_server_folder.cast());
cleanup(mime_in_reply_to, mime_references, txt_raw); cleanup(mime_in_reply_to, mime_references);
bail!("Message already in DB"); bail!("Message already in DB");
} }
@@ -631,6 +627,8 @@ unsafe fn add_parts(
// into only one message; mails sent by other clients may result in several messages // into only one message; mails sent by other clients may result in several messages
// (eg. one per attachment)) // (eg. one per attachment))
let icnt = mime_parser.parts.len(); let icnt = mime_parser.parts.len();
let mut txt_raw = None;
let is_ok = context let is_ok = context
.sql .sql
.prepare( .prepare(
@@ -658,20 +656,13 @@ unsafe fn add_parts(
} }
} }
if part.typ == Viewtype::Text { if part.typ == Viewtype::Text {
let msg_raw = let msg_raw = part.msg_raw.as_ref().cloned().unwrap_or_default();
CString::yolo(part.msg_raw.as_ref().cloned().unwrap_or_default()); let subject = mime_parser
let subject_c = CString::yolo( .subject
mime_parser .as_ref()
.subject .map(|s| s.to_string())
.as_ref() .unwrap_or("".into());
.map(|s| s.to_string()) txt_raw = Some(format!("{}\n\n{}", subject, msg_raw));
.unwrap_or("".into()),
);
txt_raw = dc_mprintf(
b"%s\n\n%s\x00" as *const u8 as *const libc::c_char,
subject_c.as_ptr(),
msg_raw.as_ptr(),
)
} }
if mime_parser.is_system_message != SystemMessage::Unknown { if mime_parser.is_system_message != SystemMessage::Unknown {
part.param part.param
@@ -693,11 +684,7 @@ unsafe fn add_parts(
msgrmsg, msgrmsg,
part.msg.as_ref().map_or("", String::as_str), part.msg.as_ref().map_or("", String::as_str),
// txt_raw might contain invalid utf8 // txt_raw might contain invalid utf8
if !txt_raw.is_null() { txt_raw.unwrap_or_default(),
to_string_lossy(txt_raw)
} else {
String::new()
},
part.param.to_string(), part.param.to_string(),
part.bytes, part.bytes,
*hidden, *hidden,
@@ -716,8 +703,7 @@ unsafe fn add_parts(
to_string(mime_references), to_string(mime_references),
])?; ])?;
free(txt_raw as *mut libc::c_void); txt_raw = None;
txt_raw = ptr::null_mut();
*insert_msg_id = sql::get_rowid_with_conn( *insert_msg_id = sql::get_rowid_with_conn(
context, context,
conn, conn,
@@ -734,7 +720,7 @@ unsafe fn add_parts(
if !is_ok { if !is_ok {
// i/o error - there is nothing more we can do - in other cases, we try to write at least an empty record // i/o error - there is nothing more we can do - in other cases, we try to write at least an empty record
cleanup(mime_in_reply_to, mime_references, txt_raw); cleanup(mime_in_reply_to, mime_references);
bail!("Cannot write DB."); bail!("Cannot write DB.");
} }
@@ -757,7 +743,7 @@ unsafe fn add_parts(
} }
context.do_heuristics_moves(server_folder.as_ref(), *insert_msg_id); context.do_heuristics_moves(server_folder.as_ref(), *insert_msg_id);
cleanup(mime_in_reply_to, mime_references, txt_raw); cleanup(mime_in_reply_to, mime_references);
Ok(()) Ok(())
} }

View File

@@ -25,12 +25,15 @@ use crate::x::*;
* @return Returns the encoded string which must be free()'d when no longed needed. * @return Returns the encoded string which must be free()'d when no longed needed.
* On errors, NULL is returned. * On errors, NULL is returned.
*/ */
pub unsafe fn dc_encode_header_words(to_encode: *const libc::c_char) -> *mut libc::c_char { pub unsafe fn dc_encode_header_words(to_encode_r: impl AsRef<str>) -> *mut libc::c_char {
let to_encode =
CString::new(to_encode_r.as_ref().as_bytes()).expect("invalid cstring to_encode");
let mut ok_to_continue = true; let mut ok_to_continue = true;
let mut ret_str: *mut libc::c_char = ptr::null_mut(); let mut ret_str: *mut libc::c_char = ptr::null_mut();
let mut cur: *const libc::c_char = to_encode; let mut cur: *const libc::c_char = to_encode.as_ptr();
let mmapstr: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char); let mmapstr: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
if to_encode.is_null() || mmapstr.is_null() { if mmapstr.is_null() {
ok_to_continue = false; ok_to_continue = false;
} }
loop { loop {
@@ -355,12 +358,13 @@ mod tests {
assert_eq!(CStr::from_ptr(buf1).to_str().unwrap(), "just ascii test"); assert_eq!(CStr::from_ptr(buf1).to_str().unwrap(), "just ascii test");
free(buf1 as *mut libc::c_void); free(buf1 as *mut libc::c_void);
buf1 = dc_encode_header_words(b"abcdef\x00" as *const u8 as *const libc::c_char); buf1 = dc_encode_header_words("abcdef");
assert_eq!(CStr::from_ptr(buf1).to_str().unwrap(), "abcdef"); assert_eq!(CStr::from_ptr(buf1).to_str().unwrap(), "abcdef");
free(buf1 as *mut libc::c_void); free(buf1 as *mut libc::c_void);
buf1 = dc_encode_header_words( buf1 = dc_encode_header_words(
b"test\xc3\xa4\xc3\xb6\xc3\xbc.txt\x00" as *const u8 as *const libc::c_char, std::string::String::from_utf8(b"test\xc3\xa4\xc3\xb6\xc3\xbc.txt".to_vec())
.unwrap(),
); );
assert_eq!( assert_eq!(
strncmp(buf1, b"=?utf-8\x00" as *const u8 as *const libc::c_char, 7), strncmp(buf1, b"=?utf-8\x00" as *const u8 as *const libc::c_char, 7),

View File

@@ -1,12 +1,14 @@
//! Some tools and enhancements to the used libraries, there should be
//! no references to Context and other "larger" entities here.
use std::borrow::Cow; use std::borrow::Cow;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString, OsString};
use std::path::Path; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use std::time::SystemTime; use std::time::SystemTime;
use std::{fmt, fs, ptr}; use std::{fmt, fs, ptr};
use chrono::{Local, TimeZone}; use chrono::{Local, TimeZone};
use itertools::max;
use libc::uintptr_t; use libc::uintptr_t;
use mmime::clist::*; use mmime::clist::*;
use mmime::mailimf_types::*; use mmime::mailimf_types::*;
@@ -16,10 +18,6 @@ use crate::context::Context;
use crate::error::Error; use crate::error::Error;
use crate::x::*; use crate::x::*;
/* Some tools and enhancements to the used libraries, there should be
no references to Context and other "larger" classes here. */
/* ** library-private **********************************************************/
/* math tools */
pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool { pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
0 != v && 0 == v & (v - 1) 0 != v && 0 == v & (v - 1)
} }
@@ -570,7 +568,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 unsafe fn dc_create_incoming_rfc724_mid( pub 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>,
@@ -579,51 +577,36 @@ pub unsafe fn dc_create_incoming_rfc724_mid(
return ptr::null_mut(); return ptr::null_mut();
} }
/* find out the largest receiver ID (we could also take the smallest, but it should be unique) */ /* find out the largest receiver ID (we could also take the smallest, but it should be unique) */
let largest_id_to = max(contact_ids_to.iter()); let largest_id_to = contact_ids_to.iter().max().copied().unwrap_or_default();
dc_mprintf( let result = format!(
b"%lu-%lu-%lu@stub\x00" as *const u8 as *const libc::c_char, "{}-{}-{}@stub",
message_timestamp as libc::c_ulong, message_timestamp, contact_id_from, largest_id_to
contact_id_from as libc::c_ulong, );
*largest_id_to.unwrap() as libc::c_ulong,
) unsafe { result.strdup() }
} }
/// Function generates a Message-ID that can be used for a new outgoing message.
/// - this function is called for all outgoing messages.
/// - the message ID should be globally unique
/// - do not add a counter or any private data as as this may give unneeded information to the receiver
pub unsafe fn dc_create_outgoing_rfc724_mid( pub unsafe fn dc_create_outgoing_rfc724_mid(
grpid: *const libc::c_char, grpid: *const libc::c_char,
from_addr: *const libc::c_char, from_addr: *const libc::c_char,
) -> *mut libc::c_char { ) -> *mut libc::c_char {
/* Function generates a Message-ID that can be used for a new outgoing message. let rand2 = dc_create_id();
- this function is called for all outgoing messages.
- the message ID should be globally unique
- do not add a counter or any private data as as this may give unneeded information to the receiver */
let mut rand1: *mut libc::c_char = ptr::null_mut();
let rand2: *mut libc::c_char = dc_create_id().strdup();
let ret: *mut libc::c_char;
let mut at_hostname: *const libc::c_char = strchr(from_addr, '@' as i32);
if at_hostname.is_null() {
at_hostname = b"@nohost\x00" as *const u8 as *const libc::c_char
}
if !grpid.is_null() {
ret = dc_mprintf(
b"Gr.%s.%s%s\x00" as *const u8 as *const libc::c_char,
grpid,
rand2,
at_hostname,
)
} else {
rand1 = dc_create_id().strdup();
ret = dc_mprintf(
b"Mr.%s.%s%s\x00" as *const u8 as *const libc::c_char,
rand1,
rand2,
at_hostname,
)
}
free(rand1 as *mut libc::c_void);
free(rand2 as *mut libc::c_void);
ret let at_hostname = as_opt_str(strchr(from_addr, '@' as i32)).unwrap_or_else(|| "@nohost");
let ret = if !grpid.is_null() {
format!("Gr.{}.{}{}", as_str(grpid), rand2, at_hostname,)
} else {
let rand1 = dc_create_id();
format!("Mr.{}.{}{}", rand1, rand2, at_hostname)
};
ret.strdup()
} }
/// Generate globally-unique message-id for a new outgoing message. /// Generate globally-unique message-id for a new outgoing message.
@@ -696,16 +679,6 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut
ptr::null_mut() ptr::null_mut()
} }
#[allow(non_snake_case)]
unsafe fn dc_ensure_no_slash(pathNfilename: *mut libc::c_char) {
let path_len = strlen(pathNfilename);
if path_len > 0 && *pathNfilename.add(path_len - 1) as libc::c_int == '/' as i32
|| *pathNfilename.add(path_len - 1) as libc::c_int == '\\' as i32
{
*pathNfilename.add(path_len - 1) = 0 as libc::c_char;
}
}
pub fn dc_ensure_no_slash_safe(path: &str) -> &str { pub 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];
@@ -713,18 +686,12 @@ pub fn dc_ensure_no_slash_safe(path: &str) -> &str {
path path
} }
unsafe fn dc_validate_filename(filename: *mut libc::c_char) { /// Function modifies the given buffer and replaces all characters not valid in filenames by a "-".
/* function modifies the given buffer and replaces all characters not valid in filenames by a "-" */ fn validate_filename(filename: &str) -> String {
let mut p1: *mut libc::c_char = filename; filename
while 0 != *p1 { .replace('/', "-")
if *p1 as libc::c_int == '/' as i32 .replace('\\', "-")
|| *p1 as libc::c_int == '\\' as i32 .replace(':', "-")
|| *p1 as libc::c_int == ':' as i32
{
*p1 = '-' as i32 as libc::c_char
}
p1 = p1.offset(1isize)
}
} }
pub unsafe fn dc_get_filename(path_filename: impl AsRef<str>) -> *mut libc::c_char { pub unsafe fn dc_get_filename(path_filename: impl AsRef<str>) -> *mut libc::c_char {
@@ -735,42 +702,6 @@ pub unsafe fn dc_get_filename(path_filename: impl AsRef<str>) -> *mut libc::c_ch
} }
} }
// the case of the suffix is preserved
#[allow(non_snake_case)]
unsafe fn dc_split_filename(
pathNfilename: *const libc::c_char,
ret_basename: *mut *mut libc::c_char,
ret_all_suffixes_incl_dot: *mut *mut libc::c_char,
) {
if pathNfilename.is_null() {
return;
}
/* splits a filename into basename and all suffixes, eg. "/path/foo.tar.gz" is split into "foo.tar" and ".gz",
(we use the _last_ dot which allows the usage inside the filename which are very usual;
maybe the detection could be more intelligent, however, for the moment, it is just file)
- if there is no suffix, the returned suffix string is empty, eg. "/path/foobar" is split into "foobar" and ""
- the case of the returned suffix is preserved; this is to allow reconstruction of (similar) names */
let basename: *mut libc::c_char = dc_get_filename(as_str(pathNfilename));
let suffix: *mut libc::c_char;
let p1: *mut libc::c_char = strrchr(basename, '.' as i32);
if !p1.is_null() {
suffix = dc_strdup(p1);
*p1 = 0 as libc::c_char
} else {
suffix = dc_strdup(ptr::null())
}
if !ret_basename.is_null() {
*ret_basename = basename
} else {
free(basename as *mut libc::c_void);
}
if !ret_all_suffixes_incl_dot.is_null() {
*ret_all_suffixes_incl_dot = suffix
} else {
free(suffix as *mut libc::c_void);
};
}
// 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 {
@@ -876,23 +807,8 @@ pub fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Path>) ->
} }
} }
#[allow(non_snake_case)] /// Write a the given content to provied file path.
pub unsafe fn dc_write_file( pub fn dc_write_file(context: &Context, path: impl AsRef<Path>, buf: &[u8]) -> bool {
context: &Context,
pathNfilename: *const libc::c_char,
buf: *const libc::c_void,
buf_bytes: libc::size_t,
) -> libc::c_int {
let bytes = std::slice::from_raw_parts(buf as *const u8, buf_bytes);
dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int
}
pub fn dc_write_file_safe<P: AsRef<std::path::Path>>(
context: &Context,
path: P,
buf: &[u8],
) -> bool {
let path_abs = dc_get_abs_path(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!(
@@ -942,58 +858,48 @@ pub fn dc_read_file_safe<P: AsRef<std::path::Path>>(context: &Context, path: P)
} }
} }
#[allow(non_snake_case)] pub fn dc_get_fine_path_filename(
pub unsafe fn dc_get_fine_pathNfilename(
context: &Context, context: &Context,
pathNfolder: *const libc::c_char, folder: impl AsRef<Path>,
desired_filenameNsuffix__: *const libc::c_char, desired_filename_suffix: impl AsRef<str>,
) -> *mut libc::c_char { ) -> PathBuf {
let mut ret: *mut libc::c_char = ptr::null_mut();
let pathNfolder_wo_slash: *mut libc::c_char;
let filenameNsuffix: *mut libc::c_char;
let mut basename: *mut libc::c_char = ptr::null_mut();
let mut dotNSuffix: *mut libc::c_char = ptr::null_mut();
let now = time(); let now = time();
pathNfolder_wo_slash = dc_strdup(pathNfolder); let folder = PathBuf::from(folder.as_ref());
dc_ensure_no_slash(pathNfolder_wo_slash); let suffix = validate_filename(desired_filename_suffix.as_ref());
filenameNsuffix = dc_strdup(desired_filenameNsuffix__);
dc_validate_filename(filenameNsuffix);
dc_split_filename(filenameNsuffix, &mut basename, &mut dotNSuffix);
for i in 0..1000i64 { let file_name = PathBuf::from(suffix);
/*no deadlocks, please*/ let extension = file_name.extension().map(|c| c.clone());
if 0 != i {
let idx = if i < 100 { i } else { now + i }; for i in 0..100_000 {
ret = dc_mprintf( let ret = if i == 0 {
b"%s/%s-%lu%s\x00" as *const u8 as *const libc::c_char, let mut folder = folder.clone();
pathNfolder_wo_slash, folder.push(&file_name);
basename, folder
idx as libc::c_ulong,
dotNSuffix,
)
} else { } else {
ret = dc_mprintf( let idx = if i < 100 { i } else { now + i };
b"%s/%s%s\x00" as *const u8 as *const libc::c_char, let file_name = if let Some(stem) = file_name.file_stem() {
pathNfolder_wo_slash, let mut stem = stem.to_os_string();
basename, stem.push(format!("-{}", idx));
dotNSuffix, stem
) } else {
OsString::from(idx.to_string())
};
let mut folder = folder.clone();
folder.push(file_name);
if let Some(ext) = extension {
folder.set_extension(&ext);
}
folder
};
if !dc_file_exist(context, &ret) {
// fine filename found
return ret;
} }
if !dc_file_exist(context, as_path(ret)) {
/* fine filename found */
break;
}
free(ret as *mut libc::c_void);
ret = ptr::null_mut();
} }
free(filenameNsuffix as *mut libc::c_void); panic!("Something is really wrong, you need to clean up your disk");
free(basename as *mut libc::c_void);
free(dotNSuffix as *mut libc::c_void);
free(pathNfolder_wo_slash as *mut libc::c_void);
ret
} }
pub fn dc_is_blobdir_path(context: &Context, path: impl AsRef<str>) -> bool { pub fn dc_is_blobdir_path(context: &Context, path: impl AsRef<str>) -> bool {
@@ -1017,38 +923,18 @@ fn dc_make_rel_path(context: &Context, path: &mut String) {
} }
pub fn dc_make_rel_and_copy(context: &Context, path: &mut String) -> bool { pub fn dc_make_rel_and_copy(context: &Context, path: &mut String) -> bool {
let mut success = false;
let mut filename = ptr::null_mut();
let mut blobdir_path = ptr::null_mut();
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);
success = true; return true;
} else {
filename = unsafe { dc_get_filename(&path) };
if !(filename.is_null()
|| {
blobdir_path = unsafe {
dc_get_fine_pathNfilename(
context,
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
filename,
)
};
blobdir_path.is_null()
}
|| !dc_copy_file(context, &path, as_path(blobdir_path)))
{
*path = to_string(blobdir_path);
blobdir_path = ptr::null_mut();
dc_make_rel_path(context, path);
success = true;
}
} }
unsafe { let blobdir_path = dc_get_fine_path_filename(context, "$BLOBDIR", &path);
free(blobdir_path.cast()); if dc_copy_file(context, &path, &blobdir_path) {
free(filename.cast()); *path = blobdir_path.to_string_lossy().to_string();
dc_make_rel_path(context, path);
return true;
} }
success
false
} }
/// Error type for the [OsStrExt] trait /// Error type for the [OsStrExt] trait
@@ -1923,4 +1809,14 @@ mod tests {
} }
} }
} }
#[test]
fn test_dc_create_incoming_rfc724_mid() {
let res = dc_create_incoming_rfc724_mid(123, 45, &vec![6, 7]);
assert_eq!(as_str(res), "123-45-7@stub");
unsafe {
free(res.cast());
}
}
} }

View File

@@ -998,38 +998,23 @@ fn send_mdn(context: &Context, msg_id: u32) {
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_t) -> libc::c_int { fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_t) -> libc::c_int {
let pathNfilename: *mut libc::c_char;
let mut success: libc::c_int = 0i32; let mut success: libc::c_int = 0i32;
let mut recipients: *mut libc::c_char = ptr::null_mut(); let mut recipients: *mut libc::c_char = ptr::null_mut();
let mut param = Params::new(); let mut param = Params::new();
pathNfilename = unsafe { let path_filename =
dc_get_fine_pathNfilename( dc_get_fine_path_filename(context, "$BLOBDIR", as_str(mimefactory.rfc724_mid));
context, let bytes = unsafe {
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, std::slice::from_raw_parts(
mimefactory.rfc724_mid, (*mimefactory.out).str_0 as *const u8,
(*mimefactory.out).len,
) )
}; };
if pathNfilename.is_null() { if !dc_write_file(context, &path_filename, bytes) {
error!(
context,
"Could not find free file name for message with ID <{}>.",
to_string(mimefactory.rfc724_mid),
);
} else if 0
== unsafe {
dc_write_file(
context,
pathNfilename,
(*mimefactory.out).str_0 as *const libc::c_void,
(*mimefactory.out).len,
)
}
{
error!( error!(
context, context,
"Could not write message <{}> to \"{}\".", "Could not write message <{}> to \"{}\".",
to_string(mimefactory.rfc724_mid), to_string(mimefactory.rfc724_mid),
as_str(pathNfilename), path_filename.display(),
); );
} else { } else {
recipients = unsafe { recipients = unsafe {
@@ -1038,7 +1023,7 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_
b"\x1e\x00" as *const u8 as *const libc::c_char, b"\x1e\x00" as *const u8 as *const libc::c_char,
) )
}; };
param.set(Param::File, as_str(pathNfilename)); param.set(Param::File, path_filename.to_string_lossy());
param.set(Param::Recipients, as_str(recipients)); param.set(Param::Recipients, as_str(recipients));
job_add( job_add(
context, context,
@@ -1057,7 +1042,6 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_
} }
unsafe { unsafe {
free(recipients.cast()); free(recipients.cast());
free(pathNfilename.cast());
} }
success success
} }

View File

@@ -218,7 +218,7 @@ impl Key {
pub fn write_asc_to_file(&self, file: impl AsRef<Path>, context: &Context) -> bool { pub fn write_asc_to_file(&self, file: impl AsRef<Path>, context: &Context) -> bool {
let file_content = self.to_asc(None).into_bytes(); let file_content = self.to_asc(None).into_bytes();
if dc_write_file_safe(context, &file, &file_content) { if dc_write_file(context, &file, &file_content) {
return true; return true;
} else { } else {
error!(context, "Cannot write key to {}", file.as_ref().display()); error!(context, "Cannot write key to {}", file.as_ref().display());

View File

@@ -33,13 +33,6 @@ pub fn strndup(s: *const libc::c_char, n: libc::c_ulong) -> *mut libc::c_char {
} }
} }
extern "C" {
pub fn clock() -> libc::clock_t;
// -- DC Methods
pub fn dc_mprintf(format: *const libc::c_char, _: ...) -> *mut libc::c_char;
}
pub(crate) unsafe fn strcasecmp(s1: *const libc::c_char, s2: *const libc::c_char) -> libc::c_int { 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) let s1 = std::ffi::CStr::from_ptr(s1)
.to_string_lossy() .to_string_lossy()

View File

@@ -1,6 +1,7 @@
//! 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 tempfile::{tempdir, TempDir};
@@ -39,15 +40,10 @@ unsafe fn stress_functions(context: &Context) {
dc_delete_file(context, "$BLOBDIR/foobar.dadada"); dc_delete_file(context, "$BLOBDIR/foobar.dadada");
dc_delete_file(context, "$BLOBDIR/foobar-folder"); dc_delete_file(context, "$BLOBDIR/foobar-folder");
} }
dc_write_file( assert!(dc_write_file(context, "$BLOBDIR/foobar", b"content"));
context,
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
b"content\x00" as *const u8 as *const libc::c_char as *const libc::c_void,
7,
);
assert!(dc_file_exist(context, "$BLOBDIR/foobar",)); assert!(dc_file_exist(context, "$BLOBDIR/foobar",));
assert!(!dc_file_exist(context, "$BLOBDIR/foobarx")); assert!(!dc_file_exist(context, "$BLOBDIR/foobarx"));
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/foobar",), 7); assert_eq!(dc_get_filebytes(context, "$BLOBDIR/foobar"), 7);
let abs_path = context let abs_path = context
.get_blobdir() .get_blobdir()
@@ -87,41 +83,14 @@ unsafe fn stress_functions(context: &Context) {
assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder")); assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder"));
assert!(dc_file_exist(context, "$BLOBDIR/foobar-folder",)); assert!(dc_file_exist(context, "$BLOBDIR/foobar-folder",));
assert!(!dc_delete_file(context, "$BLOBDIR/foobar-folder")); assert!(!dc_delete_file(context, "$BLOBDIR/foobar-folder"));
let fn0: *mut libc::c_char = dc_get_fine_pathNfilename( let fn0 = dc_get_fine_path_filename(context, "$BLOBDIR", "foobar.dadada");
context, assert_eq!(fn0, PathBuf::from("$BLOBDIR/foobar.dadada"));
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
b"foobar.dadada\x00" as *const u8 as *const libc::c_char, assert!(dc_write_file(context, &fn0, b"content"));
); let fn1 = dc_get_fine_path_filename(context, "$BLOBDIR", "foobar.dadada");
assert!(!fn0.is_null()); assert_eq!(fn1, PathBuf::from("$BLOBDIR/foobar-1.dadada"));
assert_eq!(
strcmp( assert!(dc_delete_file(context, &fn0));
fn0,
b"$BLOBDIR/foobar.dadada\x00" as *const u8 as *const libc::c_char,
),
0
);
dc_write_file(
context,
fn0,
b"content\x00" as *const u8 as *const libc::c_char as *const libc::c_void,
7,
);
let fn1: *mut libc::c_char = dc_get_fine_pathNfilename(
context,
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
b"foobar.dadada\x00" as *const u8 as *const libc::c_char,
);
assert!(!fn1.is_null());
assert_eq!(
strcmp(
fn1,
b"$BLOBDIR/foobar-1.dadada\x00" as *const u8 as *const libc::c_char,
),
0
);
assert!(dc_delete_file(context, as_path(fn0)));
free(fn0 as *mut libc::c_void);
free(fn1 as *mut libc::c_void);
let res = context.get_config(config::Config::SysConfigKeys).unwrap(); let res = context.get_config(config::Config::SysConfigKeys).unwrap();