streamline mimetype guessing and build_body_file

This commit is contained in:
holger krekel
2019-09-21 21:19:24 +02:00
parent cace6fee85
commit cea931dcc7
5 changed files with 151 additions and 208 deletions

View File

@@ -118,17 +118,14 @@ fn dc_poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(),
/// @param context The context as created by dc_context_new(). /// @param context The context as created by dc_context_new().
/// @param spec The file or directory to import. NULL for the last command. /// @param spec The file or directory to import. NULL for the last command.
/// @return 1=success, 0=error. /// @return 1=success, 0=error.
unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int { fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int {
if !context.sql.is_open() { if !context.sql.is_open() {
error!(context, "Import: Database not opened."); error!(context, "Import: Database not opened.");
return 0; return 0;
} }
let ok_to_continue;
let mut success: libc::c_int = 0;
let real_spec: String; let real_spec: String;
let mut suffix: *mut libc::c_char = ptr::null_mut(); let mut read_cnt = 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() {
@@ -137,34 +134,27 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
.sql .sql
.set_config(context, "import_spec", Some(&real_spec)) .set_config(context, "import_spec", Some(&real_spec))
.unwrap(); .unwrap();
ok_to_continue = true;
} else { } else {
let rs = context.sql.get_config(context, "import_spec"); let rs = context.sql.get_config(context, "import_spec");
if rs.is_none() { if rs.is_none() {
error!(context, "Import: No file or folder given."); error!(context, "Import: No file or folder given.");
ok_to_continue = false; return 0;
} else {
ok_to_continue = true;
} }
real_spec = rs.unwrap_or_default(); real_spec = rs.unwrap();
} }
if ok_to_continue { if let Some(suffix) = dc_get_filesuffix_lc(&real_spec) {
let ok_to_continue2; if suffix == "eml" {
suffix = dc_get_filesuffix_lc(&real_spec);
if !suffix.is_null()
&& libc::strcmp(suffix, b"eml\x00" as *const u8 as *const libc::c_char) == 0
{
if dc_poke_eml_file(context, &real_spec).is_ok() { if dc_poke_eml_file(context, &real_spec).is_ok() {
read_cnt += 1 read_cnt += 1
} }
ok_to_continue2 = true; }
} else { } else {
/* import a directory */ /* import a directory */
let dir_name = std::path::Path::new(&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!(context, "Import: Cannot open directory \"{}\".", &real_spec,); error!(context, "Import: Cannot open directory \"{}\".", &real_spec,);
ok_to_continue2 = false; return 0;
} else { } else {
let dir = dir.unwrap(); let dir = dir.unwrap();
for entry in dir { for entry in dir {
@@ -182,10 +172,8 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
} }
} }
} }
ok_to_continue2 = true;
} }
} }
if ok_to_continue2 {
info!( info!(
context, context,
"Import: {} items read from \"{}\".", read_cnt, &real_spec "Import: {} items read from \"{}\".", read_cnt, &real_spec
@@ -196,12 +184,7 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
msg_id: 0, msg_id: 0,
}); });
} }
success = 1 1
}
}
free(suffix as *mut libc::c_void);
success
} }
unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) { unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {

View File

@@ -843,7 +843,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
Maybe we should make the "default" key handlong also a little bit smarter Maybe we should make the "default" key handlong also a little bit smarter
(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 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();
// a pointer inside buf, MUST NOT be free()'d // a pointer inside buf, MUST NOT be free()'d
@@ -859,15 +858,19 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
break; break;
} }
let entry = entry.unwrap(); let entry = entry.unwrap();
free(suffix as *mut libc::c_void);
let name_f = entry.file_name(); let name_f = entry.file_name();
let name_c = name_f.to_c_string().unwrap(); let name_c = name_f.to_c_string().unwrap();
suffix = dc_get_filesuffix_lc(name_f.to_string_lossy());
if suffix.is_null() match dc_get_filesuffix_lc(name_f.to_string_lossy()) {
|| strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0 Some(suffix) => {
{ if suffix != ".asc" {
continue; continue;
} }
}
None => {
continue;
}
}
let path_plus_name = dir.join(entry.file_name()); let path_plus_name = dir.join(entry.file_name());
info!(context, "Checking: {}", path_plus_name.display()); info!(context, "Checking: {}", path_plus_name.display());
@@ -940,7 +943,6 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
} }
} }
free(suffix 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);

