diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index 02aed946d..2c01e5b69 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -25,27 +25,10 @@ use crate::param::*; use crate::stock::StockMessage; use crate::x::*; -/* Parse MIME body; this is the text part of an IMF, see https://tools.ietf.org/html/rfc5322 -dc_mimeparser_t has no deep dependencies to Context or to the database -(Context is used for logging only). */ -#[derive(Debug, Clone)] -#[repr(C)] -pub struct dc_mimepart_t { - pub type_0: Viewtype, - pub is_meta: bool, - pub int_mimetype: libc::c_int, - pub msg: Option, - pub msg_raw: Option, - pub bytes: libc::c_int, - pub param: Params, -} - -/* * - * @class dc_mimeparser_t - */ -#[allow(non_camel_case_types, missing_debug_implementations)] -pub struct dc_mimeparser_t<'a> { - pub parts: Vec, +#[derive(Debug)] +pub struct MimeParser<'a> { + pub context: &'a Context, + pub parts: Vec, pub mimeroot: *mut mailmime, pub header: HashMap, pub header_root: *mut mailimf_fields, @@ -55,454 +38,535 @@ pub struct dc_mimeparser_t<'a> { pub decrypting_failed: bool, pub e2ee_helper: E2eeHelper, pub is_forwarded: bool, - pub context: &'a Context, pub reports: Vec<*mut mailmime>, pub is_system_message: libc::c_int, pub location_kml: Option, pub message_kml: Option, } -pub fn dc_mimeparser_new(context: &Context) -> dc_mimeparser_t { - dc_mimeparser_t { - parts: Vec::new(), - mimeroot: std::ptr::null_mut(), - header: Default::default(), - header_root: std::ptr::null_mut(), - header_protected: std::ptr::null_mut(), - subject: None, - is_send_by_messenger: false, - decrypting_failed: false, - e2ee_helper: Default::default(), - is_forwarded: false, - context, - reports: Vec::new(), - is_system_message: 0, - location_kml: None, - message_kml: None, - } -} - -pub unsafe fn dc_mimeparser_unref(mimeparser: &mut dc_mimeparser_t) { - dc_mimeparser_empty(mimeparser); -} - -unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) { - mimeparser.parts = vec![]; - mimeparser.header_root = ptr::null_mut(); - mimeparser.header.clear(); - if !mimeparser.header_protected.is_null() { - mailimf_fields_free(mimeparser.header_protected); - mimeparser.header_protected = ptr::null_mut() - } - mimeparser.is_send_by_messenger = false; - mimeparser.is_system_message = 0i32; - mimeparser.subject = None; - if !mimeparser.mimeroot.is_null() { - mailmime_free(mimeparser.mimeroot); - mimeparser.mimeroot = ptr::null_mut() - } - mimeparser.is_forwarded = false; - mimeparser.reports.clear(); - mimeparser.decrypting_failed = false; - mimeparser.e2ee_helper.thanks(); - - mimeparser.location_kml = None; - mimeparser.message_kml = None; -} - -const DC_MIMETYPE_AC_SETUP_FILE: i32 = 111; - -pub unsafe fn dc_mimeparser_parse<'a>(context: &'a Context, body: &[u8]) -> dc_mimeparser_t<'a> { - let r: libc::c_int; - let mut index: libc::size_t = 0; - let optional_field: *mut mailimf_optional_field; - let mut mimeparser = dc_mimeparser_new(context); - - r = mailmime_parse( - body.as_ptr() as *const libc::c_char, - body.len(), - &mut index, - &mut mimeparser.mimeroot, - ); - if r == MAILIMF_NO_ERROR as libc::c_int && !mimeparser.mimeroot.is_null() { - mimeparser - .e2ee_helper - .decrypt(mimeparser.context, mimeparser.mimeroot); - let mimeparser_ref = &mut mimeparser; - dc_mimeparser_parse_mime_recursive(mimeparser_ref, mimeparser_ref.mimeroot); - let field: *mut mailimf_field = dc_mimeparser_lookup_field(&mimeparser, "Subject"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int { - let subj = (*(*field).fld_data.fld_subject).sbj_value; - - mimeparser.subject = as_opt_str(subj).map(dc_decode_header_words_safe); +impl<'a> MimeParser<'a> { + pub fn new(context: &'a Context) -> Self { + MimeParser { + parts: Vec::new(), + mimeroot: std::ptr::null_mut(), + header: Default::default(), + header_root: std::ptr::null_mut(), + header_protected: std::ptr::null_mut(), + subject: None, + is_send_by_messenger: false, + decrypting_failed: false, + e2ee_helper: Default::default(), + is_forwarded: false, + context, + reports: Vec::new(), + is_system_message: 0, + location_kml: None, + message_kml: None, } - if !dc_mimeparser_lookup_optional_field(&mut mimeparser, "Chat-Version").is_null() { - mimeparser.is_send_by_messenger = true - } - if !dc_mimeparser_lookup_field(&mut mimeparser, "Autocrypt-Setup-Message").is_null() { - let has_setup_file = mimeparser - .parts - .iter() - .any(|p| p.int_mimetype == DC_MIMETYPE_AC_SETUP_FILE); + } - if has_setup_file { - mimeparser.is_system_message = 6i32; + pub unsafe fn parse(&mut self, body: &[u8]) { + let mut index = 0; - // TODO: replace the following code with this - // once drain_filter stabilizes. - // - // See https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter - // and https://github.com/rust-lang/rust/issues/43244 - // - // mimeparser - // .parts - // .drain_filter(|part| part.int_mimetype != 111) - // .for_each(|part| dc_mimepart_unref(part)); + let r = mailmime_parse( + body.as_ptr() as *const libc::c_char, + body.len(), + &mut index, + &mut self.mimeroot, + ); - let mut i = 0; - while i != mimeparser.parts.len() { - if mimeparser.parts[i].int_mimetype != 111 { - mimeparser.parts.remove(i); - } else { - i += 1; + if r == MAILIMF_NO_ERROR as libc::c_int && !self.mimeroot.is_null() { + self.e2ee_helper.decrypt(self.context, self.mimeroot); + self.parse_mime_recursive(self.mimeroot); + + if let Some(field) = self.lookup_field("Subject") { + if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int { + let subj = (*(*field).fld_data.fld_subject).sbj_value; + + self.subject = as_opt_str(subj).map(dc_decode_header_words_safe); + } + } + + if self.lookup_optional_field("Chat-Version").is_some() { + self.is_send_by_messenger = true + } + if self.lookup_field("Autocrypt-Setup-Message").is_some() { + let has_setup_file = self + .parts + .iter() + .any(|p| p.mimetype == DC_MIMETYPE_AC_SETUP_FILE); + + if has_setup_file { + self.is_system_message = 6i32; + + // TODO: replace the following code with this + // once drain_filter stabilizes. + // + // See https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter + // and https://github.com/rust-lang/rust/issues/43244 + // + // mimeparser + // .parts + // .drain_filter(|part| part.int_mimetype != 111) + // .for_each(|part| dc_mimepart_unref(part)); + + let mut i = 0; + while i != self.parts.len() { + if self.parts[i].mimetype != 111 { + self.parts.remove(i); + } else { + i += 1; + } } } - } - } else { - optional_field = dc_mimeparser_lookup_optional_field(&mut mimeparser, "Chat-Content"); - if !optional_field.is_null() && !(*optional_field).fld_value.is_null() { - if strcmp( - (*optional_field).fld_value, - b"location-streaming-enabled\x00" as *const u8 as *const libc::c_char, - ) == 0i32 - { - mimeparser.is_system_message = 8i32 - } - } - } - if !dc_mimeparser_lookup_field(&mut mimeparser, "Chat-Group-Image").is_null() - && !mimeparser.parts.is_empty() - { - let textpart = &mimeparser.parts[0]; - if textpart.type_0 == Viewtype::Text { - if mimeparser.parts.len() >= 2 { - let imgpart = &mut mimeparser.parts[1]; - if imgpart.type_0 == Viewtype::Image { - imgpart.is_meta = true; - } - } - } - } - if mimeparser.is_send_by_messenger && mimeparser.parts.len() == 2 { - let need_drop = { - let textpart = &mimeparser.parts[0]; - let filepart = &mimeparser.parts[1]; - textpart.type_0 == Viewtype::Text - && (filepart.type_0 == Viewtype::Image - || filepart.type_0 == Viewtype::Gif - || filepart.type_0 == Viewtype::Audio - || filepart.type_0 == Viewtype::Voice - || filepart.type_0 == Viewtype::Video - || filepart.type_0 == Viewtype::File) - && !filepart.is_meta - }; - - if need_drop { - let mut filepart = mimeparser.parts.swap_remove(1); - - // insert new one - filepart.msg = mimeparser.parts[0].msg.as_ref().map(|s| s.to_string()); - - // forget the one we use now - mimeparser.parts[0].msg = None; - - // swap new with old - std::mem::replace(&mut mimeparser.parts[0], filepart); - } - } - if let Some(ref subject) = mimeparser.subject { - let mut prepend_subject: libc::c_int = 1i32; - if !mimeparser.decrypting_failed { - let colon = subject.find(':'); - if colon == Some(2) - || colon == Some(3) - || mimeparser.is_send_by_messenger - || subject.contains("Chat:") - { - prepend_subject = 0i32 - } - } - if 0 != prepend_subject { - let subj = if let Some(n) = subject.find('[') { - &subject[0..n] - } else { - subject - } - .trim(); - - if !subj.is_empty() { - let subj_c = CString::yolo(subj); - for part in mimeparser.parts.iter_mut() { - if part.type_0 == Viewtype::Text { - let msg_c = part.msg.as_ref().unwrap().strdup(); - 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_c.as_ptr(), - msg_c, - ); - free(msg_c.cast()); - part.msg = Some(to_string_lossy(new_txt)); - free(new_txt.cast()); - break; + } else { + if let Some(optional_field) = self.lookup_optional_field("Chat-Content") { + if !(*optional_field).fld_value.is_null() { + if strcmp( + (*optional_field).fld_value, + b"location-streaming-enabled\x00" as *const u8 as *const libc::c_char, + ) == 0i32 + { + self.is_system_message = 8i32; } } } } - } - if mimeparser.is_forwarded { - for part in mimeparser.parts.iter_mut() { - part.param.set_int(Param::Forwarded, 1); - } - } - if mimeparser.parts.len() == 1 { - if mimeparser.parts[0].type_0 == Viewtype::Audio { - if !dc_mimeparser_lookup_optional_field(&mimeparser, "Chat-Voice-Message").is_null() - { - let part_mut = &mut mimeparser.parts[0]; - part_mut.type_0 = Viewtype::Voice; - } - } - let part = &mimeparser.parts[0]; - if part.type_0 == Viewtype::Audio - || part.type_0 == Viewtype::Voice - || part.type_0 == Viewtype::Video - { - let field_0 = dc_mimeparser_lookup_optional_field(&mimeparser, "Chat-Duration"); - if !field_0.is_null() { - let duration_ms: libc::c_int = dc_atoi_null_is_0((*field_0).fld_value); - if duration_ms > 0i32 && duration_ms < 24i32 * 60i32 * 60i32 * 1000i32 { - let part_mut = &mut mimeparser.parts[0]; - part_mut.param.set_int(Param::Duration, duration_ms); + if self.lookup_field("Chat-Group-Image").is_some() && !self.parts.is_empty() { + let textpart = &self.parts[0]; + if textpart.typ == Viewtype::Text { + if self.parts.len() >= 2 { + let imgpart = &mut self.parts[1]; + if imgpart.typ == Viewtype::Image { + imgpart.is_meta = true; + } } } } - } - if !mimeparser.decrypting_failed { - let dn_field: *const mailimf_optional_field = dc_mimeparser_lookup_optional_field( - &mimeparser, - "Chat-Disposition-Notification-To", - ); - if !dn_field.is_null() && dc_mimeparser_get_last_nonmeta(&mut mimeparser).is_some() { - let mut mb_list: *mut mailimf_mailbox_list = ptr::null_mut(); - let mut index_0: libc::size_t = 0; - if mailimf_mailbox_list_parse( - (*dn_field).fld_value, - strlen((*dn_field).fld_value), - &mut index_0, - &mut mb_list, - ) == MAILIMF_NO_ERROR as libc::c_int - && !mb_list.is_null() - { - let dn_to_addr: *mut libc::c_char = mailimf_find_first_addr(mb_list); - if !dn_to_addr.is_null() { - let from_field: *mut mailimf_field = - dc_mimeparser_lookup_field(&mimeparser, "From"); - if !from_field.is_null() - && (*from_field).fld_type == MAILIMF_FIELD_FROM as libc::c_int - && !(*from_field).fld_data.fld_from.is_null() - { - let from_addr: *mut libc::c_char = mailimf_find_first_addr( - (*(*from_field).fld_data.fld_from).frm_mb_list, - ); - if !from_addr.is_null() { - if strcmp(from_addr, dn_to_addr) == 0i32 { - if let Some(part_4) = - dc_mimeparser_get_last_nonmeta(&mut mimeparser) - { - part_4.param.set_int(Param::WantsMdn, 1); - } - } - free(from_addr as *mut libc::c_void); + if self.is_send_by_messenger && self.parts.len() == 2 { + let need_drop = { + let textpart = &self.parts[0]; + let filepart = &self.parts[1]; + textpart.typ == Viewtype::Text + && (filepart.typ == Viewtype::Image + || filepart.typ == Viewtype::Gif + || filepart.typ == Viewtype::Audio + || filepart.typ == Viewtype::Voice + || filepart.typ == Viewtype::Video + || filepart.typ == Viewtype::File) + && !filepart.is_meta + }; + + if need_drop { + let mut filepart = self.parts.swap_remove(1); + + // insert new one + filepart.msg = self.parts[0].msg.as_ref().map(|s| s.to_string()); + + // forget the one we use now + self.parts[0].msg = None; + + // swap new with old + std::mem::replace(&mut self.parts[0], filepart); + } + } + if let Some(ref subject) = self.subject { + let mut prepend_subject: libc::c_int = 1i32; + if !self.decrypting_failed { + let colon = subject.find(':'); + if colon == Some(2) + || colon == Some(3) + || self.is_send_by_messenger + || subject.contains("Chat:") + { + prepend_subject = 0i32 + } + } + if 0 != prepend_subject { + let subj = if let Some(n) = subject.find('[') { + &subject[0..n] + } else { + subject + } + .trim(); + + if !subj.is_empty() { + let subj_c = CString::yolo(subj); + for part in self.parts.iter_mut() { + if part.typ == Viewtype::Text { + let msg_c = part.msg.as_ref().unwrap().strdup(); + 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_c.as_ptr(), + msg_c, + ); + free(msg_c.cast()); + part.msg = Some(to_string_lossy(new_txt)); + free(new_txt.cast()); + break; } } - free(dn_to_addr as *mut libc::c_void); } - mailimf_mailbox_list_free(mb_list); + } + } + if self.is_forwarded { + for part in self.parts.iter_mut() { + part.param.set_int(Param::Forwarded, 1); + } + } + if self.parts.len() == 1 { + if self.parts[0].typ == Viewtype::Audio { + if self.lookup_optional_field("Chat-Voice-Message").is_some() { + let part_mut = &mut self.parts[0]; + part_mut.typ = Viewtype::Voice; + } + } + let part = &self.parts[0]; + if part.typ == Viewtype::Audio + || part.typ == Viewtype::Voice + || part.typ == Viewtype::Video + { + if let Some(field_0) = self.lookup_optional_field("Chat-Duration") { + let duration_ms: libc::c_int = dc_atoi_null_is_0((*field_0).fld_value); + if duration_ms > 0i32 && duration_ms < 24i32 * 60i32 * 60i32 * 1000i32 { + let part_mut = &mut self.parts[0]; + part_mut.param.set_int(Param::Duration, duration_ms); + } + } + } + } + if !self.decrypting_failed { + if let Some(dn_field) = + self.lookup_optional_field("Chat-Disposition-Notification-To") + { + if self.get_last_nonmeta().is_some() { + let mut mb_list: *mut mailimf_mailbox_list = ptr::null_mut(); + let mut index_0 = 0; + if mailimf_mailbox_list_parse( + (*dn_field).fld_value, + strlen((*dn_field).fld_value), + &mut index_0, + &mut mb_list, + ) == MAILIMF_NO_ERROR as libc::c_int + && !mb_list.is_null() + { + if let Some(dn_to_addr) = mailimf_find_first_addr(mb_list) { + if let Some(from_field) = self.lookup_field("From") { + if (*from_field).fld_type == MAILIMF_FIELD_FROM as libc::c_int + && !(*from_field).fld_data.fld_from.is_null() + { + let from_addr = mailimf_find_first_addr( + (*(*from_field).fld_data.fld_from).frm_mb_list, + ); + if let Some(from_addr) = from_addr { + if from_addr == dn_to_addr { + if let Some(part_4) = self.get_last_nonmeta() { + part_4.param.set_int(Param::WantsMdn, 1); + } + } + } + } + } + } + mailimf_mailbox_list_free(mb_list); + } + } } } } - } - /* Cleanup - and try to create at least an empty part if there are no parts yet */ - if dc_mimeparser_get_last_nonmeta(&mut mimeparser).is_none() && mimeparser.reports.is_empty() { - let mut part_5 = dc_mimepart_new(); - part_5.type_0 = Viewtype::Text; - part_5.msg = Some("".into()); + /* Cleanup - and try to create at least an empty part if there are no parts yet */ + if self.get_last_nonmeta().is_none() && self.reports.is_empty() { + let mut part_5 = Part::default(); + part_5.typ = Viewtype::Text; + part_5.msg = Some("".into()); - if let Some(ref subject) = mimeparser.subject { - if !mimeparser.is_send_by_messenger { - part_5.msg = Some(subject.to_string()) + if let Some(ref subject) = self.subject { + if !self.is_send_by_messenger { + part_5.msg = Some(subject.to_string()) + } + } + self.parts.push(part_5); + } + } + + pub fn get_last_nonmeta(&mut self) -> Option<&mut Part> { + self.parts.iter_mut().rev().find(|part| !part.is_meta) + } + + /* the following functions can be used only after a call to dc_mimeparser_parse() */ + + pub fn lookup_field(&self, field_name: &str) -> Option<*mut mailimf_field> { + match self.header.get(field_name) { + Some(v) => { + if v.is_null() { + None + } else { + Some(*v) + } + } + None => None, + } + } + + pub fn lookup_optional_field(&self, field_name: &str) -> Option<*mut mailimf_optional_field> { + if let Some(field) = self.lookup_field(field_name) { + if unsafe { (*field).fld_type } == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int { + let val = unsafe { (*field).fld_data.fld_optional_field }; + if val.is_null() { + return None; + } else { + return Some(val); + } } } - mimeparser.parts.push(part_5); - }; - mimeparser -} -/******************************************************************************* - * a MIME part - ******************************************************************************/ -unsafe fn dc_mimepart_new() -> dc_mimepart_t { - dc_mimepart_t { - type_0: Viewtype::Unknown, - is_meta: false, - int_mimetype: 0, - msg: None, - msg_raw: None, - bytes: 0, - param: Params::new(), + None } -} -pub fn dc_mimeparser_get_last_nonmeta<'a>( - mimeparser: &'a mut dc_mimeparser_t, -) -> Option<&'a mut dc_mimepart_t> { - mimeparser.parts.iter_mut().rev().find(|part| !part.is_meta) -} - -/*the result must be freed*/ -pub unsafe fn mailimf_find_first_addr(mb_list: *const mailimf_mailbox_list) -> *mut libc::c_char { - if mb_list.is_null() { - return ptr::null_mut(); - } - let mut cur: *mut clistiter = (*(*mb_list).mb_list).first; - while !cur.is_null() { - let mb: *mut mailimf_mailbox = (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) as *mut mailimf_mailbox; - if !mb.is_null() && !(*mb).mb_addr_spec.is_null() { - return addr_normalize(as_str((*mb).mb_addr_spec)).strdup(); + unsafe fn parse_mime_recursive(&mut self, mime: *mut mailmime) -> libc::c_int { + if mime.is_null() { + return 0; } - cur = if !cur.is_null() { - (*cur).next - } else { - ptr::null_mut() - } - } + let mut any_part_added = 0; + let mut cur: *mut clistiter; - ptr::null_mut() -} - -/* the following functions can be used only after a call to dc_mimeparser_parse() */ - -pub fn dc_mimeparser_lookup_field( - mimeparser: &dc_mimeparser_t, - field_name: &str, -) -> *mut mailimf_field { - mimeparser - .header - .get(field_name) - .map(|v| *v) - .unwrap_or_else(|| std::ptr::null_mut()) -} - -pub unsafe fn dc_mimeparser_lookup_optional_field( - mimeparser: &dc_mimeparser_t, - field_name: &str, -) -> *mut mailimf_optional_field { - let field = mimeparser - .header - .get(field_name) - .map(|v| *v) - .unwrap_or_else(|| std::ptr::null_mut()); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int { - return (*field).fld_data.fld_optional_field; - } - - ptr::null_mut() -} - -unsafe fn dc_mimeparser_parse_mime_recursive( - mimeparser: &mut dc_mimeparser_t, - mime: *mut mailmime, -) -> libc::c_int { - let mut any_part_added: libc::c_int = 0i32; - let mut cur: *mut clistiter; - if mime.is_null() { - return 0i32; - } - if !mailmime_find_ct_parameter( - mime, - b"protected-headers\x00" as *const u8 as *const libc::c_char, - ) - .is_null() - { - if (*mime).mm_type == MAILMIME_SINGLE as libc::c_int - && (*(*(*mime).mm_content_type).ct_type).tp_type - == MAILMIME_TYPE_DISCRETE_TYPE as libc::c_int - && (*(*(*(*mime).mm_content_type).ct_type) - .tp_data - .tp_discrete_type) - .dt_type - == MAILMIME_DISCRETE_TYPE_TEXT as libc::c_int - && !(*(*mime).mm_content_type).ct_subtype.is_null() - && strcmp( - (*(*mime).mm_content_type).ct_subtype, - b"rfc822-headers\x00" as *const u8 as *const libc::c_char, - ) == 0i32 + if !mailmime_find_ct_parameter( + mime, + b"protected-headers\x00" as *const u8 as *const libc::c_char, + ) + .is_null() { - info!( - mimeparser.context, - "Protected headers found in text/rfc822-headers attachment: Will be ignored.", - ); - return 0i32; - } - if mimeparser.header_protected.is_null() { - let mut dummy: libc::size_t = 0; - if mailimf_envelope_and_optional_fields_parse( - (*mime).mm_mime_start, - (*mime).mm_length, - &mut dummy, - &mut mimeparser.header_protected, - ) != MAILIMF_NO_ERROR as libc::c_int - || mimeparser.header_protected.is_null() + if (*mime).mm_type == MAILMIME_SINGLE as libc::c_int + && (*(*(*mime).mm_content_type).ct_type).tp_type + == MAILMIME_TYPE_DISCRETE_TYPE as libc::c_int + && (*(*(*(*mime).mm_content_type).ct_type) + .tp_data + .tp_discrete_type) + .dt_type + == MAILMIME_DISCRETE_TYPE_TEXT as libc::c_int + && !(*(*mime).mm_content_type).ct_subtype.is_null() + && strcmp( + (*(*mime).mm_content_type).ct_subtype, + b"rfc822-headers\x00" as *const u8 as *const libc::c_char, + ) == 0i32 { - warn!(mimeparser.context, "Protected headers parsing error.",); - } else { - hash_header( - &mut mimeparser.header, - mimeparser.header_protected, - mimeparser.context, + info!( + self.context, + "Protected headers found in text/rfc822-headers attachment: Will be ignored.", ); + return 0i32; } - } else { - info!( - mimeparser.context, + if self.header_protected.is_null() { + let mut dummy = 0; + if mailimf_envelope_and_optional_fields_parse( + (*mime).mm_mime_start, + (*mime).mm_length, + &mut dummy, + &mut self.header_protected, + ) != MAILIMF_NO_ERROR as libc::c_int + || self.header_protected.is_null() + { + warn!(self.context, "Protected headers parsing error.",); + } else { + hash_header(&mut self.header, self.header_protected); + } + } else { + info!( + self.context, "Protected headers found in MIME header: Will be ignored as we already found an outer one." ); + } } - } - match (*mime).mm_type { - // TODO match on enums /rtn - 1 => any_part_added = dc_mimeparser_add_single_part_if_known(mimeparser, mime), - 2 => { - match mailmime_get_mime_type(mime, ptr::null_mut(), ptr::null_mut()) { - 10 => { - cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; - while !cur.is_null() { - let childmime: *mut mailmime = (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) as *mut mailmime; - if mailmime_get_mime_type(childmime, ptr::null_mut(), ptr::null_mut()) - == 30i32 - { - any_part_added = - dc_mimeparser_parse_mime_recursive(mimeparser, childmime); - break; - } else { + match (*mime).mm_type { + // TODO match on enums /rtn + 1 => any_part_added = self.add_single_part_if_known(mime), + 2 => { + match mailmime_get_mime_type(mime, ptr::null_mut(), ptr::null_mut()) { + 10 => { + cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; + while !cur.is_null() { + let childmime: *mut mailmime = (if !cur.is_null() { + (*cur).data + } else { + ptr::null_mut() + }) + as *mut mailmime; + if mailmime_get_mime_type(childmime, ptr::null_mut(), ptr::null_mut()) + == 30i32 + { + any_part_added = self.parse_mime_recursive(childmime); + break; + } else { + cur = if !cur.is_null() { + (*cur).next + } else { + ptr::null_mut() + } + } + } + if 0 == any_part_added { + cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; + while !cur.is_null() { + let childmime_0: *mut mailmime = (if !cur.is_null() { + (*cur).data + } else { + ptr::null_mut() + }) + as *mut mailmime; + if mailmime_get_mime_type( + childmime_0, + ptr::null_mut(), + ptr::null_mut(), + ) == 60i32 + { + any_part_added = self.parse_mime_recursive(childmime_0); + break; + } else { + cur = if !cur.is_null() { + (*cur).next + } else { + ptr::null_mut() + } + } + } + } + if 0 == any_part_added { + cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; + while !cur.is_null() { + if 0 != self.parse_mime_recursive( + (if !cur.is_null() { + (*cur).data + } else { + ptr::null_mut() + }) as *mut mailmime, + ) { + any_part_added = 1i32; + /* out of for() */ + break; + } else { + cur = if !cur.is_null() { + (*cur).next + } else { + ptr::null_mut() + } + } + } + } + } + 20 => { + cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; + if !cur.is_null() { + any_part_added = self.parse_mime_recursive( + (if !cur.is_null() { + (*cur).data + } else { + ptr::null_mut() + }) as *mut mailmime, + ) + } + } + 40 => { + let mut part = Part::default(); + part.typ = Viewtype::Text; + let msg_body = self.context.stock_str(StockMessage::CantDecryptMsgBody); + + let txt = format!("[{}]", msg_body); + part.msg_raw = Some(txt.clone()); + part.msg = Some(txt); + + self.parts.push(part); + any_part_added = 1i32; + self.decrypting_failed = true; + } + 46 => { + cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; + if !cur.is_null() { + any_part_added = self.parse_mime_recursive( + (if !cur.is_null() { + (*cur).data + } else { + ptr::null_mut() + }) as *mut mailmime, + ) + } + } + 45 => { + if (*(*mime).mm_data.mm_multipart.mm_mp_list).count >= 2i32 { + let report_type = mailmime_find_ct_parameter( + mime, + b"report-type\x00" as *const u8 as *const libc::c_char, + ); + if !report_type.is_null() + && !(*report_type).pa_value.is_null() + && strcmp( + (*report_type).pa_value, + b"disposition-notification\x00" as *const u8 + as *const libc::c_char, + ) == 0i32 + { + self.reports.push(mime); + } else { + any_part_added = self.parse_mime_recursive( + (if !(*(*mime).mm_data.mm_multipart.mm_mp_list).first.is_null() + { + (*(*(*mime).mm_data.mm_multipart.mm_mp_list).first).data + } else { + ptr::null_mut() + }) as *mut mailmime, + ) + } + } + } + _ => { + let mut skip_part = ptr::null_mut(); + let mut html_part = ptr::null_mut(); + let mut plain_cnt = 0i32; + let mut html_cnt = 0i32; + cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; + while !cur.is_null() { + let childmime_1 = (if !cur.is_null() { + (*cur).data + } else { + ptr::null_mut() + }) as *mut mailmime; + if mailmime_get_mime_type(childmime_1, ptr::null_mut(), ptr::null_mut()) + == 60i32 + { + plain_cnt += 1 + } else if mailmime_get_mime_type( + childmime_1, + ptr::null_mut(), + ptr::null_mut(), + ) == 70i32 + { + html_part = childmime_1; + html_cnt += 1 + } + cur = if !cur.is_null() { + (*cur).next + } else { + ptr::null_mut() + } + } + if plain_cnt == 1i32 && html_cnt == 1i32 { + warn!( + self.context, + "HACK: multipart/mixed message found with PLAIN and HTML, we\'ll skip the HTML part as this seems to be unwanted." + ); + skip_part = html_part + } + cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; + while !cur.is_null() { + let childmime_2 = (if !cur.is_null() { + (*cur).data + } else { + ptr::null_mut() + }) as *mut mailmime; + if childmime_2 != skip_part { + if 0 != self.parse_mime_recursive(childmime_2) { + any_part_added = 1i32 + } + } cur = if !cur.is_null() { (*cur).next } else { @@ -510,262 +574,511 @@ unsafe fn dc_mimeparser_parse_mime_recursive( } } } - if 0 == any_part_added { - cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; - while !cur.is_null() { - let childmime_0: *mut mailmime = (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) - as *mut mailmime; - if mailmime_get_mime_type(childmime_0, ptr::null_mut(), ptr::null_mut()) - == 60i32 - { - any_part_added = - dc_mimeparser_parse_mime_recursive(mimeparser, childmime_0); - break; - } else { - cur = if !cur.is_null() { - (*cur).next - } else { - ptr::null_mut() - } - } - } - } - if 0 == any_part_added { - cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; - while !cur.is_null() { - if 0 != dc_mimeparser_parse_mime_recursive( - mimeparser, - (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) as *mut mailmime, - ) { - any_part_added = 1i32; - /* out of for() */ - break; - } else { - cur = if !cur.is_null() { - (*cur).next - } else { - ptr::null_mut() - } - } - } - } - } - 20 => { - cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; - if !cur.is_null() { - any_part_added = dc_mimeparser_parse_mime_recursive( - mimeparser, - (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) as *mut mailmime, - ) - } - } - 40 => { - let mut part = dc_mimepart_new(); - part.type_0 = Viewtype::Text; - let msg_body = mimeparser - .context - .stock_str(StockMessage::CantDecryptMsgBody); - - let txt = format!("[{}]", msg_body); - part.msg_raw = Some(txt.clone()); - part.msg = Some(txt); - - mimeparser.parts.push(part); - any_part_added = 1i32; - mimeparser.decrypting_failed = true; - } - 46 => { - cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; - if !cur.is_null() { - any_part_added = dc_mimeparser_parse_mime_recursive( - mimeparser, - (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) as *mut mailmime, - ) - } - } - 45 => { - if (*(*mime).mm_data.mm_multipart.mm_mp_list).count >= 2i32 { - let report_type: *mut mailmime_parameter = mailmime_find_ct_parameter( - mime, - b"report-type\x00" as *const u8 as *const libc::c_char, - ); - if !report_type.is_null() - && !(*report_type).pa_value.is_null() - && strcmp( - (*report_type).pa_value, - b"disposition-notification\x00" as *const u8 as *const libc::c_char, - ) == 0i32 - { - mimeparser.reports.push(mime); - } else { - any_part_added = dc_mimeparser_parse_mime_recursive( - mimeparser, - (if !(*(*mime).mm_data.mm_multipart.mm_mp_list).first.is_null() { - (*(*(*mime).mm_data.mm_multipart.mm_mp_list).first).data - } else { - ptr::null_mut() - }) as *mut mailmime, - ) - } - } - } - _ => { - let mut skip_part: *mut mailmime = ptr::null_mut(); - let mut html_part: *mut mailmime = ptr::null_mut(); - let mut plain_cnt: libc::c_int = 0i32; - let mut html_cnt: libc::c_int = 0i32; - cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; - while !cur.is_null() { - let childmime_1: *mut mailmime = (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) - as *mut mailmime; - if mailmime_get_mime_type(childmime_1, ptr::null_mut(), ptr::null_mut()) - == 60i32 - { - plain_cnt += 1 - } else if mailmime_get_mime_type( - childmime_1, - ptr::null_mut(), - ptr::null_mut(), - ) == 70i32 - { - html_part = childmime_1; - html_cnt += 1 - } - cur = if !cur.is_null() { - (*cur).next - } else { - ptr::null_mut() - } - } - if plain_cnt == 1i32 && html_cnt == 1i32 { - warn!( - mimeparser.context, - "HACK: multipart/mixed message found with PLAIN and HTML, we\'ll skip the HTML part as this seems to be unwanted." - ); - skip_part = html_part - } - cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first; - while !cur.is_null() { - let childmime_2: *mut mailmime = (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) - as *mut mailmime; - if childmime_2 != skip_part { - if 0 != dc_mimeparser_parse_mime_recursive(mimeparser, childmime_2) { - any_part_added = 1i32 - } - } - cur = if !cur.is_null() { - (*cur).next - } else { - ptr::null_mut() - } - } } } - } - 3 => { - if mimeparser.header_root.is_null() { - mimeparser.header_root = (*mime).mm_data.mm_message.mm_fields; - hash_header( - &mut mimeparser.header, - mimeparser.header_root, - mimeparser.context, - ); - } - if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() { - any_part_added = dc_mimeparser_parse_mime_recursive( - mimeparser, - (*mime).mm_data.mm_message.mm_msg_mime, - ) - } - } - _ => {} - } - - any_part_added -} - -unsafe fn hash_header( - out: &mut HashMap, - in_0: *const mailimf_fields, - _context: &Context, -) { - if in_0.is_null() { - return; - } - let mut cur1: *mut clistiter = (*(*in_0).fld_list).first; - while !cur1.is_null() { - let field: *mut mailimf_field = (if !cur1.is_null() { - (*cur1).data - } else { - ptr::null_mut() - }) as *mut mailimf_field; - let mut key: *const libc::c_char = ptr::null(); - // TODO match on enums /rtn - match (*field).fld_type { - 1 => key = b"Return-Path\x00" as *const u8 as *const libc::c_char, - 9 => key = b"Date\x00" as *const u8 as *const libc::c_char, - 10 => key = b"From\x00" as *const u8 as *const libc::c_char, - 11 => key = b"Sender\x00" as *const u8 as *const libc::c_char, - 12 => key = b"Reply-To\x00" as *const u8 as *const libc::c_char, - 13 => key = b"To\x00" as *const u8 as *const libc::c_char, - 14 => key = b"Cc\x00" as *const u8 as *const libc::c_char, - 15 => key = b"Bcc\x00" as *const u8 as *const libc::c_char, - 16 => key = b"Message-ID\x00" as *const u8 as *const libc::c_char, - 17 => key = b"In-Reply-To\x00" as *const u8 as *const libc::c_char, - 18 => key = b"References\x00" as *const u8 as *const libc::c_char, - 19 => key = b"Subject\x00" as *const u8 as *const libc::c_char, - 22 => { - // MAILIMF_FIELD_OPTIONAL_FIELD - let optional_field: *const mailimf_optional_field = - (*field).fld_data.fld_optional_field; - if !optional_field.is_null() { - key = (*optional_field).fld_name + 3 => { + if self.header_root.is_null() { + self.header_root = (*mime).mm_data.mm_message.mm_fields; + hash_header(&mut self.header, self.header_root); + } + if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() { + any_part_added = + self.parse_mime_recursive((*mime).mm_data.mm_message.mm_msg_mime); } } _ => {} } - if !key.is_null() { + + any_part_added + } + + unsafe fn add_single_part_if_known(&mut self, mime: *mut mailmime) -> libc::c_int { + let mut ok_to_continue = true; + let old_part_count = self.parts.len(); + let mime_type: libc::c_int; + let mime_data: *mut mailmime_data; + let file_suffix: *mut libc::c_char = ptr::null_mut(); + let mut desired_filename: *mut libc::c_char = ptr::null_mut(); + let mut msg_type = Viewtype::Unknown; + let mut raw_mime: *mut libc::c_char = ptr::null_mut(); + /* mmap_string_unref()'d if set */ + let mut transfer_decoding_buffer: *mut libc::c_char = ptr::null_mut(); + /* must not be free()'d */ + let mut decoded_data: *const libc::c_char = ptr::null(); + let mut decoded_data_bytes = 0; + let mut simplifier: Option = None; + if !(mime.is_null() || (*mime).mm_data.mm_single.is_null()) { + mime_type = mailmime_get_mime_type(mime, &mut msg_type, &mut raw_mime); + mime_data = (*mime).mm_data.mm_single; + /* MAILMIME_DATA_FILE indicates, the data is in a file; AFAIK this is not used on parsing */ + if !((*mime_data).dt_type != MAILMIME_DATA_TEXT as libc::c_int + || (*mime_data).dt_data.dt_text.dt_data.is_null() + || (*mime_data).dt_data.dt_text.dt_length <= 0) + { + /* regard `Content-Transfer-Encoding:` */ + if mailmime_transfer_decode( + mime, + &mut decoded_data, + &mut decoded_data_bytes, + &mut transfer_decoding_buffer, + ) { + /* no always error - but no data */ + match mime_type { + 60 | 70 => { + if simplifier.is_none() { + simplifier = Some(Simplify::new()); + } + /* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */ + let charset = mailmime_content_charset_get((*mime).mm_content_type); + if !charset.is_null() + && strcmp(charset, b"utf-8\x00" as *const u8 as *const libc::c_char) + != 0i32 + && strcmp(charset, b"UTF-8\x00" as *const u8 as *const libc::c_char) + != 0i32 + { + if let Some(encoding) = Charset::for_label( + CStr::from_ptr(charset).to_str().unwrap().as_bytes(), + ) { + let data = std::slice::from_raw_parts( + decoded_data as *const u8, + decoded_data_bytes, + ); + + let (res, _, _) = encoding.decode(data); + if res.is_empty() { + /* no error - but nothing to add */ + ok_to_continue = false; + } else { + let b = res.as_bytes(); + decoded_data = b.as_ptr() as *const libc::c_char; + decoded_data_bytes = b.len(); + std::mem::forget(res); + } + } else { + warn!( + self.context, + "Cannot convert {} bytes from \"{}\" to \"utf-8\".", + decoded_data_bytes as libc::c_int, + as_str(charset), + ); + } + } + if ok_to_continue { + /* 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 simplified_txt = if decoded_data_bytes <= 0 + || decoded_data.is_null() + { + "".into() + } else { + let input_c = strndup(decoded_data, decoded_data_bytes as _); + let input = to_string_lossy(input_c); + let is_html = mime_type == 70; + free(input_c as *mut _); + + simplifier.unwrap().simplify(&input, is_html, is_msgrmsg) + }; + if !simplified_txt.is_empty() { + let mut part = Part::default(); + part.typ = Viewtype::Text; + part.mimetype = mime_type; + part.msg = Some(simplified_txt); + part.msg_raw = { + let raw_c = strndup( + decoded_data, + decoded_data_bytes as libc::c_ulong, + ); + let raw = to_string_lossy(raw_c); + free(raw_c.cast()); + Some(raw) + }; + self.do_add_single_part(part); + } + + if simplifier.unwrap().is_forwarded { + self.is_forwarded = true; + } + } + } + 80 | 90 | 100 | 110 | 111 => { + /* try to get file name from + `Content-Disposition: ... filename*=...` + or `Content-Disposition: ... filename*0*=... filename*1*=... filename*2*=...` + or `Content-Disposition: ... filename=...` */ + let mut filename_parts = String::new(); + + for cur1 in (*(*(*mime).mm_mime_fields).fld_list).into_iter() { + let field = cur1 as *mut mailmime_field; + if !field.is_null() + && (*field).fld_type + == MAILMIME_FIELD_DISPOSITION as libc::c_int + && !(*field).fld_data.fld_disposition.is_null() + { + let file_disposition: *mut mailmime_disposition = + (*field).fld_data.fld_disposition; + if !file_disposition.is_null() { + for cur2 in (*(*file_disposition).dsp_parms).into_iter() { + let dsp_param = cur2 as *mut mailmime_disposition_parm; + if !dsp_param.is_null() { + if (*dsp_param).pa_type + == MAILMIME_DISPOSITION_PARM_PARAMETER + as libc::c_int + && !(*dsp_param).pa_data.pa_parameter.is_null() + && !(*(*dsp_param).pa_data.pa_parameter) + .pa_name + .is_null() + && strncmp( + (*(*dsp_param).pa_data.pa_parameter) + .pa_name, + b"filename*\x00" as *const u8 + as *const libc::c_char, + 9, + ) == 0i32 + { + filename_parts += &to_string_lossy( + (*(*dsp_param).pa_data.pa_parameter) + .pa_value, + ); + } else if (*dsp_param).pa_type + == MAILMIME_DISPOSITION_PARM_FILENAME + as libc::c_int + { + desired_filename = dc_decode_header_words( + (*dsp_param).pa_data.pa_filename, + ) + } + } + } + } + break; + } + } + if !filename_parts.is_empty() { + free(desired_filename as *mut libc::c_void); + desired_filename = + dc_decode_ext_header(filename_parts.as_bytes()).strdup(); + } + if desired_filename.is_null() { + let param = mailmime_find_ct_parameter( + mime, + b"name\x00" as *const u8 as *const libc::c_char, + ); + if !param.is_null() + && !(*param).pa_value.is_null() + && 0 != *(*param).pa_value.offset(0isize) as libc::c_int + { + desired_filename = dc_strdup((*param).pa_value) + } + } + /* if there is still no filename, guess one */ + if desired_filename.is_null() { + if !(*mime).mm_content_type.is_null() + && !(*(*mime).mm_content_type).ct_subtype.is_null() + { + desired_filename = dc_mprintf( + b"file.%s\x00" as *const u8 as *const libc::c_char, + (*(*mime).mm_content_type).ct_subtype, + ); + } else { + ok_to_continue = false; + } + } + if ok_to_continue { + if strncmp( + desired_filename, + b"location\x00" as *const u8 as *const libc::c_char, + 8, + ) == 0i32 + && strncmp( + desired_filename + .offset(strlen(desired_filename) as isize) + .offset(-4isize), + b".kml\x00" as *const u8 as *const libc::c_char, + 4, + ) == 0i32 + { + if !decoded_data.is_null() && decoded_data_bytes > 0 { + let d = dc_null_terminate( + decoded_data, + decoded_data_bytes as i32, + ); + self.location_kml = + location::Kml::parse(self.context, as_str(d)).ok(); + free(d.cast()); + } + } else if strncmp( + desired_filename, + b"message\x00" as *const u8 as *const libc::c_char, + 7, + ) == 0i32 + && strncmp( + desired_filename + .offset(strlen(desired_filename) as isize) + .offset(-4isize), + b".kml\x00" as *const u8 as *const libc::c_char, + 4, + ) == 0i32 + { + if !decoded_data.is_null() && decoded_data_bytes > 0 { + let d = dc_null_terminate( + decoded_data, + decoded_data_bytes as i32, + ); + self.message_kml = + location::Kml::parse(self.context, as_str(d)).ok(); + free(d.cast()); + } + } else { + dc_replace_bad_utf8_chars(desired_filename); + self.do_add_single_file_part( + msg_type, + mime_type, + as_str(raw_mime), + decoded_data, + decoded_data_bytes, + desired_filename, + ); + } + } + } + _ => {} + } + } + } + } + /* 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(file_suffix as *mut libc::c_void); + free(desired_filename as *mut libc::c_void); + free(raw_mime as *mut libc::c_void); + (self.parts.len() > old_part_count) as libc::c_int + } + + unsafe fn do_add_single_file_part( + &mut self, + msg_type: Viewtype, + mime_type: libc::c_int, + raw_mime: &str, + decoded_data: *const libc::c_char, + decoded_data_bytes: libc::size_t, + desired_filename: *const libc::c_char, + ) { + /* create a free file name to use */ + let path_n_filename = dc_get_fine_pathNfilename( + self.context, + b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, + 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 { + 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) { + part.param.set_int(Param::Width, width as i32); + part.param.set_int(Param::Height, height as i32); + } + } + 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) { + if self.e2ee_helper.encrypted && self.e2ee_helper.signatures.len() > 0 { + part.param.set_int(Param::GuranteeE2ee, 1); + } else if self.e2ee_helper.encrypted { + part.param.set_int(Param::ErroneousE2ee, 0x2); + } + self.parts.push(part); + } + + pub unsafe fn is_mailinglist_message(&self) -> bool { + if self.lookup_field("List-Id").is_some() { + return true; + } + + if let Some(precedence) = self.lookup_optional_field("Precedence") { + if strcasecmp( + (*precedence).fld_value, + b"list\x00" as *const u8 as *const libc::c_char, + ) == 0i32 + || strcasecmp( + (*precedence).fld_value, + b"bulk\x00" as *const u8 as *const libc::c_char, + ) == 0i32 + { + return true; + } + } + + false + } + + pub unsafe fn sender_equals_recipient(&self) -> bool { + if self.header_root.is_null() { + return false; + } + + let mut sender_equals_recipient = false; + let mut fld_from: *const mailimf_from = ptr::null(); + + /* get From: and check there is exactly one sender */ + let fld = mailimf_find_field(self.header_root, MAILIMF_FIELD_FROM as libc::c_int); + if !(fld.is_null() + || { + fld_from = (*fld).fld_data.fld_from; + fld_from.is_null() + } + || (*fld_from).frm_mb_list.is_null() + || (*(*fld_from).frm_mb_list).mb_list.is_null() + || (*(*(*fld_from).frm_mb_list).mb_list).count != 1i32) + { + let mb = (if !(*(*(*fld_from).frm_mb_list).mb_list).first.is_null() { + (*(*(*(*fld_from).frm_mb_list).mb_list).first).data + } else { + ptr::null_mut() + }) as *mut mailimf_mailbox; + + if !mb.is_null() { + let from_addr_norm = addr_normalize(as_str((*mb).mb_addr_spec)); + let recipients = mailimf_get_recipients(self.header_root); + if recipients.len() == 1 { + if recipients.contains(from_addr_norm) { + sender_equals_recipient = true; + } + } + } + } + + sender_equals_recipient + } + + pub fn repl_msg_by_error(&mut self, error_msg: impl AsRef) { + if self.parts.is_empty() { + return; + } + + let part = &mut self.parts[0]; + part.typ = Viewtype::Text; + part.msg = Some(format!("[{}]", error_msg.as_ref())); + self.parts.truncate(1); + + assert_eq!(self.parts.len(), 1); + } +} + +impl<'a> Drop for MimeParser<'a> { + fn drop(&mut self) { + if !self.header_protected.is_null() { + unsafe { mailimf_fields_free(self.header_protected) }; + } + if !self.mimeroot.is_null() { + unsafe { mailmime_free(self.mimeroot) }; + } + unsafe { self.e2ee_helper.thanks() }; + } +} + +const DC_MIMETYPE_AC_SETUP_FILE: i32 = 111; + +#[derive(Default, Debug, Clone)] +pub struct Part { + pub typ: Viewtype, + pub is_meta: bool, + pub mimetype: i32, + pub msg: Option, + pub msg_raw: Option, + pub bytes: i32, + pub param: Params, +} + +pub fn mailimf_find_first_addr(mb_list: *const mailimf_mailbox_list) -> Option { + if mb_list.is_null() { + return None; + } + + for cur in unsafe { (*(*mb_list).mb_list).into_iter() } { + let mb = cur as *mut mailimf_mailbox; + if !mb.is_null() && !unsafe { (*mb).mb_addr_spec.is_null() } { + let addr = unsafe { as_str((*mb).mb_addr_spec) }; + return Some(addr_normalize(addr).to_string()); + } + } + + None +} + +unsafe fn hash_header(out: &mut HashMap, in_0: *const mailimf_fields) { + if in_0.is_null() { + return; + } + + for cur in (*(*in_0).fld_list).into_iter() { + let field = cur as *mut mailimf_field; + // TODO match on enums /rtn + + let key = match (*field).fld_type { + 1 => Some("Return-Path".to_string()), + 9 => Some("Date".to_string()), + 10 => Some("From".to_string()), + 11 => Some("Sender".to_string()), + 12 => Some("Reply-To".to_string()), + 13 => Some("To".to_string()), + 14 => Some("Cc".to_string()), + 15 => Some("Bcc".to_string()), + 16 => Some("Message-ID".to_string()), + 17 => Some("In-Reply-To".to_string()), + 18 => Some("References".to_string()), + 19 => Some("Subject".to_string()), + 22 => { + // MAILIMF_FIELD_OPTIONAL_FIELD + let optional_field = (*field).fld_data.fld_optional_field; + if !optional_field.is_null() { + Some(to_string_lossy((*optional_field).fld_name)) + } else { + None + } + } + _ => None, + }; + if let Some(key) = key { // XXX the optional field sometimes contains invalid UTF8 // which should not happen (according to the mime standard). // This might point to a bug in our mime parsing/processing // logic. As mmime/dc_mimeparser is scheduled fore replacement // anyway we just use a lossy conversion. - let key_r = &to_string_lossy(key); - if !out.contains_key(key_r) || // key already exists, only overwrite known types (protected headers) - (*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as i32 || key_r.starts_with("Chat-") + + if !out.contains_key(&key) || // key already exists, only overwrite known types (protected headers) + (*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as i32 || key.starts_with("Chat-") { - out.insert(key_r.to_string(), field); + out.insert(key, field); } } - cur1 = if !cur1.is_null() { - (*cur1).next - } else { - ptr::null_mut() - } } } @@ -774,20 +1087,22 @@ unsafe fn mailmime_get_mime_type( mut msg_type: *mut Viewtype, raw_mime: *mut *mut libc::c_char, ) -> libc::c_int { - let c: *mut mailmime_content = (*mime).mm_content_type; + let c = (*mime).mm_content_type; let mut dummy = Viewtype::Unknown; + if msg_type.is_null() { msg_type = &mut dummy } *msg_type = Viewtype::Unknown; if c.is_null() || (*c).ct_type.is_null() { - return 0i32; + return 0; } + // TODO match on enums /rtn match (*(*c).ct_type).tp_type { 1 => match (*(*(*c).ct_type).tp_data.tp_discrete_type).dt_type { 1 => { - if !(0 != mailmime_is_attachment_disposition(mime)) { + if !mailmime_is_attachment_disposition(mime) { if strcmp( (*c).ct_subtype, b"plain\x00" as *const u8 as *const libc::c_char, @@ -933,42 +1248,34 @@ unsafe fn mailmime_get_mime_type( 0 } -fn reconcat_mime(type_0: Option<&str>, subtype: Option<&str>) -> String { - let type_0 = type_0.unwrap_or("application"); +fn reconcat_mime(typ: Option<&str>, subtype: Option<&str>) -> String { + let typ = typ.unwrap_or("application"); let subtype = subtype.unwrap_or("octet-stream"); - format!("{}/{}", type_0, subtype) + format!("{}/{}", typ, subtype) } -unsafe fn mailmime_is_attachment_disposition(mime: *mut mailmime) -> libc::c_int { - if !(*mime).mm_mime_fields.is_null() { - let mut cur: *mut clistiter = (*(*(*mime).mm_mime_fields).fld_list).first; - while !cur.is_null() { - let field: *mut mailmime_field = (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) as *mut mailmime_field; - if !field.is_null() - && (*field).fld_type == MAILMIME_FIELD_DISPOSITION as libc::c_int - && !(*field).fld_data.fld_disposition.is_null() +unsafe fn mailmime_is_attachment_disposition(mime: *mut mailmime) -> bool { + if (*mime).mm_mime_fields.is_null() { + return false; + } + + for cur in (*(*(*mime).mm_mime_fields).fld_list).into_iter() { + let field = cur as *mut mailmime_field; + if !field.is_null() + && (*field).fld_type == MAILMIME_FIELD_DISPOSITION as libc::c_int + && !(*field).fld_data.fld_disposition.is_null() + { + if !(*(*field).fld_data.fld_disposition).dsp_type.is_null() + && (*(*(*field).fld_data.fld_disposition).dsp_type).dsp_type + == MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int { - if !(*(*field).fld_data.fld_disposition).dsp_type.is_null() - && (*(*(*field).fld_data.fld_disposition).dsp_type).dsp_type - == MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int - { - return 1i32; - } - } - cur = if !cur.is_null() { - (*cur).next - } else { - ptr::null_mut() + return true; } } } - 0 + false } /* low-level-tools for working with mailmime structures directly */ @@ -983,384 +1290,32 @@ pub unsafe fn mailmime_find_ct_parameter( { return ptr::null_mut(); } - let mut cur: *mut clistiter; - cur = (*(*(*mime).mm_content_type).ct_parameters).first; - while !cur.is_null() { - let param: *mut mailmime_parameter = (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) as *mut mailmime_parameter; + + for cur in (*(*(*mime).mm_content_type).ct_parameters).into_iter() { + let param = cur as *mut mailmime_parameter; if !param.is_null() && !(*param).pa_name.is_null() { if strcmp((*param).pa_name, name) == 0i32 { return param; } } - cur = if !cur.is_null() { - (*cur).next - } else { - ptr::null_mut() - } } ptr::null_mut() } -unsafe fn dc_mimeparser_add_single_part_if_known( - mimeparser: &mut dc_mimeparser_t, - mime: *mut mailmime, -) -> libc::c_int { - let mut ok_to_continue = true; - let old_part_count = mimeparser.parts.len(); - let mime_type: libc::c_int; - let mime_data: *mut mailmime_data; - let file_suffix: *mut libc::c_char = ptr::null_mut(); - let mut desired_filename: *mut libc::c_char = ptr::null_mut(); - let mut msg_type = Viewtype::Unknown; - let mut raw_mime: *mut libc::c_char = ptr::null_mut(); - /* mmap_string_unref()'d if set */ - let mut transfer_decoding_buffer: *mut libc::c_char = ptr::null_mut(); - /* must not be free()'d */ - let mut decoded_data: *const libc::c_char = ptr::null(); - let mut decoded_data_bytes = 0; - let mut simplifier: Option = None; - if !(mime.is_null() || (*mime).mm_data.mm_single.is_null()) { - mime_type = mailmime_get_mime_type(mime, &mut msg_type, &mut raw_mime); - mime_data = (*mime).mm_data.mm_single; - /* MAILMIME_DATA_FILE indicates, the data is in a file; AFAIK this is not used on parsing */ - if !((*mime_data).dt_type != MAILMIME_DATA_TEXT as libc::c_int - || (*mime_data).dt_data.dt_text.dt_data.is_null() - || (*mime_data).dt_data.dt_text.dt_length <= 0) - { - /* regard `Content-Transfer-Encoding:` */ - if mailmime_transfer_decode( - mime, - &mut decoded_data, - &mut decoded_data_bytes, - &mut transfer_decoding_buffer, - ) { - /* no always error - but no data */ - match mime_type { - 60 | 70 => { - if simplifier.is_none() { - simplifier = Some(Simplify::new()); - } - /* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */ - let charset = mailmime_content_charset_get((*mime).mm_content_type); - if !charset.is_null() - && strcmp(charset, b"utf-8\x00" as *const u8 as *const libc::c_char) - != 0i32 - && strcmp(charset, b"UTF-8\x00" as *const u8 as *const libc::c_char) - != 0i32 - { - if let Some(encoding) = Charset::for_label( - CStr::from_ptr(charset).to_str().unwrap().as_bytes(), - ) { - let data = std::slice::from_raw_parts( - decoded_data as *const u8, - decoded_data_bytes, - ); - - let (res, _, _) = encoding.decode(data); - info!(mimeparser.context, "decoded message: '{}'", res); - if res.is_empty() { - /* no error - but nothing to add */ - ok_to_continue = false; - } else { - let b = res.as_bytes(); - decoded_data = b.as_ptr() as *const libc::c_char; - decoded_data_bytes = b.len(); - std::mem::forget(res); - } - } else { - warn!( - mimeparser.context, - "Cannot convert {} bytes from \"{}\" to \"utf-8\".", - decoded_data_bytes as libc::c_int, - as_str(charset), - ); - } - } - if ok_to_continue { - /* check header directly as is_send_by_messenger is not yet set up */ - let is_msgrmsg = - !dc_mimeparser_lookup_optional_field(&mimeparser, "Chat-Version") - .is_null(); - - let simplified_txt = - if decoded_data_bytes <= 0 || decoded_data.is_null() { - "".into() - } else { - let input_c = strndup(decoded_data, decoded_data_bytes as _); - let input = to_string_lossy(input_c); - let is_html = mime_type == 70; - free(input_c as *mut _); - - simplifier.unwrap().simplify(&input, is_html, is_msgrmsg) - }; - if !simplified_txt.is_empty() { - let mut part = dc_mimepart_new(); - part.type_0 = Viewtype::Text; - part.int_mimetype = mime_type; - part.msg = Some(simplified_txt); - part.msg_raw = { - let raw_c = - strndup(decoded_data, decoded_data_bytes as libc::c_ulong); - let raw = to_string_lossy(raw_c); - free(raw_c.cast()); - Some(raw) - }; - do_add_single_part(mimeparser, part); - } - - if simplifier.unwrap().is_forwarded { - mimeparser.is_forwarded = true; - } - } - } - 80 | 90 | 100 | 110 | 111 => { - /* try to get file name from - `Content-Disposition: ... filename*=...` - or `Content-Disposition: ... filename*0*=... filename*1*=... filename*2*=...` - or `Content-Disposition: ... filename=...` */ - let mut filename_parts = String::new(); - let mut cur1: *mut clistiter = (*(*(*mime).mm_mime_fields).fld_list).first; - while !cur1.is_null() { - let field: *mut mailmime_field = (if !cur1.is_null() { - (*cur1).data - } else { - ptr::null_mut() - }) - as *mut mailmime_field; - if !field.is_null() - && (*field).fld_type == MAILMIME_FIELD_DISPOSITION as libc::c_int - && !(*field).fld_data.fld_disposition.is_null() - { - let file_disposition: *mut mailmime_disposition = - (*field).fld_data.fld_disposition; - if !file_disposition.is_null() { - let mut cur2: *mut clistiter = - (*(*file_disposition).dsp_parms).first; - while !cur2.is_null() { - let dsp_param: *mut mailmime_disposition_parm = - (if !cur2.is_null() { - (*cur2).data - } else { - ptr::null_mut() - }) - as *mut mailmime_disposition_parm; - if !dsp_param.is_null() { - if (*dsp_param).pa_type - == MAILMIME_DISPOSITION_PARM_PARAMETER - as libc::c_int - && !(*dsp_param).pa_data.pa_parameter.is_null() - && !(*(*dsp_param).pa_data.pa_parameter) - .pa_name - .is_null() - && strncmp( - (*(*dsp_param).pa_data.pa_parameter).pa_name, - b"filename*\x00" as *const u8 - as *const libc::c_char, - 9, - ) == 0i32 - { - filename_parts += &to_string_lossy( - (*(*dsp_param).pa_data.pa_parameter).pa_value, - ); - } else if (*dsp_param).pa_type - == MAILMIME_DISPOSITION_PARM_FILENAME as libc::c_int - { - desired_filename = dc_decode_header_words( - (*dsp_param).pa_data.pa_filename, - ) - } - } - cur2 = if !cur2.is_null() { - (*cur2).next - } else { - ptr::null_mut() - } - } - } - break; - } else { - cur1 = if !cur1.is_null() { - (*cur1).next - } else { - ptr::null_mut() - } - } - } - if !filename_parts.is_empty() { - free(desired_filename as *mut libc::c_void); - desired_filename = - dc_decode_ext_header(filename_parts.as_bytes()).strdup(); - } - if desired_filename.is_null() { - let param = mailmime_find_ct_parameter( - mime, - b"name\x00" as *const u8 as *const libc::c_char, - ); - if !param.is_null() - && !(*param).pa_value.is_null() - && 0 != *(*param).pa_value.offset(0isize) as libc::c_int - { - desired_filename = dc_strdup((*param).pa_value) - } - } - /* if there is still no filename, guess one */ - if desired_filename.is_null() { - if !(*mime).mm_content_type.is_null() - && !(*(*mime).mm_content_type).ct_subtype.is_null() - { - desired_filename = dc_mprintf( - b"file.%s\x00" as *const u8 as *const libc::c_char, - (*(*mime).mm_content_type).ct_subtype, - ); - } else { - ok_to_continue = false; - } - } - if ok_to_continue { - if strncmp( - desired_filename, - b"location\x00" as *const u8 as *const libc::c_char, - 8, - ) == 0i32 - && strncmp( - desired_filename - .offset(strlen(desired_filename) as isize) - .offset(-4isize), - b".kml\x00" as *const u8 as *const libc::c_char, - 4, - ) == 0i32 - { - if !decoded_data.is_null() && decoded_data_bytes > 0 { - let d = - dc_null_terminate(decoded_data, decoded_data_bytes as i32); - mimeparser.location_kml = - location::Kml::parse(mimeparser.context, as_str(d)).ok(); - free(d.cast()); - } - } else if strncmp( - desired_filename, - b"message\x00" as *const u8 as *const libc::c_char, - 7, - ) == 0i32 - && strncmp( - desired_filename - .offset(strlen(desired_filename) as isize) - .offset(-4isize), - b".kml\x00" as *const u8 as *const libc::c_char, - 4, - ) == 0i32 - { - if !decoded_data.is_null() && decoded_data_bytes > 0 { - let d = - dc_null_terminate(decoded_data, decoded_data_bytes as i32); - mimeparser.message_kml = - location::Kml::parse(mimeparser.context, as_str(d)).ok(); - free(d.cast()); - } - } else { - dc_replace_bad_utf8_chars(desired_filename); - do_add_single_file_part( - mimeparser, - msg_type, - mime_type, - as_str(raw_mime), - decoded_data, - decoded_data_bytes, - desired_filename, - ); - } - } - } - _ => {} - } - } - } - } - /* 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(file_suffix as *mut libc::c_void); - free(desired_filename as *mut libc::c_void); - free(raw_mime as *mut libc::c_void); - (mimeparser.parts.len() > old_part_count) as libc::c_int -} - -#[allow(non_snake_case)] -unsafe fn do_add_single_file_part( - parser: &mut dc_mimeparser_t, - msg_type: Viewtype, - mime_type: libc::c_int, - raw_mime: &str, - decoded_data: *const libc::c_char, - decoded_data_bytes: libc::size_t, - desired_filename: *const libc::c_char, -) { - let pathNfilename: *mut libc::c_char; - /* create a free file name to use */ - pathNfilename = dc_get_fine_pathNfilename( - (*parser).context, - b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, - desired_filename, - ); - if !pathNfilename.is_null() { - /* copy data to file */ - if !(dc_write_file( - (*parser).context, - pathNfilename, - decoded_data as *const libc::c_void, - decoded_data_bytes, - ) == 0i32) - { - let mut part = dc_mimepart_new(); - part.type_0 = msg_type; - part.int_mimetype = mime_type; - part.bytes = decoded_data_bytes as libc::c_int; - part.param.set(Param::File, as_str(pathNfilename)); - 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) { - part.param.set_int(Param::Width, width as i32); - part.param.set_int(Param::Height, height as i32); - } - } - do_add_single_part(parser, part); - } - } - free(pathNfilename as *mut libc::c_void); -} - -unsafe fn do_add_single_part(parser: &mut dc_mimeparser_t, mut part: dc_mimepart_t) { - if (*parser).e2ee_helper.encrypted && (*parser).e2ee_helper.signatures.len() > 0 { - part.param.set_int(Param::GuranteeE2ee, 1); - } else if (*parser).e2ee_helper.encrypted { - part.param.set_int(Param::ErroneousE2ee, 0x2); - } - parser.parts.push(part); -} - pub unsafe fn mailmime_transfer_decode( mime: *mut mailmime, 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: libc::c_int = 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 decoded_data: *const libc::c_char; - let mut decoded_data_bytes: libc::size_t = 0; + 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() @@ -1375,29 +1330,19 @@ pub unsafe fn mailmime_transfer_decode( } mime_data = (*mime).mm_data.mm_single; if !(*mime).mm_mime_fields.is_null() { - let mut cur: *mut clistiter; - cur = (*(*(*mime).mm_mime_fields).fld_list).first; - while !cur.is_null() { - let field: *mut mailmime_field = (if !cur.is_null() { - (*cur).data - } else { - ptr::null_mut() - }) as *mut mailmime_field; + for cur in (*(*(*mime).mm_mime_fields).fld_list).into_iter() { + let field = cur as *mut mailmime_field; + if !field.is_null() && (*field).fld_type == MAILMIME_FIELD_TRANSFER_ENCODING as libc::c_int && !(*field).fld_data.fld_encoding.is_null() { mime_transfer_encoding = (*(*field).fld_data.fld_encoding).enc_type; break; - } else { - cur = if !cur.is_null() { - (*cur).next - } else { - ptr::null_mut() - } } } } + if mime_transfer_encoding == MAILMIME_MECHANISM_7BIT as libc::c_int || mime_transfer_encoding == MAILMIME_MECHANISM_8BIT as libc::c_int || mime_transfer_encoding == MAILMIME_MECHANISM_BINARY as libc::c_int @@ -1408,9 +1353,8 @@ pub unsafe fn mailmime_transfer_decode( return false; } } else { - let r: libc::c_int; let mut current_index = 0; - r = mailmime_part_parse( + let r = mailmime_part_parse( (*mime_data).dt_data.dt_text.dt_data, (*mime_data).dt_data.dt_text.dt_length, &mut current_index, @@ -1424,8 +1368,9 @@ pub unsafe fn mailmime_transfer_decode( { return false; } - decoded_data = transfer_decoding_buffer + decoded_data = transfer_decoding_buffer; } + *ret_decoded_data = decoded_data; *ret_decoded_data_bytes = decoded_data_bytes; *ret_to_mmap_string_unref = transfer_decoding_buffer; @@ -1433,80 +1378,16 @@ pub unsafe fn mailmime_transfer_decode( true } -pub unsafe fn dc_mimeparser_is_mailinglist_message(mimeparser: &dc_mimeparser_t) -> bool { - if !dc_mimeparser_lookup_field(&mimeparser, "List-Id").is_null() { - return true; - } - let precedence: *mut mailimf_optional_field = - dc_mimeparser_lookup_optional_field(mimeparser, "Precedence"); - if !precedence.is_null() { - if strcasecmp( - (*precedence).fld_value, - b"list\x00" as *const u8 as *const libc::c_char, - ) == 0i32 - || strcasecmp( - (*precedence).fld_value, - b"bulk\x00" as *const u8 as *const libc::c_char, - ) == 0i32 - { - return true; - } - } - - false -} - -pub unsafe fn dc_mimeparser_sender_equals_recipient(mimeparser: &dc_mimeparser_t) -> libc::c_int { - let mut sender_equals_recipient: libc::c_int = 0i32; - let fld: *const mailimf_field; - let mut fld_from: *const mailimf_from = ptr::null(); - let mb: *mut mailimf_mailbox; - - if !mimeparser.header_root.is_null() { - /* get From: and check there is exactly one sender */ - fld = mailimf_find_field(mimeparser.header_root, MAILIMF_FIELD_FROM as libc::c_int); - if !(fld.is_null() - || { - fld_from = (*fld).fld_data.fld_from; - fld_from.is_null() - } - || (*fld_from).frm_mb_list.is_null() - || (*(*fld_from).frm_mb_list).mb_list.is_null() - || (*(*(*fld_from).frm_mb_list).mb_list).count != 1i32) - { - mb = (if !(*(*(*fld_from).frm_mb_list).mb_list).first.is_null() { - (*(*(*(*fld_from).frm_mb_list).mb_list).first).data - } else { - ptr::null_mut() - }) as *mut mailimf_mailbox; - if !mb.is_null() { - let from_addr_norm = addr_normalize(as_str((*mb).mb_addr_spec)); - let recipients = mailimf_get_recipients(mimeparser.header_root); - if recipients.len() == 1 { - if recipients.contains(from_addr_norm) { - sender_equals_recipient = 1i32; - } - } - } - } - } - - sender_equals_recipient -} - pub unsafe fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet { /* returned addresses are normalized. */ let mut recipients: HashSet = Default::default(); - let mut cur1: *mut clistiter; - cur1 = (*(*imffields).fld_list).first; - while !cur1.is_null() { - let fld: *mut mailimf_field = (if !cur1.is_null() { - (*cur1).data - } else { - ptr::null_mut() - }) as *mut mailimf_field; + + for cur in (*(*imffields).fld_list).into_iter() { + let fld = cur as *mut mailimf_field; + let fld_to: *mut mailimf_to; let fld_cc: *mut mailimf_cc; + let mut addr_list: *mut mailimf_address_list = ptr::null_mut(); // TODO match on enums /rtn match (*fld).fld_type { @@ -1524,78 +1405,38 @@ pub unsafe fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet< } _ => {} } + if !addr_list.is_null() { - let mut cur2: *mut clistiter; - cur2 = (*(*addr_list).ad_list).first; - while !cur2.is_null() { - let adr: *mut mailimf_address = (if !cur2.is_null() { - (*cur2).data - } else { - ptr::null_mut() - }) as *mut mailimf_address; + for cur2 in (*(*addr_list).ad_list).into_iter() { + let adr = cur2 as *mut mailimf_address; + if !adr.is_null() { if (*adr).ad_type == MAILIMF_ADDRESS_MAILBOX as libc::c_int { - mailimf_get_recipients__add_addr( - &mut recipients, - (*adr).ad_data.ad_mailbox, - ); + mailimf_get_recipients_add_addr(&mut recipients, (*adr).ad_data.ad_mailbox); } else if (*adr).ad_type == MAILIMF_ADDRESS_GROUP as libc::c_int { let group: *mut mailimf_group = (*adr).ad_data.ad_group; if !group.is_null() && !(*group).grp_mb_list.is_null() { - let mut cur3: *mut clistiter; - cur3 = (*(*(*group).grp_mb_list).mb_list).first; - while !cur3.is_null() { - mailimf_get_recipients__add_addr( + for cur3 in (*(*(*group).grp_mb_list).mb_list).into_iter() { + mailimf_get_recipients_add_addr( &mut recipients, - (if !cur3.is_null() { - (*cur3).data - } else { - ptr::null_mut() - }) as *mut mailimf_mailbox, + cur3 as *mut mailimf_mailbox, ); - cur3 = if !cur3.is_null() { - (*cur3).next - } else { - ptr::null_mut() - } } } } } - cur2 = if !cur2.is_null() { - (*cur2).next - } else { - ptr::null_mut() - } } } - cur1 = if !cur1.is_null() { - (*cur1).next - } else { - ptr::null_mut() - } } recipients } -/* ****************************************************************************** - * debug output - ******************************************************************************/ -/* DEBUG_MIME_OUTPUT */ -/* ****************************************************************************** - * low-level-tools for getting a list of all recipients - ******************************************************************************/ - -#[allow(non_snake_case)] -unsafe fn mailimf_get_recipients__add_addr( - recipients: &mut HashSet, - mb: *mut mailimf_mailbox, -) { +fn mailimf_get_recipients_add_addr(recipients: &mut HashSet, mb: *mut mailimf_mailbox) { if !mb.is_null() { - let addr_norm = addr_normalize(as_str((*mb).mb_addr_spec)); + let addr_norm = addr_normalize(as_str(unsafe { (*mb).mb_addr_spec })); recipients.insert(addr_norm.into()); - }; + } } /*the result is a pointer to mime, must not be freed*/ @@ -1628,20 +1469,6 @@ pub unsafe fn mailimf_find_field( ptr::null_mut() } -pub unsafe fn dc_mimeparser_repl_msg_by_error( - mimeparser: &mut dc_mimeparser_t, - error_msg: *const libc::c_char, -) { - if mimeparser.parts.is_empty() { - return; - } - let part = &mut mimeparser.parts[0]; - part.type_0 = Viewtype::Text; - part.msg = Some(format!("[{}]", to_string_lossy(error_msg))); - mimeparser.parts.truncate(1); - assert_eq!(mimeparser.parts.len(), 1); -} - /*the result is a pointer to mime, must not be freed*/ pub unsafe fn mailmime_find_mailimf_fields(mime: *mut mailmime) -> *mut mailimf_fields { if mime.is_null() { @@ -1789,29 +1616,27 @@ mod tests { } } #[test] - fn test_dc_mimeparser_with_context() { + fn test_mimeparser_with_context() { unsafe { let context = dummy_context(); let raw = b"Content-Type: multipart/mixed; boundary=\"==break==\";\nSubject: outer-subject\nX-Special-A: special-a\nFoo: Bar\nChat-Version: 0.0\n\n--==break==\nContent-Type: text/plain; protected-headers=\"v1\";\nSubject: inner-subject\nX-Special-B: special-b\nFoo: Xy\nChat-Version: 1.0\n\ntest1\n\n--==break==--\n\n\x00"; - let mut mimeparser = dc_mimeparser_parse(&context.ctx, &raw[..]); + let mut mimeparser = MimeParser::new(&context.ctx); + mimeparser.parse(&raw[..]); assert_eq!(mimeparser.subject, Some("inner-subject".into())); - let mut of: *mut mailimf_optional_field = - dc_mimeparser_lookup_optional_field(&mimeparser, "X-Special-A"); + let of = mimeparser.lookup_optional_field("X-Special-A").unwrap(); assert_eq!( &to_string((*of).fld_value as *const libc::c_char), "special-a", ); - of = dc_mimeparser_lookup_optional_field(&mimeparser, "Foo"); + let of = mimeparser.lookup_optional_field("Foo").unwrap(); assert_eq!(&to_string((*of).fld_value as *const libc::c_char), "Bar",); - of = dc_mimeparser_lookup_optional_field(&mimeparser, "Chat-Version"); + let of = mimeparser.lookup_optional_field("Chat-Version").unwrap(); assert_eq!(&to_string((*of).fld_value as *const libc::c_char), "1.0",); assert_eq!(mimeparser.parts.len(), 1); - - dc_mimeparser_unref(&mut mimeparser); } } } diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index f24fa7d00..1920e0cec 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -63,7 +63,8 @@ pub unsafe fn dc_receive_imf( // somewhen, I did not found out anything that speaks against this approach yet) let body = std::slice::from_raw_parts(imf_raw_not_terminated as *const u8, imf_raw_bytes); - let mut mime_parser = dc_mimeparser_parse(context, body); + let mut mime_parser = MimeParser::new(context); + mime_parser.parse(body); if mime_parser.header.is_empty() { // Error - even adding an empty record won't help as we do not know the message ID @@ -149,7 +150,7 @@ pub unsafe fn dc_receive_imf( ); if 0 != check_self { incoming = 0; - if 0 != dc_mimeparser_sender_equals_recipient(&mime_parser) { + if mime_parser.sender_equals_recipient() { from_id = DC_CONTACT_ID_SELF; } } else if from_list.len() >= 1 { @@ -183,7 +184,7 @@ pub unsafe fn dc_receive_imf( } // Add parts - if dc_mimeparser_get_last_nonmeta(&mut mime_parser).is_some() { + if mime_parser.get_last_nonmeta().is_some() { if let Err(err) = add_parts( context, &mut mime_parser, @@ -278,7 +279,7 @@ pub unsafe fn dc_receive_imf( unsafe fn add_parts( context: &Context, - mut mime_parser: &mut dc_mimeparser_t, + mut mime_parser: &mut MimeParser, imf_raw_not_terminated: *const libc::c_char, imf_raw_bytes: libc::size_t, incoming: i32, @@ -414,7 +415,7 @@ unsafe fn add_parts( *to_id = 1; // handshake messages must be processed _before_ chats are created // (eg. contacs may be marked as verified) - if !dc_mimeparser_lookup_field(mime_parser, "Secure-Join").is_null() { + if mime_parser.lookup_field("Secure-Join").is_some() { // avoid discarding by show_emails setting msgrmsg = 1; *chat_id = 0; @@ -463,7 +464,7 @@ unsafe fn add_parts( if *chat_id == 0 { // check if the message belongs to a mailing list - if dc_mimeparser_is_mailinglist_message(mime_parser) { + if mime_parser.is_mailinglist_message() { *chat_id = 3; info!(context, "Message belongs to a mailing list and is ignored.",); } @@ -656,7 +657,7 @@ unsafe fn add_parts( } } } - if part.type_0 == Viewtype::Text { + if part.typ == Viewtype::Text { let msg_raw = CString::yolo(part.msg_raw.as_ref().cloned().unwrap_or_default()); let subject_c = CString::yolo( @@ -687,7 +688,7 @@ unsafe fn add_parts( sort_timestamp, *sent_timestamp, rcvd_timestamp, - part.type_0, + part.typ, state, msgrmsg, part.msg.as_ref().map_or("", String::as_str), @@ -762,14 +763,13 @@ unsafe fn add_parts( } /// Lookup a mime field given its name and type. -unsafe fn lookup_field( - parser: &dc_mimeparser_t, - name: &str, - typ: u32, -) -> Option<*const mailimf_field> { - let field = dc_mimeparser_lookup_field(parser, name); - if !field.is_null() && (*field).fld_type == typ as libc::c_int { - Some(field) +fn lookup_field(parser: &MimeParser, name: &str, typ: u32) -> Option<*const mailimf_field> { + if let Some(field) = parser.lookup_field(name) { + if unsafe { (*field).fld_type } == typ as libc::c_int { + Some(field) + } else { + None + } } else { None } @@ -778,7 +778,7 @@ unsafe fn lookup_field( // Handle reports (mainly MDNs) unsafe fn handle_reports( context: &Context, - mime_parser: &dc_mimeparser_t, + mime_parser: &MimeParser, from_id: u32, sent_timestamp: i64, rr_event_to_send: &mut Vec<(u32, u32)>, @@ -941,7 +941,7 @@ unsafe fn handle_reports( fn save_locations( context: &Context, - mime_parser: &dc_mimeparser_t, + mime_parser: &MimeParser, chat_id: u32, from_id: u32, insert_msg_id: u32, @@ -1039,7 +1039,7 @@ unsafe fn calc_timestamps( #[allow(non_snake_case)] unsafe fn create_or_lookup_group( context: &Context, - mime_parser: &mut dc_mimeparser_t, + mime_parser: &mut MimeParser, allow_creation: libc::c_int, create_blocked: Blocked, from_id: u32, @@ -1062,16 +1062,13 @@ unsafe fn create_or_lookup_group( let mut X_MrGrpNameChanged = 0; let mut X_MrGrpImageChanged = "".to_string(); let mut better_msg: String = From::from(""); - let mut failure_reason = std::ptr::null_mut(); let cleanup = |grpname: *mut libc::c_char, - failure_reason: *mut libc::c_char, ret_chat_id: *mut u32, ret_chat_id_blocked: &mut Blocked, chat_id: u32, chat_id_blocked: Blocked| { free(grpname.cast()); - free(failure_reason.cast()); if !ret_chat_id.is_null() { *ret_chat_id = chat_id; @@ -1089,10 +1086,10 @@ unsafe fn create_or_lookup_group( } set_better_msg(mime_parser, &better_msg); - let optional_field = dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-ID"); - if !optional_field.is_null() { - grpid = to_string((*optional_field).fld_value) + if let Some(optional_field) = mime_parser.lookup_optional_field("Chat-Group-ID") { + grpid = to_string((*optional_field).fld_value); } + if grpid.is_empty() { if let Some(field) = lookup_field(mime_parser, "Message-ID", MAILIMF_FIELD_MESSAGE_ID) { let fld_message_id = (*field).fld_data.fld_message_id; @@ -1141,7 +1138,6 @@ unsafe fn create_or_lookup_group( ); cleanup( grpname, - failure_reason, ret_chat_id, ret_chat_id_blocked, chat_id, @@ -1153,13 +1149,10 @@ unsafe fn create_or_lookup_group( } } - let optional_field = dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Name"); - if !optional_field.is_null() { - grpname = dc_decode_header_words((*optional_field).fld_value) + if let Some(optional_field) = mime_parser.lookup_optional_field("Chat-Group-Name") { + grpname = dc_decode_header_words((*optional_field).fld_value); } - let optional_field = - dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Member-Removed"); - if !optional_field.is_null() { + if let Some(optional_field) = mime_parser.lookup_optional_field("Chat-Group-Member-Removed") { X_MrRemoveFromGrp = (*optional_field).fld_value; mime_parser.is_system_message = DC_CMD_MEMBER_REMOVED_FROM_GROUP; let left_group = (Contact::lookup_id_by_addr(context, as_str(X_MrRemoveFromGrp)) @@ -1175,14 +1168,10 @@ unsafe fn create_or_lookup_group( from_id as u32, ) } else { - let optional_field = - dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Member-Added"); - if !optional_field.is_null() { + if let Some(optional_field) = mime_parser.lookup_optional_field("Chat-Group-Member-Added") { X_MrAddToGrp = (*optional_field).fld_value; mime_parser.is_system_message = DC_CMD_MEMBER_ADDED_TO_GROUP; - let optional_field = - dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Image"); - if !optional_field.is_null() { + if let Some(optional_field) = mime_parser.lookup_optional_field("Chat-Group-Image") { // fld_value is a pointer somewhere into mime_parser, must not be freed X_MrGrpImageChanged = as_str((*optional_field).fld_value).to_string(); } @@ -1193,9 +1182,9 @@ unsafe fn create_or_lookup_group( from_id as u32, ) } else { - let optional_field = - dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Name-Changed"); - if !optional_field.is_null() { + if let Some(optional_field) = + mime_parser.lookup_optional_field("Chat-Group-Name-Changed") + { X_MrGrpNameChanged = 1; mime_parser.is_system_message = DC_CMD_GROUPNAME_CHANGED; better_msg = context.stock_system_msg( @@ -1205,9 +1194,8 @@ unsafe fn create_or_lookup_group( from_id as u32, ) } else { - let optional_field = - dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Image"); - if !optional_field.is_null() { + if let Some(optional_field) = mime_parser.lookup_optional_field("Chat-Group-Image") + { // fld_value is a pointer somewhere into mime_parser, must not be freed X_MrGrpImageChanged = as_str((*optional_field).fld_value).to_string(); mime_parser.is_system_message = DC_CMD_GROUPIMAGE_CHANGED; @@ -1230,6 +1218,8 @@ unsafe fn create_or_lookup_group( // check, if we have a chat with this group ID let (mut chat_id, chat_id_verified, _blocked) = chat::get_chat_id_by_grpid(context, &grpid); if chat_id != 0 { + let mut failure_reason = std::ptr::null_mut(); + if chat_id_verified && 0 == check_verified_properties( context, @@ -1239,8 +1229,10 @@ unsafe fn create_or_lookup_group( &mut failure_reason, ) { - dc_mimeparser_repl_msg_by_error(mime_parser, failure_reason); + mime_parser.repl_msg_by_error(to_string(failure_reason)); } + + free(failure_reason.cast()); } // check if the sender is a member of the existing group - @@ -1257,7 +1249,7 @@ unsafe fn create_or_lookup_group( .get_config(context, "configured_addr") .unwrap_or_default(); if chat_id == 0 - && !dc_mimeparser_is_mailinglist_message(mime_parser) + && !mime_parser.is_mailinglist_message() && !grpid.is_empty() && !grpname.is_null() // otherwise, a pending "quit" message may pop up @@ -1267,8 +1259,10 @@ unsafe fn create_or_lookup_group( || !X_MrAddToGrp.is_null() && addr_cmp(&self_addr, as_str(X_MrAddToGrp))) { let mut create_verified = VerifiedStatus::Unverified; - if !dc_mimeparser_lookup_field(mime_parser, "Chat-Verified").is_null() { + if mime_parser.lookup_field("Chat-Verified").is_some() { create_verified = VerifiedStatus::Verified; + let mut failure_reason = std::ptr::null_mut(); + if 0 == check_verified_properties( context, mime_parser, @@ -1276,13 +1270,13 @@ unsafe fn create_or_lookup_group( to_ids, &mut failure_reason, ) { - dc_mimeparser_repl_msg_by_error(mime_parser, failure_reason); + mime_parser.repl_msg_by_error(to_string(failure_reason)); } + free(failure_reason.cast()); } if 0 == allow_creation { cleanup( grpname, - failure_reason, ret_chat_id, ret_chat_id_blocked, chat_id, @@ -1314,7 +1308,6 @@ unsafe fn create_or_lookup_group( } cleanup( grpname, - failure_reason, ret_chat_id, ret_chat_id_blocked, chat_id, @@ -1350,7 +1343,7 @@ unsafe fn create_or_lookup_group( changed = true; } else { for part in &mut mime_parser.parts { - if part.type_0 == Viewtype::Image { + if part.typ == Viewtype::Image { grpimage = part .param .get(Param::File) @@ -1444,7 +1437,6 @@ unsafe fn create_or_lookup_group( cleanup( grpname, - failure_reason, ret_chat_id, ret_chat_id_blocked, chat_id, @@ -1455,7 +1447,7 @@ unsafe fn create_or_lookup_group( /// Handle groups for received messages unsafe fn create_or_lookup_adhoc_group( context: &Context, - mime_parser: &dc_mimeparser_t, + mime_parser: &MimeParser, allow_creation: libc::c_int, create_blocked: Blocked, from_id: u32, @@ -1483,7 +1475,7 @@ unsafe fn create_or_lookup_adhoc_group( }; // build member list from the given ids - if to_ids.is_empty() || dc_mimeparser_is_mailinglist_message(mime_parser) { + if to_ids.is_empty() || mime_parser.is_mailinglist_message() { // too few contacts or a mailinglist cleanup( grpname, @@ -1744,7 +1736,7 @@ fn search_chat_ids_by_contact_ids(context: &Context, unsorted_contact_ids: &Vec< unsafe fn check_verified_properties( context: &Context, - mimeparser: &dc_mimeparser_t, + mimeparser: &MimeParser, from_id: u32, to_ids: &Vec, failure_reason: *mut *mut libc::c_char, @@ -1844,46 +1836,53 @@ unsafe fn check_verified_properties( 1 } -unsafe fn set_better_msg>(mime_parser: &mut dc_mimeparser_t, better_msg: T) { +fn set_better_msg(mime_parser: &mut MimeParser, better_msg: impl AsRef) { let msg = better_msg.as_ref(); if msg.len() > 0 && !mime_parser.parts.is_empty() { let part = &mut mime_parser.parts[0]; - if (*part).type_0 == Viewtype::Text { + if part.typ == Viewtype::Text { part.msg = Some(msg.to_string()); } }; } -unsafe fn dc_is_reply_to_known_message( - context: &Context, - mime_parser: &dc_mimeparser_t, -) -> libc::c_int { +unsafe fn dc_is_reply_to_known_message(context: &Context, mime_parser: &MimeParser) -> libc::c_int { /* check if the message is a reply to a known message; the replies are identified by the Message-ID from `In-Reply-To`/`References:` (to support non-Delta-Clients) or from `Chat-Predecessor:` (Delta clients, see comment in dc_chat.c) */ - let optional_field = dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Predecessor"); - if !optional_field.is_null() { + if let Some(optional_field) = mime_parser.lookup_optional_field("Chat-Predecessor") { if 0 != is_known_rfc724_mid(context, (*optional_field).fld_value) { return 1; } } - let field = dc_mimeparser_lookup_field(mime_parser, "In-Reply-To"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_IN_REPLY_TO as libc::c_int { - let fld_in_reply_to: *mut mailimf_in_reply_to = (*field).fld_data.fld_in_reply_to; - if !fld_in_reply_to.is_null() { - if is_known_rfc724_mid_in_list(context, (*(*field).fld_data.fld_in_reply_to).mid_list) { - return 1; + + if let Some(field) = mime_parser.lookup_field("In-Reply-To") { + if (*field).fld_type == MAILIMF_FIELD_IN_REPLY_TO as libc::c_int { + let fld_in_reply_to = (*field).fld_data.fld_in_reply_to; + if !fld_in_reply_to.is_null() { + if is_known_rfc724_mid_in_list( + context, + (*(*field).fld_data.fld_in_reply_to).mid_list, + ) { + return 1; + } } } } - let field = dc_mimeparser_lookup_field(mime_parser, "References"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_REFERENCES as libc::c_int { - let fld_references: *mut mailimf_references = (*field).fld_data.fld_references; - if !fld_references.is_null() { - if is_known_rfc724_mid_in_list(context, (*(*field).fld_data.fld_references).mid_list) { - return 1; + + if let Some(field) = mime_parser.lookup_field("References") { + if (*field).fld_type == MAILIMF_FIELD_REFERENCES as libc::c_int { + let fld_references = (*field).fld_data.fld_references; + if !fld_references.is_null() { + if is_known_rfc724_mid_in_list( + context, + (*(*field).fld_data.fld_references).mid_list, + ) { + return 1; + } } } } + 0 } @@ -1920,37 +1919,42 @@ fn is_known_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) -> li unsafe fn dc_is_reply_to_messenger_message( context: &Context, - mime_parser: &dc_mimeparser_t, + mime_parser: &MimeParser, ) -> libc::c_int { /* function checks, if the message defined by mime_parser references a message send by us from Delta Chat. This is similar to is_reply_to_known_message() but - checks also if any of the referenced IDs are send by a messenger - it is okay, if the referenced messages are moved to trash here - no check for the Chat-* headers (function is only called if it is no messenger message itself) */ - let field = dc_mimeparser_lookup_field(mime_parser, "In-Reply-To"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_IN_REPLY_TO as libc::c_int { - let fld_in_reply_to: *mut mailimf_in_reply_to = (*field).fld_data.fld_in_reply_to; - if !fld_in_reply_to.is_null() { - if 0 != is_msgrmsg_rfc724_mid_in_list( - context, - (*(*field).fld_data.fld_in_reply_to).mid_list, - ) { - return 1; + + if let Some(field) = mime_parser.lookup_field("In-Reply-To") { + if (*field).fld_type == MAILIMF_FIELD_IN_REPLY_TO as libc::c_int { + let fld_in_reply_to = (*field).fld_data.fld_in_reply_to; + if !fld_in_reply_to.is_null() { + if 0 != is_msgrmsg_rfc724_mid_in_list( + context, + (*(*field).fld_data.fld_in_reply_to).mid_list, + ) { + return 1; + } } } } - let field = dc_mimeparser_lookup_field(mime_parser, "References"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_REFERENCES as libc::c_int { - let fld_references: *mut mailimf_references = (*field).fld_data.fld_references; - if !fld_references.is_null() { - if 0 != is_msgrmsg_rfc724_mid_in_list( - context, - (*(*field).fld_data.fld_references).mid_list, - ) { - return 1; + + if let Some(field) = mime_parser.lookup_field("References") { + if (*field).fld_type == MAILIMF_FIELD_REFERENCES as libc::c_int { + let fld_references: *mut mailimf_references = (*field).fld_data.fld_references; + if !fld_references.is_null() { + if 0 != is_msgrmsg_rfc724_mid_in_list( + context, + (*(*field).fld_data.fld_references).mid_list, + ) { + return 1; + } } } } + 0 } diff --git a/src/e2ee.rs b/src/e2ee.rs index dddd24810..8b00c1f1e 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -386,16 +386,17 @@ impl E2eeHelper { /*just a pointer into mailmime structure, must not be freed*/ let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message); let mut message_time = 0; - let mut from: *mut libc::c_char = ptr::null_mut(); + let mut from = None; let mut private_keyring = Keyring::default(); let mut public_keyring_for_validate = Keyring::default(); let mut gossip_headers: *mut mailimf_fields = ptr::null_mut(); if !(in_out_message.is_null() || imffields.is_null()) { - let mut field: *mut mailimf_field = - mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int); + let mut field = mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int); + if !field.is_null() && !(*field).fld_data.fld_from.is_null() { from = mailimf_find_first_addr((*(*field).fld_data.fld_from).frm_mb_list) } + field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int); if !field.is_null() && !(*field).fld_data.fld_orig_date.is_null() { let orig_date: *mut mailimf_orig_date = (*field).fld_data.fld_orig_date; @@ -407,25 +408,28 @@ impl E2eeHelper { } } let mut peerstate = None; - let autocryptheader = - as_opt_str(from).and_then(|from| Aheader::from_imffields(from, imffields)); - if message_time > 0 && !from.is_null() { - peerstate = Peerstate::from_addr(context, &context.sql, as_str(from)); + let autocryptheader = from + .as_ref() + .and_then(|from| Aheader::from_imffields(from, imffields)); + if message_time > 0 { + if let Some(ref from) = from { + peerstate = Peerstate::from_addr(context, &context.sql, from); - if let Some(ref mut peerstate) = peerstate { - if let Some(ref header) = autocryptheader { - peerstate.apply_header(&header, message_time); - peerstate.save_to_db(&context.sql, false); - } else if message_time > peerstate.last_seen_autocrypt - && !contains_report(in_out_message) - { - peerstate.degrade_encryption(message_time); - peerstate.save_to_db(&context.sql, false); + if let Some(ref mut peerstate) = peerstate { + if let Some(ref header) = autocryptheader { + peerstate.apply_header(&header, message_time); + peerstate.save_to_db(&context.sql, false); + } else if message_time > peerstate.last_seen_autocrypt + && !contains_report(in_out_message) + { + peerstate.degrade_encryption(message_time); + peerstate.save_to_db(&context.sql, false); + } + } else if let Some(ref header) = autocryptheader { + let p = Peerstate::from_header(context, header, message_time); + assert!(p.save_to_db(&context.sql, true)); + peerstate = Some(p); } - } else if let Some(ref header) = autocryptheader { - let p = Peerstate::from_header(context, header, message_time); - assert!(p.save_to_db(&context.sql, true)); - peerstate = Some(p); } } /* load private key for decryption */ @@ -437,7 +441,8 @@ impl E2eeHelper { &context.sql, ) { if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 { - peerstate = Peerstate::from_addr(&context, &context.sql, as_str(from)); + peerstate = + Peerstate::from_addr(&context, &context.sql, &from.unwrap_or_default()); } if let Some(ref peerstate) = peerstate { if peerstate.degrade_event.is_some() { @@ -486,8 +491,6 @@ impl E2eeHelper { if !gossip_headers.is_null() { mailimf_fields_free(gossip_headers); } - - free(from as *mut libc::c_void); } } diff --git a/src/securejoin.rs b/src/securejoin.rs index 805788c9d..6a302cd33 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -335,7 +335,7 @@ fn fingerprint_equals_sender( /* library private: secure-join */ pub fn handle_securejoin_handshake( context: &Context, - mimeparser: &dc_mimeparser_t, + mimeparser: &MimeParser, contact_id: u32, ) -> libc::c_int { let own_fingerprint: String; @@ -651,21 +651,21 @@ fn secure_connection_established(context: &Context, contact_chat_id: u32) { emit_event!(context, Event::ChatModified(contact_chat_id)); } -fn lookup_field(mimeparser: &dc_mimeparser_t, key: &str) -> Option { - let field: *mut mailimf_field = dc_mimeparser_lookup_field(mimeparser, key); - unsafe { +fn lookup_field(mime_parser: &MimeParser, key: &str) -> Option { + if let Some(field) = mime_parser.lookup_field(key) { let mut value: *const libc::c_char = ptr::null(); - if field.is_null() - || (*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int - || (*field).fld_data.fld_optional_field.is_null() + if unsafe { (*field).fld_type } != MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int + || unsafe { (*field).fld_data.fld_optional_field.is_null() } || { - value = (*(*field).fld_data.fld_optional_field).fld_value; + value = unsafe { (*(*field).fld_data.fld_optional_field).fld_value }; value.is_null() } { return None; } - Some(as_str(value).to_string()) + Some(to_string(value)) + } else { + None } } @@ -706,10 +706,7 @@ fn mark_peer_as_verified(context: &Context, fingerprint: impl AsRef) -> Res * Tools: Misc. ******************************************************************************/ -fn encrypted_and_signed( - mimeparser: &dc_mimeparser_t, - expected_fingerprint: impl AsRef, -) -> bool { +fn encrypted_and_signed(mimeparser: &MimeParser, expected_fingerprint: impl AsRef) -> bool { if !mimeparser.e2ee_helper.encrypted { warn!(mimeparser.context, "Message not encrypted.",); false