diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 8824e36c2..315a4942e 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -118,17 +118,14 @@ fn dc_poke_eml_file(context: &Context, filename: impl AsRef) -> Result<(), /// @param context The context as created by dc_context_new(). /// @param spec The file or directory to import. NULL for the last command. /// @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() { error!(context, "Import: Database not opened."); return 0; } - let ok_to_continue; - let mut success: libc::c_int = 0; let real_spec: String; - let mut suffix: *mut libc::c_char = ptr::null_mut(); - let mut read_cnt: libc::c_int = 0; + let mut read_cnt = 0; /* if `spec` is given, remember it for later usage; if it is not given, try to use the last one */ if !spec.is_null() { @@ -137,71 +134,57 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int .sql .set_config(context, "import_spec", Some(&real_spec)) .unwrap(); - ok_to_continue = true; } else { let rs = context.sql.get_config(context, "import_spec"); if rs.is_none() { error!(context, "Import: No file or folder given."); - ok_to_continue = false; - } else { - ok_to_continue = true; + return 0; } - real_spec = rs.unwrap_or_default(); + real_spec = rs.unwrap(); } - if ok_to_continue { - let ok_to_continue2; - 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 let Some(suffix) = dc_get_filesuffix_lc(&real_spec) { + if suffix == "eml" { if dc_poke_eml_file(context, &real_spec).is_ok() { read_cnt += 1 } - ok_to_continue2 = true; + } + } else { + /* import a directory */ + let dir_name = std::path::Path::new(&real_spec); + let dir = std::fs::read_dir(dir_name); + if dir.is_err() { + error!(context, "Import: Cannot open directory \"{}\".", &real_spec,); + return 0; } else { - /* import a directory */ - let dir_name = std::path::Path::new(&real_spec); - let dir = std::fs::read_dir(dir_name); - if dir.is_err() { - error!(context, "Import: Cannot open directory \"{}\".", &real_spec,); - ok_to_continue2 = false; - } else { - let dir = dir.unwrap(); - for entry in dir { - if entry.is_err() { - break; - } - let entry = entry.unwrap(); - let name_f = entry.file_name(); - let name = name_f.to_string_lossy(); - if name.ends_with(".eml") { - let path_plus_name = format!("{}/{}", &real_spec, name); - info!(context, "Import: {}", path_plus_name); - if dc_poke_eml_file(context, path_plus_name).is_ok() { - read_cnt += 1 - } + let dir = dir.unwrap(); + for entry in dir { + if entry.is_err() { + break; + } + let entry = entry.unwrap(); + let name_f = entry.file_name(); + let name = name_f.to_string_lossy(); + if name.ends_with(".eml") { + let path_plus_name = format!("{}/{}", &real_spec, name); + info!(context, "Import: {}", path_plus_name); + if dc_poke_eml_file(context, path_plus_name).is_ok() { + read_cnt += 1 } } - ok_to_continue2 = true; } } - if ok_to_continue2 { - info!( - context, - "Import: {} items read from \"{}\".", read_cnt, &real_spec - ); - if read_cnt > 0 { - context.call_cb(Event::MsgsChanged { - chat_id: 0, - msg_id: 0, - }); - } - success = 1 - } } - - free(suffix as *mut libc::c_void); - success + info!( + context, + "Import: {} items read from \"{}\".", read_cnt, &real_spec + ); + if read_cnt > 0 { + context.call_cb(Event::MsgsChanged { + chat_id: 0, + msg_id: 0, + }); + } + 1 } unsafe fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { diff --git a/src/dc_imex.rs b/src/dc_imex.rs index 7902f44b7..1445796c9 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -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 (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 suffix: *mut libc::c_char = ptr::null_mut(); let mut set_default: libc::c_int; let mut buf: *mut libc::c_char = ptr::null_mut(); // a pointer inside buf, MUST NOT be free()'d @@ -859,14 +858,18 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) -> break; } let entry = entry.unwrap(); - free(suffix as *mut libc::c_void); let name_f = entry.file_name(); let name_c = name_f.to_c_string().unwrap(); - suffix = dc_get_filesuffix_lc(name_f.to_string_lossy()); - if suffix.is_null() - || strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0 - { - continue; + + match dc_get_filesuffix_lc(name_f.to_string_lossy()) { + Some(suffix) => { + if suffix != ".asc" { + continue; + } + } + None => { + continue; + } } let path_plus_name = dir.join(entry.file_name()); 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(buf2 as *mut libc::c_void); diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 142d8f630..ad89a47f9 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::ptr; use chrono::TimeZone; -use libc::{free, strcmp}; +use libc::free; use mmime::clist::*; use mmime::mailimf_types::*; use mmime::mailimf_types_helper::*; @@ -904,164 +904,122 @@ unsafe fn set_body_text(part: *mut mailmime, text: &str) { } #[allow(non_snake_case)] -unsafe fn build_body_file( - context: &Context, - msg: &Message, - base_name: &str, -) -> (*mut mailmime, String) { - let needs_ext: bool; - 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) +fn build_body_file(context: &Context, msg: &Message, base_name: &str) -> (*mut mailmime, String) { + let path_filename = match msg.param.get(Param::File) { + None => { + return (ptr::null_mut(), "".to_string()); + } + Some(path) => path, + }; + let suffix = dc_get_filesuffix_lc(path_filename).unwrap_or_else(|| "dat".into()); + let filename_to_send = match msg.type_0 { + Viewtype::Voice => chrono::Utc + .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() + .map(|c| c.to_string_lossy().to_string()) + .unwrap_or_default(), + Viewtype::Image | Viewtype::Gif => format!( + "{}.{}", + if base_name.is_empty() { + "image" } else { - "dat".into() - }; - ts.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix)) - .to_string() - } else if msg.type_0 == Viewtype::Audio { - 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 { - format!( - "{}.{}", - if base_name.is_empty() { - "image" - } else { - base_name - }, - if !suffix.is_null() { - as_str(suffix) - } else { - "dat" - }, - ) - } 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() - .map(|c| c.to_string_lossy().to_string()) - .unwrap_or_default() - }; + base_name + }, + &suffix, + ), + Viewtype::Video => format!("video.{}", &suffix), + _ => Path::new(path_filename) + .file_name() + .map(|c| c.to_string_lossy().to_string()) + .unwrap_or_default(), + }; - if mimetype.is_null() { - if suffix.is_null() { - mimetype = "application/octet-stream".strdup(); - } else if strcmp(suffix, b"png\x00" as *const u8 as *const libc::c_char) == 0 { - mimetype = "image/png".strdup(); - } else if strcmp(suffix, b"jpg\x00" as *const u8 as *const libc::c_char) == 0 - || 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(); + let mimetype = match msg.param.get(Param::MimeType) { + Some(mtype) => mtype, + None => { + let path = Path::new(path_filename); + if let Some(res) = message::guess_msgtype_from_suffix(&path) { + res.1 } else { - mimetype = "application/octet-stream".strdup(); + "application/octet-stream" } } - if !mimetype.is_null() { - /* 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. - 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); - mime_fields = mailmime_fields_new_filename( - MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int, - if needs_ext { - ptr::null_mut() - } else { - filename_to_send.strdup() - }, - MAILMIME_MECHANISM_BASE64 as libc::c_int, - ); + }; + + let needs_ext = dc_needs_ext_header(&filename_to_send); + + unsafe { + /* 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. + But I've heard about problems with inline and outl'k, so we just use the attachment-type until we run into other problems ... */ + let mime_fields = mailmime_fields_new_filename( + MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int, if needs_ext { - for cur_data in (*(*mime_fields).fld_list).into_iter() { - let field: *mut mailmime_field = cur_data as *mut _; - if (*field).fld_type == MAILMIME_FIELD_DISPOSITION as libc::c_int - && !(*field).fld_data.fld_disposition.is_null() - { - let file_disposition = (*field).fld_data.fld_disposition; - if !file_disposition.is_null() { - let parm = mailmime_disposition_parm_new( - MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0 as libc::size_t, - mailmime_parameter_new( - strdup(b"filename*\x00" as *const u8 as *const libc::c_char), - dc_encode_ext_header(&filename_to_send).strdup(), - ), + ptr::null_mut() + } else { + filename_to_send.strdup() + }, + MAILMIME_MECHANISM_BASE64 as libc::c_int, + ); + if needs_ext { + for cur_data in (*(*mime_fields).fld_list).into_iter() { + let field: *mut mailmime_field = cur_data as *mut _; + if (*field).fld_type == MAILMIME_FIELD_DISPOSITION as libc::c_int + && !(*field).fld_data.fld_disposition.is_null() + { + let file_disposition = (*field).fld_data.fld_disposition; + if !file_disposition.is_null() { + let parm = mailmime_disposition_parm_new( + MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0 as libc::size_t, + mailmime_parameter_new( + strdup(b"filename*\x00" as *const u8 as *const libc::c_char), + dc_encode_ext_header(&filename_to_send).strdup(), + ), + ); + if !parm.is_null() { + clist_insert_after( + (*file_disposition).dsp_parms, + (*(*file_disposition).dsp_parms).last, + parm as *mut libc::c_void, ); - if !parm.is_null() { - clist_insert_after( - (*file_disposition).dsp_parms, - (*(*file_disposition).dsp_parms).last, - parm as *mut libc::c_void, - ); - } } - break; } + break; } } - content = mailmime_content_new_with_str(mimetype); - filename_encoded = dc_encode_header_words(&filename_to_send); - clist_insert_after( - (*content).ct_parameters, - (*(*content).ct_parameters).last, - mailmime_param_new_with_data( - b"name\x00" as *const u8 as *const libc::c_char as *mut libc::c_char, - filename_encoded, - ) as *mut libc::c_void, - ); - mime_sub = mailmime_new_empty(content, mime_fields); - let abs_path = dc_get_abs_path(context, path_filename) - .to_c_string() - .unwrap(); - mailmime_set_body_file(mime_sub, dc_strdup(abs_path.as_ptr())); } + let content = mailmime_content_new_with_str(mimetype.strdup()); + let filename_encoded = dc_encode_header_words(&filename_to_send); + clist_insert_after( + (*content).ct_parameters, + (*(*content).ct_parameters).last, + mailmime_param_new_with_data( + b"name\x00" as *const u8 as *const libc::c_char as *mut libc::c_char, + filename_encoded, + ) as *mut libc::c_void, + ); + 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) + .to_c_string() + .unwrap(); + mailmime_set_body_file(mime_sub, dc_strdup(abs_path.as_ptr())); + (mime_sub, filename_to_send) } - - free(mimetype as *mut libc::c_void); - free(filename_encoded as *mut libc::c_void); - - (mime_sub, filename_to_send) } /******************************************************************************* * 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 path = msg.param.get(Param::File).unwrap_or_default(); let bytes = dc_get_filebytes(context, &path); diff --git a/src/dc_tools.rs b/src/dc_tools.rs index eb190c27e..3780459ae 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -548,11 +548,11 @@ fn validate_filename(filename: &str) -> String { // the returned suffix is lower-case #[allow(non_snake_case)] -pub unsafe fn dc_get_filesuffix_lc(path_filename: impl AsRef) -> *mut libc::c_char { +pub fn dc_get_filesuffix_lc(path_filename: impl AsRef) -> Option { 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 { - ptr::null_mut() + None } } diff --git a/src/message.rs b/src/message.rs index edf54655b..3af674d19 100644 --- a/src/message.rs +++ b/src/message.rs @@ -680,6 +680,7 @@ pub fn guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)> { "mp4" => (Viewtype::Video, "video/mp4"), "jpg" => (Viewtype::Image, "image/jpeg"), "jpeg" => (Viewtype::Image, "image/jpeg"), + "jpe" => (Viewtype::Image, "image/jpeg"), "png" => (Viewtype::Image, "image/png"), "webp" => (Viewtype::Image, "image/webp"), "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"), }; let extension: &str = &path.extension()?.to_str()?.to_lowercase(); - KNOWN.get(extension).map(|x| *x) }