View File

@@ -2,7 +2,7 @@ use std::path::Path;
use std::ptr; use std::ptr;
use chrono::TimeZone; use chrono::TimeZone;
use libc::{free, strcmp}; use libc::free;
use mmime::clist::*; use mmime::clist::*;
use mmime::mailimf_types::*; use mmime::mailimf_types::*;
use mmime::mailimf_types_helper::*; use mmime::mailimf_types_helper::*;
@@ -904,96 +904,58 @@ unsafe fn set_body_text(part: *mut mailmime, text: &str) {
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe fn build_body_file( fn build_body_file(context: &Context, msg: &Message, base_name: &str) -> (*mut mailmime, String) {
context: &Context, let path_filename = match msg.param.get(Param::File) {
msg: &Message, None => {
base_name: &str, return (ptr::null_mut(), "".to_string());
) -> (*mut mailmime, String) { }
let needs_ext: bool; Some(path) => path,
let mime_fields: *mut mailmime_fields;
let mut mime_sub: *mut mailmime = ptr::null_mut();
let content: *mut mailmime_content;
let path_filename = msg.param.get(Param::File);
let mut filename_to_send = "".to_string();
let mut mimetype = msg
.param
.get(Param::MimeType)
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
let mut filename_encoded = ptr::null_mut();
if let Some(ref path_filename) = path_filename {
let suffix = dc_get_filesuffix_lc(path_filename);
filename_to_send = if msg.type_0 == Viewtype::Voice {
let ts = chrono::Utc.timestamp(msg.timestamp_sort as i64, 0);
let suffix = if !suffix.is_null() {
to_string(suffix)
} else {
"dat".into()
}; };
ts.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix)) let suffix = dc_get_filesuffix_lc(path_filename).unwrap_or_else(|| "dat".into());
.to_string() let filename_to_send = match msg.type_0 {
} else if msg.type_0 == Viewtype::Audio { Viewtype::Voice => chrono::Utc
Path::new(path_filename) .timestamp(msg.timestamp_sort as i64, 0)
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
.to_string(),
Viewtype::Audio => Path::new(path_filename)
.file_name() .file_name()
.map(|c| c.to_string_lossy().to_string()) .map(|c| c.to_string_lossy().to_string())
.unwrap_or_default() .unwrap_or_default(),
} else if msg.type_0 == Viewtype::Image || msg.type_0 == Viewtype::Gif { Viewtype::Image | Viewtype::Gif => format!(
format!(
"{}.{}", "{}.{}",
if base_name.is_empty() { if base_name.is_empty() {
"image" "image"
} else { } else {
base_name base_name
}, },
if !suffix.is_null() { &suffix,
as_str(suffix) ),
} else { Viewtype::Video => format!("video.{}", &suffix),
"dat" _ => Path::new(path_filename)
},
)
} else if msg.type_0 == Viewtype::Video {
format!(
"video.{}",
if !suffix.is_null() {
as_str(suffix)
} else {
"dat"
},
)
} else {
Path::new(path_filename)
.file_name() .file_name()
.map(|c| c.to_string_lossy().to_string()) .map(|c| c.to_string_lossy().to_string())
.unwrap_or_default() .unwrap_or_default(),
}; };
if mimetype.is_null() { let mimetype = match msg.param.get(Param::MimeType) {
if suffix.is_null() { Some(mtype) => mtype,
mimetype = "application/octet-stream".strdup(); None => {
} else if strcmp(suffix, b"png\x00" as *const u8 as *const libc::c_char) == 0 { let path = Path::new(path_filename);
mimetype = "image/png".strdup(); if let Some(res) = message::guess_msgtype_from_suffix(&path) {
} else if strcmp(suffix, b"jpg\x00" as *const u8 as *const libc::c_char) == 0 res.1
|| strcmp(suffix, b"jpeg\x00" as *const u8 as *const libc::c_char) == 0
|| strcmp(suffix, b"jpe\x00" as *const u8 as *const libc::c_char) == 0
{
mimetype = "image/jpeg".strdup();
} else if strcmp(suffix, b"gif\x00" as *const u8 as *const libc::c_char) == 0 {
mimetype = "image/gif".strdup();
} else { } else {
mimetype = "application/octet-stream".strdup(); "application/octet-stream"
} }
} }
if !mimetype.is_null() { };
let needs_ext = dc_needs_ext_header(&filename_to_send);
unsafe {
/* 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(&filename_to_send); let 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()
@@ -1034,8 +996,8 @@ unsafe fn build_body_file(
} }
} }
} }
content = mailmime_content_new_with_str(mimetype); let content = mailmime_content_new_with_str(mimetype.strdup());
filename_encoded = dc_encode_header_words(&filename_to_send); let 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,
@@ -1044,24 +1006,20 @@ unsafe fn build_body_file(
filename_encoded, filename_encoded,
) as *mut libc::c_void, ) as *mut libc::c_void,
); );
mime_sub = mailmime_new_empty(content, mime_fields); free(filename_encoded as *mut libc::c_void);
let mime_sub = mailmime_new_empty(content, mime_fields);
let abs_path = dc_get_abs_path(context, path_filename) let abs_path = dc_get_abs_path(context, path_filename)
.to_c_string() .to_c_string()
.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()));
}
}
free(mimetype as *mut libc::c_void);
free(filename_encoded as *mut libc::c_void);
(mime_sub, filename_to_send) (mime_sub, filename_to_send)
} }
}
/******************************************************************************* /*******************************************************************************
* Render * Render
******************************************************************************/ ******************************************************************************/
unsafe fn is_file_size_okay(context: &Context, msg: &Message) -> bool { fn is_file_size_okay(context: &Context, msg: &Message) -> bool {
let mut file_size_okay = true; let mut file_size_okay = true;
let path = msg.param.get(Param::File).unwrap_or_default(); let path = msg.param.get(Param::File).unwrap_or_default();
let bytes = dc_get_filebytes(context, &path); let bytes = dc_get_filebytes(context, &path);

View File

@@ -548,11 +548,11 @@ fn validate_filename(filename: &str) -> String {
// 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 fn dc_get_filesuffix_lc(path_filename: impl AsRef<str>) -> Option<String> {
if let Some(p) = Path::new(path_filename.as_ref()).extension() { if let Some(p) = Path::new(path_filename.as_ref()).extension() {
p.to_string_lossy().to_lowercase().strdup() Some(p.to_string_lossy().to_lowercase())
} else { } else {
ptr::null_mut() None
} }
} }

View File

@@ -680,6 +680,7 @@ pub fn guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)> {
"mp4" => (Viewtype::Video, "video/mp4"), "mp4" => (Viewtype::Video, "video/mp4"),
"jpg" => (Viewtype::Image, "image/jpeg"), "jpg" => (Viewtype::Image, "image/jpeg"),
"jpeg" => (Viewtype::Image, "image/jpeg"), "jpeg" => (Viewtype::Image, "image/jpeg"),
"jpe" => (Viewtype::Image, "image/jpeg"),
"png" => (Viewtype::Image, "image/png"), "png" => (Viewtype::Image, "image/png"),
"webp" => (Viewtype::Image, "image/webp"), "webp" => (Viewtype::Image, "image/webp"),
"gif" => (Viewtype::Gif, "image/gif"), "gif" => (Viewtype::Gif, "image/gif"),
@@ -687,7 +688,6 @@ pub fn guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)> {
"vcard" => (Viewtype::File, "text/vcard"), "vcard" => (Viewtype::File, "text/vcard"),
}; };
let extension: &str = &path.extension()?.to_str()?.to_lowercase(); let extension: &str = &path.extension()?.to_str()?.to_lowercase();
KNOWN.get(extension).map(|x| *x) KNOWN.get(extension).map(|x| *x)
} }