diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 7ab8f7d97..748c53074 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -2,7 +2,6 @@ use std::path::Path; use std::ptr; use chrono::TimeZone; -use libc::free; use mmime::clist::*; use mmime::mailimf_types::*; use mmime::mailimf_types_helper::*; @@ -535,7 +534,7 @@ pub unsafe fn dc_mimefactory_render( meta.type_0 = Viewtype::Image; meta.param.set(Param::File, grpimage); - let res = build_body_file(context, &meta, "group-image"); + let res = build_body_file(context, &meta, "group-image")?; meta_part = res.0; let filename_as_sent = res.1; if !meta_part.is_null() { @@ -610,10 +609,8 @@ pub unsafe fn dc_mimefactory_render( 24 * 1024 * 1024 / 4 * 3 / 1000 / 1000, ); } else { - let (file_part, _) = build_body_file(context, &factory.msg, ""); - if !file_part.is_null() { - mailmime_smart_add_part(message, file_part); - } + let (file_part, _) = build_body_file(context, &factory.msg, "")?; + mailmime_smart_add_part(message, file_part); } } if !meta_part.is_null() { @@ -699,8 +696,7 @@ pub unsafe fn dc_mimefactory_render( factory.msg.rfc724_mid ); - let content_type_0 = - wrapmime::new_mailmime_content_type("message/disposition-notification"); + let content_type_0 = wrapmime::new_content_type("message/disposition-notification")?; let mime_fields_0: *mut mailmime_fields = mailmime_fields_new_encoding(MAILMIME_MECHANISM_8BIT as libc::c_int); let mach_mime_part: *mut mailmime = mailmime_new_empty(content_type_0, mime_fields_0); @@ -816,10 +812,14 @@ fn get_subject( } #[allow(non_snake_case)] -fn build_body_file(context: &Context, msg: &Message, base_name: &str) -> (*mut mailmime, String) { +fn build_body_file( + context: &Context, + msg: &Message, + base_name: &str, +) -> Result<(*mut mailmime, String), Error> { let path_filename = match msg.param.get(Param::File) { None => { - return (ptr::null_mut(), "".to_string()); + bail!("msg has no filename"); } Some(path) => path, }; @@ -913,23 +913,16 @@ fn build_body_file(context: &Context, msg: &Message, base_name: &str) -> (*mut m } } } - let content = wrapmime::new_mailmime_content_type(&mimetype); - let filename_encoded = dc_encode_header_words(&filename_to_send).strdup(); - 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 content = wrapmime::new_content_type(&mimetype)?; + let filename_encoded = dc_encode_header_words(&filename_to_send); + wrapmime::append_ct_param(content, "name", &filename_encoded)?; + 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) + Ok((mime_sub, filename_to_send)) } } diff --git a/src/e2ee.rs b/src/e2ee.rs index aa104921b..7c5710405 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -252,16 +252,16 @@ impl EncryptHelper { ptr::null_mut(), 0 as libc::size_t, "multipart/encrypted", - -1, - ); + MAILMIME_MECHANISM_BASE64, + )?; let content: *mut mailmime_content = (*encrypted_part).mm_content_type; wrapmime::append_ct_param(content, "protocol", "application/pgp-encrypted")?; let version_mime: *mut mailmime = new_data_part( VERSION_CONTENT.as_mut_ptr() as *mut libc::c_void, strlen(VERSION_CONTENT.as_mut_ptr()), "application/pgp-encrypted", - MAILMIME_MECHANISM_7BIT as i32, - ); + MAILMIME_MECHANISM_7BIT, + )?; mailmime_smart_add_part(encrypted_part, version_mime); // we assume that ctext_v is not dropped until the end @@ -270,8 +270,8 @@ impl EncryptHelper { ctext_v.as_ptr() as *mut libc::c_void, ctext_v.len(), "application/octet-stream", - MAILMIME_MECHANISM_7BIT as i32, - ); + MAILMIME_MECHANISM_7BIT, + )?; mailmime_smart_add_part(encrypted_part, ctext_part); (*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part; (*encrypted_part).mm_parent = in_out_message; @@ -421,95 +421,38 @@ impl E2eeHelper { } } -unsafe fn new_data_part( +fn new_data_part( data: *mut libc::c_void, data_bytes: libc::size_t, - default_content_type: &str, - default_encoding: libc::c_int, -) -> *mut mailmime { - let mut ok_to_continue = true; - let mut encoding: *mut mailmime_mechanism = ptr::null_mut(); - let content: *mut mailmime_content; - let mime: *mut mailmime; - let mime_fields: *mut mailmime_fields; - let encoding_type: libc::c_int; - let mut do_encoding: libc::c_int; + content_type: &str, + default_encoding: u32, +) -> Result<*mut mailmime> { + let content = new_content_type(&content_type)?; + unsafe { + let mut encoding: *mut mailmime_mechanism = ptr::null_mut(); + if wrapmime::content_type_needs_encoding(content) { + encoding = mailmime_mechanism_new(default_encoding as i32, ptr::null_mut()); + ensure!(!encoding.is_null(), "failed to create encoding"); + } + let mime_fields = mailmime_fields_new_with_data( + encoding, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ); + ensure!(!mime_fields.is_null(), "internal mime error"); - let content_type = if default_content_type.is_empty() { - "application/octet-stream" - } else { - default_content_type - }; - content = new_mailmime_content_type(&content_type); - if content.is_null() { - ok_to_continue = false; - } else { - do_encoding = 1i32; - if (*(*content).ct_type).tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int { - let composite: *mut mailmime_composite_type; - composite = (*(*content).ct_type).tp_data.tp_composite_type; - match (*composite).ct_type { - 1 => { - if strcasecmp( - (*content).ct_subtype, - b"rfc822\x00" as *const u8 as *const libc::c_char, - ) == 0i32 - { - do_encoding = 0i32 - } - } - 2 => do_encoding = 0i32, - _ => {} - } - } - if 0 != do_encoding { - if default_encoding == -1i32 { - encoding_type = MAILMIME_MECHANISM_BASE64 as libc::c_int - } else { - encoding_type = default_encoding - } - encoding = mailmime_mechanism_new(encoding_type, ptr::null_mut()); - if encoding.is_null() { - ok_to_continue = false; - } - } - if ok_to_continue { - mime_fields = mailmime_fields_new_with_data( - encoding, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ); - if mime_fields.is_null() { - ok_to_continue = false; - } else { - mime = mailmime_new_empty(content, mime_fields); - if mime.is_null() { - mailmime_fields_free(mime_fields); - mailmime_content_free(content); - } else { - if !data.is_null() - && data_bytes > 0 - && (*mime).mm_type == MAILMIME_SINGLE as libc::c_int - { - mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes); - } - return mime; - } - } - } - } + let mime = mailmime_new_empty(content, mime_fields); + ensure!(!mime.is_null(), "internal mime error"); - if ok_to_continue == false { - if !encoding.is_null() { - mailmime_mechanism_free(encoding); - } - if !content.is_null() { - mailmime_content_free(content); + if (*mime).mm_type == MAILMIME_SINGLE as libc::c_int { + if !data.is_null() && data_bytes > 0 { + mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes); + } } + return Ok(mime); } - ptr::null_mut() } /// Load public key from database or generate a new one. diff --git a/src/wrapmime.rs b/src/wrapmime.rs index e770b2185..967ca7808 100644 --- a/src/wrapmime.rs +++ b/src/wrapmime.rs @@ -5,6 +5,7 @@ use crate::error::Error; use mmime::clist::*; use mmime::mailimf_types::*; use mmime::mailimf_types_helper::*; +use mmime::mailmime::*; use mmime::mailmime_disposition::*; use mmime::mailmime_types::*; use mmime::mailmime_types_helper::*; @@ -60,7 +61,7 @@ pub fn build_body_text(text: &str) -> Result<*mut mailmime, Error> { let mime_fields: *mut mailmime_fields; let message_part: *mut mailmime; - let content = new_mailmime_content_type("text/plain"); + let content = new_content_type("text/plain")?; append_ct_param(content, "charset", "utf-8")?; unsafe { @@ -92,18 +93,15 @@ pub fn append_ct_param( Ok(()) } -pub fn new_mailmime_content_type(content_type: &str) -> *mut mailmime_content { +pub fn new_content_type(content_type: &str) -> Result<*mut mailmime_content, Error> { let ct = CString::new(content_type).unwrap(); let content: *mut mailmime_content; // mailmime_content_new_with_str only parses but does not retain/own ct - // unsafe { content = mailmime_content_new_with_str(ct.as_ptr()); } - if content.is_null() { - panic!("mailimf failed to allocate"); - } - content + ensure!(!content.is_null(), "mailimf failed to allocate"); + Ok(content) } pub fn set_body_text(part: *mut mailmime, text: &str) -> Result<(), Error> { @@ -116,3 +114,39 @@ pub fn set_body_text(part: *mut mailmime, text: &str) -> Result<(), Error> { } Ok(()) } + +pub fn content_type_needs_encoding(content: *const mailmime_content) -> bool { + unsafe { + if (*(*content).ct_type).tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int { + let composite = (*(*content).ct_type).tp_data.tp_composite_type; + match (*composite).ct_type as u32 { + MAILMIME_COMPOSITE_TYPE_MESSAGE => as_str((*content).ct_subtype) != "rfc822", + MAILMIME_COMPOSITE_TYPE_MULTIPART => false, + _ => false, + } + } else { + true + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_needs_encoding() { + assert!(content_type_needs_encoding( + new_content_type("text/plain").unwrap() + )); + assert!(content_type_needs_encoding( + new_content_type("application/octect-stream").unwrap() + )); + assert!(!content_type_needs_encoding( + new_content_type("multipart/encrypted").unwrap() + )); + assert!(content_type_needs_encoding( + new_content_type("application/pgp-encrypted").unwrap() + )); + } +}