refactor: rustify interface of maimlime_transfer_decode

This commit is contained in:
dignifiedquire
2019-09-20 22:53:54 +02:00
committed by holger krekel
parent 7dd3bad8bd
commit 266b205c75
3 changed files with 71 additions and 144 deletions

View File

@@ -21,6 +21,7 @@ use crate::dc_simplify::*;
use crate::dc_strencode::*; use crate::dc_strencode::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::e2ee::*; use crate::e2ee::*;
use crate::error::Error;
use crate::location; use crate::location;
use crate::param::*; use crate::param::*;
use crate::stock::StockMessage; use crate::stock::StockMessage;
@@ -580,9 +581,11 @@ impl<'a> MimeParser<'a> {
if mime.is_null() || (*mime).mm_data.mm_single.is_null() { if mime.is_null() || (*mime).mm_data.mm_single.is_null() {
return false; return false;
} }
let mut raw_mime: *mut libc::c_char = ptr::null_mut();
let mut raw_mime = ptr::null_mut();
let mut msg_type = Viewtype::Unknown; let mut msg_type = Viewtype::Unknown;
let mime_type = mailmime_get_mime_type(mime, &mut msg_type, &mut raw_mime); let mime_type = mailmime_get_mime_type(mime, &mut msg_type, &mut raw_mime);
let mime_data = (*mime).mm_data.mm_single; let mime_data = (*mime).mm_data.mm_single;
if (*mime_data).dt_type != MAILMIME_DATA_TEXT as libc::c_int if (*mime_data).dt_type != MAILMIME_DATA_TEXT as libc::c_int
/* MAILMIME_DATA_FILE indicates, the data is in a file; AFAIK this is not used on parsing */ /* MAILMIME_DATA_FILE indicates, the data is in a file; AFAIK this is not used on parsing */
@@ -592,22 +595,14 @@ impl<'a> MimeParser<'a> {
return false; return false;
} }
/* mmap_string_unref()'d if set */ let mut decoded_data = match mailmime_transfer_decode(mime) {
let mut transfer_decoding_buffer: *mut libc::c_char = ptr::null_mut(); Ok(decoded_data) => decoded_data,
/* must not be free()'d */ Err(_) => {
let mut decoded_data: *const libc::c_char = ptr::null(); // Note that it's now always an error - might be no data
let mut decoded_data_bytes = 0; return false;
}
};
if !mailmime_transfer_decode(
mime,
&mut decoded_data,
&mut decoded_data_bytes,
&mut transfer_decoding_buffer,
) {
/* mailmime_transfer_decode does not allocate when it returns false.
Note that it's now always an error - might be no data */
return false;
}
let old_part_count = self.parts.len(); let old_part_count = self.parts.len();
/* regard `Content-Transfer-Encoding:` */ /* regard `Content-Transfer-Encoding:` */
@@ -628,26 +623,18 @@ impl<'a> MimeParser<'a> {
if let Some(encoding) = if let Some(encoding) =
Charset::for_label(CStr::from_ptr(charset).to_str().unwrap().as_bytes()) Charset::for_label(CStr::from_ptr(charset).to_str().unwrap().as_bytes())
{ {
let data = std::slice::from_raw_parts( let (res, _, _) = encoding.decode(&decoded_data);
decoded_data as *const u8,
decoded_data_bytes,
);
let (res, _, _) = encoding.decode(data);
if res.is_empty() { if res.is_empty() {
/* no error - but nothing to add */ /* no error - but nothing to add */
ok_to_continue = false; ok_to_continue = false;
} else { } else {
let b = res.as_bytes(); decoded_data = res.as_bytes().to_vec()
decoded_data = b.as_ptr() as *const libc::c_char;
decoded_data_bytes = b.len();
std::mem::forget(res);
} }
} else { } else {
warn!( warn!(
self.context, self.context,
"Cannot convert {} bytes from \"{}\" to \"utf-8\".", "Cannot convert {} bytes from \"{}\" to \"utf-8\".",
decoded_data_bytes as libc::c_int, decoded_data.len(),
as_str(charset), as_str(charset),
); );
} }
@@ -656,13 +643,11 @@ impl<'a> MimeParser<'a> {
/* check header directly as is_send_by_messenger is not yet set up */ /* check header directly as is_send_by_messenger is not yet set up */
let is_msgrmsg = self.lookup_optional_field("Chat-Version").is_some(); let is_msgrmsg = self.lookup_optional_field("Chat-Version").is_some();
let simplified_txt = if decoded_data_bytes <= 0 || decoded_data.is_null() { let simplified_txt = if decoded_data.is_empty() {
"".into() "".into()
} else { } else {
let input_c = strndup(decoded_data, decoded_data_bytes as _); let input = std::string::String::from_utf8_lossy(&decoded_data);
let input = to_string_lossy(input_c);
let is_html = mime_type == 70; let is_html = mime_type == 70;
free(input_c as *mut _);
simplifier.unwrap().simplify(&input, is_html, is_msgrmsg) simplifier.unwrap().simplify(&input, is_html, is_msgrmsg)
}; };
@@ -671,12 +656,8 @@ impl<'a> MimeParser<'a> {
part.typ = Viewtype::Text; part.typ = Viewtype::Text;
part.mimetype = mime_type; part.mimetype = mime_type;
part.msg = Some(simplified_txt); part.msg = Some(simplified_txt);
part.msg_raw = { part.msg_raw =
let raw_c = strndup(decoded_data, decoded_data_bytes as libc::c_ulong); Some(std::string::String::from_utf8_lossy(&decoded_data).to_string());
let raw = to_string_lossy(raw_c);
free(raw_c.cast());
Some(raw)
};
self.do_add_single_part(part); self.do_add_single_part(part);
} }
@@ -764,26 +745,23 @@ impl<'a> MimeParser<'a> {
if desired_filename.starts_with("location") if desired_filename.starts_with("location")
&& desired_filename.ends_with(".kml") && desired_filename.ends_with(".kml")
{ {
if !decoded_data.is_null() && decoded_data_bytes > 0 { if !decoded_data.is_empty() {
let d = dc_null_terminate(decoded_data, decoded_data_bytes as i32); let d = std::string::String::from_utf8_lossy(&decoded_data);
self.location_kml = location::Kml::parse(self.context, as_str(d)).ok(); self.location_kml = location::Kml::parse(self.context, &d).ok();
free(d.cast());
} }
} else if desired_filename.starts_with("message") } else if desired_filename.starts_with("message")
&& desired_filename.ends_with(".kml") && desired_filename.ends_with(".kml")
{ {
if !decoded_data.is_null() && decoded_data_bytes > 0 { if !decoded_data.is_empty() {
let d = dc_null_terminate(decoded_data, decoded_data_bytes as i32); let d = std::string::String::from_utf8_lossy(&decoded_data);
self.message_kml = location::Kml::parse(self.context, as_str(d)).ok(); self.message_kml = location::Kml::parse(self.context, &d).ok();
free(d.cast());
} }
} else { } else {
self.do_add_single_file_part( self.do_add_single_file_part(
msg_type, msg_type,
mime_type, mime_type,
as_str(raw_mime), as_str(raw_mime),
decoded_data, &decoded_data,
decoded_data_bytes,
&desired_filename, &desired_filename,
); );
} }
@@ -792,9 +770,7 @@ impl<'a> MimeParser<'a> {
_ => {} _ => {}
} }
/* add object? (we do not add all objects, eg. signatures etc. are ignored) */ /* add object? (we do not add all objects, eg. signatures etc. are ignored) */
if !transfer_decoding_buffer.is_null() {
mmap_string_unref(transfer_decoding_buffer);
}
free(raw_mime as *mut libc::c_void); free(raw_mime as *mut libc::c_void);
self.parts.len() > old_part_count self.parts.len() > old_part_count
} }
@@ -804,30 +780,24 @@ impl<'a> MimeParser<'a> {
msg_type: Viewtype, msg_type: Viewtype,
mime_type: libc::c_int, mime_type: libc::c_int,
raw_mime: &str, raw_mime: &str,
decoded_data: *const libc::c_char, decoded_data: &[u8],
decoded_data_bytes: libc::size_t,
desired_filename: &str, desired_filename: &str,
) { ) {
/* create a free file name to use */ /* create a free file name to use */
let path_filename = dc_get_fine_path_filename(self.context, "$BLOBDIR", desired_filename); let path_filename = dc_get_fine_path_filename(self.context, "$BLOBDIR", desired_filename);
let bytes = std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes);
/* copy data to file */ /* copy data to file */
if dc_write_file(self.context, &path_filename, bytes) { if dc_write_file(self.context, &path_filename, decoded_data) {
let mut part = Part::default(); let mut part = Part::default();
part.typ = msg_type; part.typ = msg_type;
part.mimetype = mime_type; part.mimetype = mime_type;
part.bytes = decoded_data_bytes as libc::c_int; part.bytes = decoded_data.len() as libc::c_int;
part.param.set(Param::File, path_filename.to_string_lossy()); part.param.set(Param::File, path_filename.to_string_lossy());
part.param.set(Param::MimeType, raw_mime); part.param.set(Param::MimeType, raw_mime);
if mime_type == 80 { if mime_type == 80 {
assert!(!decoded_data.is_null(), "invalid image data"); assert!(!decoded_data.is_empty(), "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(decoded_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);
} }
@@ -1233,32 +1203,12 @@ pub unsafe fn mailmime_find_ct_parameter(
ptr::null_mut() ptr::null_mut()
} }
pub unsafe fn mailmime_transfer_decode( pub unsafe fn mailmime_transfer_decode(mime: *mut mailmime) -> Result<Vec<u8>, Error> {
mime: *mut mailmime, ensure!(!mime.is_null(), "invalid inputs");
ret_decoded_data: *mut *const libc::c_char,
ret_decoded_data_bytes: *mut libc::size_t,
ret_to_mmap_string_unref: *mut *mut libc::c_char,
) -> bool {
let mut mime_transfer_encoding = MAILMIME_MECHANISM_BINARY as libc::c_int; let mut mime_transfer_encoding = MAILMIME_MECHANISM_BINARY as libc::c_int;
let mime_data: *mut mailmime_data;
/* must not be free()'d */ let mime_data = (*mime).mm_data.mm_single;
let decoded_data: *const libc::c_char;
let mut decoded_data_bytes = 0;
/* mmap_string_unref()'d if set */
let mut transfer_decoding_buffer: *mut libc::c_char = ptr::null_mut();
if mime.is_null()
|| ret_decoded_data.is_null()
|| ret_decoded_data_bytes.is_null()
|| ret_to_mmap_string_unref.is_null()
|| !(*ret_decoded_data).is_null()
|| *ret_decoded_data_bytes != 0
|| !(*ret_to_mmap_string_unref).is_null()
{
return false;
}
mime_data = (*mime).mm_data.mm_single;
if !(*mime).mm_mime_fields.is_null() { if !(*mime).mm_mime_fields.is_null() {
for cur in (*(*(*mime).mm_mime_fields).fld_list).into_iter() { for cur in (*(*(*mime).mm_mime_fields).fld_list).into_iter() {
let field = cur as *mut mailmime_field; let field = cur as *mut mailmime_field;
@@ -1277,35 +1227,42 @@ pub unsafe fn mailmime_transfer_decode(
|| mime_transfer_encoding == MAILMIME_MECHANISM_8BIT as libc::c_int || mime_transfer_encoding == MAILMIME_MECHANISM_8BIT as libc::c_int
|| mime_transfer_encoding == MAILMIME_MECHANISM_BINARY as libc::c_int || mime_transfer_encoding == MAILMIME_MECHANISM_BINARY as libc::c_int
{ {
decoded_data = (*mime_data).dt_data.dt_text.dt_data; let decoded_data = (*mime_data).dt_data.dt_text.dt_data;
decoded_data_bytes = (*mime_data).dt_data.dt_text.dt_length; let decoded_data_bytes = (*mime_data).dt_data.dt_text.dt_length;
if decoded_data.is_null() || decoded_data_bytes <= 0 { if decoded_data.is_null() || decoded_data_bytes <= 0 {
return false; bail!("No data to decode found");
} else {
let result = std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes);
return Ok(result.to_vec());
} }
} else {
let mut current_index = 0;
let r = mailmime_part_parse(
(*mime_data).dt_data.dt_text.dt_data,
(*mime_data).dt_data.dt_text.dt_length,
&mut current_index,
mime_transfer_encoding,
&mut transfer_decoding_buffer,
&mut decoded_data_bytes,
);
if r != MAILIMF_NO_ERROR as libc::c_int
|| transfer_decoding_buffer.is_null()
|| decoded_data_bytes <= 0
{
return false;
}
decoded_data = transfer_decoding_buffer;
} }
*ret_decoded_data = decoded_data; let mut current_index = 0;
*ret_decoded_data_bytes = decoded_data_bytes; let mut transfer_decoding_buffer = ptr::null_mut();
*ret_to_mmap_string_unref = transfer_decoding_buffer; let mut decoded_data_bytes = 0;
true let r = mailmime_part_parse(
(*mime_data).dt_data.dt_text.dt_data,
(*mime_data).dt_data.dt_text.dt_length,
&mut current_index,
mime_transfer_encoding,
&mut transfer_decoding_buffer,
&mut decoded_data_bytes,
);
if r == MAILIMF_NO_ERROR as libc::c_int
&& !transfer_decoding_buffer.is_null()
&& decoded_data_bytes > 0
{
let result =
std::slice::from_raw_parts(transfer_decoding_buffer as *const u8, decoded_data_bytes);
mmap_string_unref(transfer_decoding_buffer);
return Ok(result.to_vec());
}
Err(format_err!("Failed to to decode"))
} }
pub unsafe fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet<String> { pub unsafe fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet<String> {

View File

@@ -8,7 +8,6 @@ use mmime::mailimf_types::*;
use mmime::mailmime::*; use mmime::mailmime::*;
use mmime::mailmime_content::*; use mmime::mailmime_content::*;
use mmime::mailmime_types::*; use mmime::mailmime_types::*;
use mmime::mmapstring::*;
use mmime::other::*; use mmime::other::*;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
@@ -800,22 +799,13 @@ unsafe fn handle_reports(
b"disposition-notification\x00" as *const u8 as *const libc::c_char, b"disposition-notification\x00" as *const u8 as *const libc::c_char,
) == 0 ) == 0
{ {
let mut report_body = std::ptr::null(); if let Ok(report_body) = mailmime_transfer_decode(report_data) {
let mut report_body_bytes = 0;
let mut to_mmap_string_unref = std::ptr::null_mut();
if mailmime_transfer_decode(
report_data,
&mut report_body,
&mut report_body_bytes,
&mut to_mmap_string_unref,
) {
let mut report_parsed = std::ptr::null_mut(); let mut report_parsed = std::ptr::null_mut();
let mut dummy = 0; let mut dummy = 0;
if mailmime_parse( if mailmime_parse(
report_body, report_body.as_ptr() as *const _,
report_body_bytes, report_body.len(),
&mut dummy, &mut dummy,
&mut report_parsed, &mut report_parsed,
) == MAIL_NO_ERROR as libc::c_int ) == MAIL_NO_ERROR as libc::c_int
@@ -867,9 +857,6 @@ unsafe fn handle_reports(
} }
mailmime_free(report_parsed); mailmime_free(report_parsed);
} }
if !to_mmap_string_unref.is_null() {
mmap_string_unref(to_mmap_string_unref);
}
} }
} }
} }

View File

@@ -1093,25 +1093,8 @@ Sent with my Delta Chat Messenger: https://delta.chat";
}; };
unsafe { unsafe {
let msg1 = (*decrypted_mime).mm_data.mm_message.mm_msg_mime; let msg1 = (*decrypted_mime).mm_data.mm_message.mm_msg_mime;
let mut decoded_data = ptr::null(); let data = mailmime_transfer_decode(msg1).unwrap();
let mut decoded_data_bytes = 0; println!("{:?}", String::from_utf8_lossy(&data));
let mut transfer_decoding_buffer: *mut libc::c_char = ptr::null_mut();
assert!(mailmime_transfer_decode(
msg1,
&mut decoded_data,
&mut decoded_data_bytes,
&mut transfer_decoding_buffer,
));
println!(
"{:?}",
String::from_utf8_lossy(std::slice::from_raw_parts(
decoded_data as *const u8,
decoded_data_bytes as usize,
))
);
free(decoded_data as *mut _);
} }
assert_eq!(res, 0); assert_eq!(res, 0);