majorly rustify and simplify the incoming decryption pipeline

This commit is contained in:
holger krekel
2019-09-26 21:33:26 +02:00
parent 86369148ee
commit da725a5d62
10 changed files with 724 additions and 699 deletions

387
mmime/src/display.rs Normal file
View File

@@ -0,0 +1,387 @@
use crate::clist::*;
use crate::mailimf::types::*;
use crate::mailmime::types::*;
use std::ffi::CStr;
pub unsafe fn display_mime(mut mime: *mut Mailmime) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
println!("{}", (*mime).mm_type);
match (*mime).mm_type as u32 {
MAILMIME_SINGLE => {
println!("single part");
}
MAILMIME_MULTIPLE => {
println!("multipart");
}
MAILMIME_MESSAGE => println!("message"),
_ => {}
}
if !(*mime).mm_mime_fields.is_null() {
if !(*(*(*mime).mm_mime_fields).fld_list).first.is_null() {
print!("MIME headers begin");
display_mime_fields((*mime).mm_mime_fields);
println!("MIME headers end");
}
}
display_mime_content((*mime).mm_content_type);
match (*mime).mm_type as u32 {
MAILMIME_SINGLE => {
display_mime_data((*mime).mm_data.mm_single);
}
MAILMIME_MULTIPLE => {
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
while !cur.is_null() {
display_mime(
(if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut Mailmime,
);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
MAILMIME_MESSAGE => {
if !(*mime).mm_data.mm_message.mm_fields.is_null() {
if !(*(*(*mime).mm_data.mm_message.mm_fields).fld_list)
.first
.is_null()
{
println!("headers begin");
display_fields((*mime).mm_data.mm_message.mm_fields);
println!("headers end");
}
if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() {
display_mime((*mime).mm_data.mm_message.mm_msg_mime);
}
}
}
_ => {}
};
}
unsafe fn display_mime_content(mut content_type: *mut mailmime_content) {
print!("type: ");
display_mime_type((*content_type).ct_type);
println!(
"/{}",
CStr::from_ptr((*content_type).ct_subtype).to_str().unwrap()
);
}
unsafe fn display_mime_type(mut type_0: *mut mailmime_type) {
match (*type_0).tp_type {
1 => {
display_mime_discrete_type((*type_0).tp_data.tp_discrete_type);
}
2 => {
display_mime_composite_type((*type_0).tp_data.tp_composite_type);
}
_ => {}
};
}
unsafe fn display_mime_composite_type(mut ct: *mut mailmime_composite_type) {
match (*ct).ct_type {
1 => {
print!("message");
}
2 => {
print!("multipart");
}
3 => {
print!("{}", CStr::from_ptr((*ct).ct_token).to_str().unwrap());
}
_ => {}
};
}
unsafe fn display_mime_discrete_type(mut discrete_type: *mut mailmime_discrete_type) {
match (*discrete_type).dt_type {
1 => {
print!("text");
}
2 => {
print!("image");
}
3 => {
print!("audio");
}
4 => {
print!("video");
}
5 => {
print!("application");
}
6 => {
print!("{}", (*discrete_type).dt_extension as u8 as char);
}
_ => {}
};
}
unsafe fn display_mime_data(mut data: *mut mailmime_data) {
match (*data).dt_type {
0 => {
println!(
"data : {} bytes",
(*data).dt_data.dt_text.dt_length as libc::c_uint,
);
}
1 => {
println!(
"data (file) : {}",
CStr::from_ptr((*data).dt_data.dt_filename)
.to_str()
.unwrap()
);
}
_ => {}
};
}
unsafe fn display_mime_dsp_parm(mut param: *mut mailmime_disposition_parm) {
match (*param).pa_type {
0 => {
println!(
"filename: {}",
CStr::from_ptr((*param).pa_data.pa_filename)
.to_str()
.unwrap()
);
}
_ => {}
};
}
unsafe fn display_mime_disposition(mut disposition: *mut mailmime_disposition) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*disposition).dsp_parms).first;
while !cur.is_null() {
let mut param: *mut mailmime_disposition_parm = 0 as *mut mailmime_disposition_parm;
param = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailmime_disposition_parm;
display_mime_dsp_parm(param);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
unsafe fn display_mime_field(mut field: *mut mailmime_field) {
match (*field).fld_type {
1 => {
print!("content-type: ");
display_mime_content((*field).fld_data.fld_content);
println!("");
}
6 => {
display_mime_disposition((*field).fld_data.fld_disposition);
}
_ => {}
};
}
unsafe fn display_mime_fields(mut fields: *mut mailmime_fields) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*fields).fld_list).first;
while !cur.is_null() {
let mut field: *mut mailmime_field = 0 as *mut mailmime_field;
field = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailmime_field;
display_mime_field(field);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
unsafe fn display_date_time(mut d: *mut mailimf_date_time) {
print!(
"{:02}/{:02}/{:02} {:02}:{:02}:{:02} +{:04}",
(*d).dt_day,
(*d).dt_month,
(*d).dt_year,
(*d).dt_hour,
(*d).dt_min,
(*d).dt_sec,
(*d).dt_zone,
);
}
unsafe fn display_orig_date(mut orig_date: *mut mailimf_orig_date) {
display_date_time((*orig_date).dt_date_time);
}
unsafe fn display_mailbox(mut mb: *mut mailimf_mailbox) {
if !(*mb).mb_display_name.is_null() {
print!(
"{}",
CStr::from_ptr((*mb).mb_display_name).to_str().unwrap()
);
}
print!("<{}>", CStr::from_ptr((*mb).mb_addr_spec).to_str().unwrap());
}
unsafe fn display_mailbox_list(mut mb_list: *mut mailimf_mailbox_list) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*mb_list).mb_list).first;
while !cur.is_null() {
let mut mb: *mut mailimf_mailbox = 0 as *mut mailimf_mailbox;
mb = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailimf_mailbox;
display_mailbox(mb);
if !if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
.is_null()
{
print!(", ");
}
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
unsafe fn display_group(mut group: *mut mailimf_group) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
print!(
"{}: ",
CStr::from_ptr((*group).grp_display_name).to_str().unwrap()
);
cur = (*(*(*group).grp_mb_list).mb_list).first;
while !cur.is_null() {
let mut mb: *mut mailimf_mailbox = 0 as *mut mailimf_mailbox;
mb = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailimf_mailbox;
display_mailbox(mb);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
print!("; ");
}
unsafe fn display_address(mut a: *mut mailimf_address) {
match (*a).ad_type {
2 => {
display_group((*a).ad_data.ad_group);
}
1 => {
display_mailbox((*a).ad_data.ad_mailbox);
}
_ => {}
};
}
unsafe fn display_address_list(mut addr_list: *mut mailimf_address_list) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*addr_list).ad_list).first;
while !cur.is_null() {
let mut addr: *mut mailimf_address = 0 as *mut mailimf_address;
addr = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailimf_address;
display_address(addr);
if !if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
.is_null()
{
print!(", ");
}
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
unsafe fn display_from(mut from: *mut mailimf_from) {
display_mailbox_list((*from).frm_mb_list);
}
unsafe fn display_to(mut to: *mut mailimf_to) {
display_address_list((*to).to_addr_list);
}
unsafe fn display_cc(mut cc: *mut mailimf_cc) {
display_address_list((*cc).cc_addr_list);
}
unsafe fn display_subject(mut subject: *mut mailimf_subject) {
print!("{}", CStr::from_ptr((*subject).sbj_value).to_str().unwrap());
}
unsafe fn display_field(mut field: *mut mailimf_field) {
match (*field).fld_type {
9 => {
print!("Date: ");
display_orig_date((*field).fld_data.fld_orig_date);
println!("");
}
10 => {
print!("From: ");
display_from((*field).fld_data.fld_from);
println!("");
}
13 => {
print!("To: ");
display_to((*field).fld_data.fld_to);
println!("");
}
14 => {
print!("Cc: ");
display_cc((*field).fld_data.fld_cc);
println!("");
}
19 => {
print!("Subject: ");
display_subject((*field).fld_data.fld_subject);
println!("");
}
16 => {
println!(
"Message-ID: {}",
CStr::from_ptr((*(*field).fld_data.fld_message_id).mid_value)
.to_str()
.unwrap(),
);
}
_ => {}
};
}
unsafe fn display_fields(mut fields: *mut mailimf_fields) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*fields).fld_list).first;
while !cur.is_null() {
let mut f: *mut mailimf_field = 0 as *mut mailimf_field;
f = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailimf_field;
display_field(f);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}

View File

@@ -23,6 +23,7 @@ pub mod mailimf;
pub mod mailmime; pub mod mailmime;
pub mod mmapstring; pub mod mmapstring;
pub mod other; pub mod other;
pub mod display;
pub use self::charconv::*; pub use self::charconv::*;
pub use self::chash::*; pub use self::chash::*;
@@ -31,6 +32,8 @@ pub use self::mailimf::*;
pub use self::mailmime::*; pub use self::mailmime::*;
pub use self::mmapstring::*; pub use self::mmapstring::*;
pub use self::other::*; pub use self::other::*;
pub use self::display::*;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@@ -77,384 +80,4 @@ mod tests {
mailmime::types::mailmime_free(mime); mailmime::types::mailmime_free(mime);
} }
} }
unsafe fn display_mime(mut mime: *mut Mailmime) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
println!("{}", (*mime).mm_type);
match (*mime).mm_type {
1 => {
println!("single part");
}
2 => {
println!("multipart");
}
3 => println!("message"),
_ => {}
}
if !(*mime).mm_mime_fields.is_null() {
if !(*(*(*mime).mm_mime_fields).fld_list).first.is_null() {
print!("MIME headers begin");
display_mime_fields((*mime).mm_mime_fields);
println!("MIME headers end");
}
}
display_mime_content((*mime).mm_content_type);
match (*mime).mm_type {
1 => {
display_mime_data((*mime).mm_data.mm_single);
}
2 => {
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
while !cur.is_null() {
display_mime(
(if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut Mailmime,
);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
3 => {
if !(*mime).mm_data.mm_message.mm_fields.is_null() {
if !(*(*(*mime).mm_data.mm_message.mm_fields).fld_list)
.first
.is_null()
{
println!("headers begin");
display_fields((*mime).mm_data.mm_message.mm_fields);
println!("headers end");
}
if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() {
display_mime((*mime).mm_data.mm_message.mm_msg_mime);
}
}
}
_ => {}
};
}
unsafe fn display_mime_content(mut content_type: *mut mailmime_content) {
print!("type: ");
display_mime_type((*content_type).ct_type);
println!(
"/{}",
CStr::from_ptr((*content_type).ct_subtype).to_str().unwrap()
);
}
unsafe fn display_mime_type(mut type_0: *mut mailmime_type) {
match (*type_0).tp_type {
1 => {
display_mime_discrete_type((*type_0).tp_data.tp_discrete_type);
}
2 => {
display_mime_composite_type((*type_0).tp_data.tp_composite_type);
}
_ => {}
};
}
unsafe fn display_mime_composite_type(mut ct: *mut mailmime_composite_type) {
match (*ct).ct_type {
1 => {
print!("message");
}
2 => {
print!("multipart");
}
3 => {
print!("{}", CStr::from_ptr((*ct).ct_token).to_str().unwrap());
}
_ => {}
};
}
unsafe fn display_mime_discrete_type(mut discrete_type: *mut mailmime_discrete_type) {
match (*discrete_type).dt_type {
1 => {
print!("text");
}
2 => {
print!("image");
}
3 => {
print!("audio");
}
4 => {
print!("video");
}
5 => {
print!("application");
}
6 => {
print!("{}", (*discrete_type).dt_extension as u8 as char);
}
_ => {}
};
}
unsafe fn display_mime_data(mut data: *mut mailmime_data) {
match (*data).dt_type {
0 => {
println!(
"data : {} bytes",
(*data).dt_data.dt_text.dt_length as libc::c_uint,
);
}
1 => {
println!(
"data (file) : {}",
CStr::from_ptr((*data).dt_data.dt_filename)
.to_str()
.unwrap()
);
}
_ => {}
};
}
unsafe fn display_mime_dsp_parm(mut param: *mut mailmime_disposition_parm) {
match (*param).pa_type {
0 => {
println!(
"filename: {}",
CStr::from_ptr((*param).pa_data.pa_filename)
.to_str()
.unwrap()
);
}
_ => {}
};
}
unsafe fn display_mime_disposition(mut disposition: *mut mailmime_disposition) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*disposition).dsp_parms).first;
while !cur.is_null() {
let mut param: *mut mailmime_disposition_parm = 0 as *mut mailmime_disposition_parm;
param = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailmime_disposition_parm;
display_mime_dsp_parm(param);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
unsafe fn display_mime_field(mut field: *mut mailmime_field) {
match (*field).fld_type {
1 => {
print!("content-type: ");
display_mime_content((*field).fld_data.fld_content);
println!("");
}
6 => {
display_mime_disposition((*field).fld_data.fld_disposition);
}
_ => {}
};
}
unsafe fn display_mime_fields(mut fields: *mut mailmime_fields) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*fields).fld_list).first;
while !cur.is_null() {
let mut field: *mut mailmime_field = 0 as *mut mailmime_field;
field = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailmime_field;
display_mime_field(field);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
unsafe fn display_date_time(mut d: *mut mailimf_date_time) {
print!(
"{:02}/{:02}/{:02} {:02}:{:02}:{:02} +{:04}",
(*d).dt_day,
(*d).dt_month,
(*d).dt_year,
(*d).dt_hour,
(*d).dt_min,
(*d).dt_sec,
(*d).dt_zone,
);
}
unsafe fn display_orig_date(mut orig_date: *mut mailimf_orig_date) {
display_date_time((*orig_date).dt_date_time);
}
unsafe fn display_mailbox(mut mb: *mut mailimf_mailbox) {
if !(*mb).mb_display_name.is_null() {
print!(
"{}",
CStr::from_ptr((*mb).mb_display_name).to_str().unwrap()
);
}
print!("<{}>", CStr::from_ptr((*mb).mb_addr_spec).to_str().unwrap());
}
unsafe fn display_mailbox_list(mut mb_list: *mut mailimf_mailbox_list) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*mb_list).mb_list).first;
while !cur.is_null() {
let mut mb: *mut mailimf_mailbox = 0 as *mut mailimf_mailbox;
mb = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailimf_mailbox;
display_mailbox(mb);
if !if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
.is_null()
{
print!(", ");
}
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
unsafe fn display_group(mut group: *mut mailimf_group) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
print!(
"{}: ",
CStr::from_ptr((*group).grp_display_name).to_str().unwrap()
);
cur = (*(*(*group).grp_mb_list).mb_list).first;
while !cur.is_null() {
let mut mb: *mut mailimf_mailbox = 0 as *mut mailimf_mailbox;
mb = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailimf_mailbox;
display_mailbox(mb);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
print!("; ");
}
unsafe fn display_address(mut a: *mut mailimf_address) {
match (*a).ad_type {
2 => {
display_group((*a).ad_data.ad_group);
}
1 => {
display_mailbox((*a).ad_data.ad_mailbox);
}
_ => {}
};
}
unsafe fn display_address_list(mut addr_list: *mut mailimf_address_list) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*addr_list).ad_list).first;
while !cur.is_null() {
let mut addr: *mut mailimf_address = 0 as *mut mailimf_address;
addr = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailimf_address;
display_address(addr);
if !if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
.is_null()
{
print!(", ");
}
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
unsafe fn display_from(mut from: *mut mailimf_from) {
display_mailbox_list((*from).frm_mb_list);
}
unsafe fn display_to(mut to: *mut mailimf_to) {
display_address_list((*to).to_addr_list);
}
unsafe fn display_cc(mut cc: *mut mailimf_cc) {
display_address_list((*cc).cc_addr_list);
}
unsafe fn display_subject(mut subject: *mut mailimf_subject) {
print!("{}", CStr::from_ptr((*subject).sbj_value).to_str().unwrap());
}
unsafe fn display_field(mut field: *mut mailimf_field) {
match (*field).fld_type {
9 => {
print!("Date: ");
display_orig_date((*field).fld_data.fld_orig_date);
println!("");
}
10 => {
print!("From: ");
display_from((*field).fld_data.fld_from);
println!("");
}
13 => {
print!("To: ");
display_to((*field).fld_data.fld_to);
println!("");
}
14 => {
print!("Cc: ");
display_cc((*field).fld_data.fld_cc);
println!("");
}
19 => {
print!("Subject: ");
display_subject((*field).fld_data.fld_subject);
println!("");
}
16 => {
println!(
"Message-ID: {}",
CStr::from_ptr((*(*field).fld_data.fld_message_id).mid_value)
.to_str()
.unwrap(),
);
}
_ => {}
};
}
unsafe fn display_fields(mut fields: *mut mailimf_fields) {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*fields).fld_list).first;
while !cur.is_null() {
let mut f: *mut mailimf_field = 0 as *mut mailimf_field;
f = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailimf_field;
display_field(f);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
} }

View File

@@ -154,6 +154,7 @@ pub struct unnamed_6 {
pub dt_data: *const libc::c_char, pub dt_data: *const libc::c_char,
pub dt_length: size_t, pub dt_length: size_t,
} }
pub type unnamed_7 = libc::c_uint; pub type unnamed_7 = libc::c_uint;
pub const MAILMIME_MESSAGE: unnamed_7 = 3; pub const MAILMIME_MESSAGE: unnamed_7 = 3;
pub const MAILMIME_MULTIPLE: unnamed_7 = 2; pub const MAILMIME_MULTIPLE: unnamed_7 = 2;

View File

@@ -102,7 +102,7 @@ impl<'a> MimeParser<'a> {
} }
} }
pub unsafe fn parse(&mut self, body: &[u8]) { pub unsafe fn parse(&mut self, body: &[u8]) -> Result<(), Error> {
let mut index = 0; let mut index = 0;
let r = mailmime_parse( let r = mailmime_parse(
@@ -113,7 +113,7 @@ impl<'a> MimeParser<'a> {
); );
if r == MAILIMF_NO_ERROR as libc::c_int && !self.mimeroot.is_null() { if r == MAILIMF_NO_ERROR as libc::c_int && !self.mimeroot.is_null() {
self.e2ee_helper.decrypt(self.context, self.mimeroot); self.e2ee_helper.try_decrypt(self.context, self.mimeroot)?;
self.parse_mime_recursive(self.mimeroot); self.parse_mime_recursive(self.mimeroot);
if let Some(field) = self.lookup_field("Subject") { if let Some(field) = self.lookup_field("Subject") {
@@ -317,6 +317,7 @@ impl<'a> MimeParser<'a> {
} }
self.parts.push(part_5); self.parts.push(part_5);
} }
Ok(())
} }
pub fn get_last_nonmeta(&mut self) -> Option<&mut Part> { pub fn get_last_nonmeta(&mut self) -> Option<&mut Part> {
@@ -1056,7 +1057,7 @@ unsafe fn mailmime_get_mime_type(mime: *mut Mailmime) -> (libc::c_int, Viewtype,
Some("alternative") => DC_MIMETYPE_MP_ALTERNATIVE, Some("alternative") => DC_MIMETYPE_MP_ALTERNATIVE,
Some("related") => DC_MIMETYPE_MP_RELATED, Some("related") => DC_MIMETYPE_MP_RELATED,
Some("encrypted") => { Some("encrypted") => {
// decryptable parts are already converted to other mime parts in dc_e2ee_decrypt() // apparently try_decrypt failed to decrypt
DC_MIMETYPE_MP_NOT_DECRYPTABLE DC_MIMETYPE_MP_NOT_DECRYPTABLE
} }
Some("signed") => DC_MIMETYPE_MP_SIGNED, Some("signed") => DC_MIMETYPE_MP_SIGNED,
@@ -1426,7 +1427,7 @@ mod tests {
let context = dummy_context(); let context = dummy_context();
let raw = include_bytes!("../test-data/message/issue_523.txt"); let raw = include_bytes!("../test-data/message/issue_523.txt");
let mut mimeparser = MimeParser::new(&context.ctx); let mut mimeparser = MimeParser::new(&context.ctx);
unsafe { mimeparser.parse(&raw[..]) }; unsafe { mimeparser.parse(&raw[..]).unwrap() };
assert_eq!(mimeparser.subject, None); assert_eq!(mimeparser.subject, None);
assert_eq!(mimeparser.parts.len(), 1); assert_eq!(mimeparser.parts.len(), 1);
} }
@@ -1436,7 +1437,7 @@ mod tests {
fn test_dc_mailmime_parse_crash_fuzzy(data in "[!-~\t ]{2000,}") { fn test_dc_mailmime_parse_crash_fuzzy(data in "[!-~\t ]{2000,}") {
let context = dummy_context(); let context = dummy_context();
let mut mimeparser = MimeParser::new(&context.ctx); let mut mimeparser = MimeParser::new(&context.ctx);
unsafe { mimeparser.parse(data.as_bytes()) }; unsafe { mimeparser.parse(data.as_bytes()).unwrap() };
} }
} }
@@ -1445,7 +1446,7 @@ mod tests {
let context = dummy_context(); let context = dummy_context();
let raw = include_bytes!("../test-data/message/mail_with_message_id.txt"); let raw = include_bytes!("../test-data/message/mail_with_message_id.txt");
let mut mimeparser = MimeParser::new(&context.ctx); let mut mimeparser = MimeParser::new(&context.ctx);
unsafe { mimeparser.parse(&raw[..]) }; unsafe { mimeparser.parse(&raw[..]).unwrap() };
assert_eq!( assert_eq!(
mimeparser.get_rfc724_mid(), mimeparser.get_rfc724_mid(),
Some("2dfdbde7@example.org".into()) Some("2dfdbde7@example.org".into())
@@ -1457,7 +1458,7 @@ mod tests {
let context = dummy_context(); let context = dummy_context();
let raw = include_bytes!("../test-data/message/issue_523.txt"); let raw = include_bytes!("../test-data/message/issue_523.txt");
let mut mimeparser = MimeParser::new(&context.ctx); let mut mimeparser = MimeParser::new(&context.ctx);
unsafe { mimeparser.parse(&raw[..]) }; unsafe { mimeparser.parse(&raw[..]).unwrap() };
assert_eq!(mimeparser.get_rfc724_mid(), None); assert_eq!(mimeparser.get_rfc724_mid(), None);
} }
@@ -1467,7 +1468,7 @@ mod tests {
let context = dummy_context(); 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 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 = MimeParser::new(&context.ctx); let mut mimeparser = MimeParser::new(&context.ctx);
mimeparser.parse(&raw[..]); mimeparser.parse(&raw[..]).unwrap();
assert_eq!(mimeparser.subject, Some("inner-subject".into())); assert_eq!(mimeparser.subject, Some("inner-subject".into()));

View File

@@ -61,7 +61,9 @@ pub unsafe fn dc_receive_imf(
// somewhen, I did not found out anything that speaks against this approach yet) // somewhen, I did not found out anything that speaks against this approach yet)
let mut mime_parser = MimeParser::new(context); let mut mime_parser = MimeParser::new(context);
mime_parser.parse(imf_raw); if let Err(err) = mime_parser.parse(imf_raw) {
error!(context, "dc_receive_imf parse error: {}", err);
};
if mime_parser.header.is_empty() { if mime_parser.header.is_empty() {
// Error - even adding an empty record won't help as we do not know the message ID // Error - even adding an empty record won't help as we do not know the message ID
@@ -1148,21 +1150,15 @@ unsafe fn create_or_lookup_group(
// check, if we have a chat with this group ID // 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); let (mut chat_id, chat_id_verified, _blocked) = chat::get_chat_id_by_grpid(context, &grpid);
if chat_id != 0 { if chat_id != 0 {
let mut failure_reason = std::ptr::null_mut(); if chat_id_verified {
if let Err(err) =
if chat_id_verified check_verified_properties(context, mime_parser, from_id as u32, to_ids)
&& 0 == check_verified_properties(
context,
mime_parser,
from_id as u32,
to_ids,
&mut failure_reason,
)
{ {
mime_parser.repl_msg_by_error(to_string(failure_reason)); warn!(context, "verification problem: {}", err);
let s = format!("{}. See 'Info' for more details", err);
mime_parser.repl_msg_by_error(s);
}
} }
free(failure_reason.cast());
} }
// check if the sender is a member of the existing group - // check if the sender is a member of the existing group -
@@ -1191,18 +1187,14 @@ unsafe fn create_or_lookup_group(
let mut create_verified = VerifiedStatus::Unverified; let mut create_verified = VerifiedStatus::Unverified;
if mime_parser.lookup_field("Chat-Verified").is_some() { if mime_parser.lookup_field("Chat-Verified").is_some() {
create_verified = VerifiedStatus::Verified; create_verified = VerifiedStatus::Verified;
let mut failure_reason = std::ptr::null_mut();
if 0 == check_verified_properties( if let Err(err) =
context, check_verified_properties(context, mime_parser, from_id as u32, to_ids)
mime_parser, {
from_id as u32, warn!(context, "verification problem: {}", err);
to_ids, let s = format!("{}. See 'Info' for more details", err);
&mut failure_reason, mime_parser.repl_msg_by_error(&s);
) {
mime_parser.repl_msg_by_error(to_string(failure_reason));
} }
free(failure_reason.cast());
} }
if 0 == allow_creation { if 0 == allow_creation {
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked); cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
@@ -1609,51 +1601,41 @@ fn search_chat_ids_by_contact_ids(context: &Context, unsorted_contact_ids: &Vec<
chat_ids chat_ids
} }
unsafe fn check_verified_properties( fn check_verified_properties(
context: &Context, context: &Context,
mimeparser: &MimeParser, mimeparser: &MimeParser,
from_id: u32, from_id: u32,
to_ids: &Vec<u32>, to_ids: &Vec<u32>,
failure_reason: *mut *mut libc::c_char, ) -> Result<()> {
) -> libc::c_int { let contact = Contact::load_from_db(context, from_id)?;
let verify_fail = |reason: String| {
*failure_reason = format!("{}. See \"Info\" for details.", reason).strdup();
warn!(context, "{}", reason);
};
let contact = match Contact::load_from_db(context, from_id) { ensure!(
Ok(contact) => contact, mimeparser.e2ee_helper.encrypted,
Err(_err) => { "This message is not encrypted."
verify_fail("Internal Error; cannot load contact".into()); );
return 0;
}
};
if !mimeparser.e2ee_helper.encrypted {
verify_fail("This message is not encrypted".into());
return 0;
}
// ensure, the contact is verified // ensure, the contact is verified
// and the message is signed with a verified key of the sender. // and the message is signed with a verified key of the sender.
// this check is skipped for SELF as there is no proper SELF-peerstate // this check is skipped for SELF as there is no proper SELF-peerstate
// and results in group-splits otherwise. // and results in group-splits otherwise.
if from_id != 1 { if from_id != DC_CONTACT_ID_SELF {
let peerstate = Peerstate::from_addr(context, &context.sql, contact.get_addr()); let peerstate = Peerstate::from_addr(context, &context.sql, contact.get_addr());
if peerstate.is_none() if peerstate.is_none()
|| contact.is_verified_ex(context, peerstate.as_ref()) || contact.is_verified_ex(context, peerstate.as_ref())
!= VerifiedStatus::BidirectVerified != VerifiedStatus::BidirectVerified
{ {
verify_fail("The sender of this message is not verified.".into()); bail!(
return 0; "Sender of this message is not verified: {}",
contact.get_addr()
);
} }
if let Some(peerstate) = peerstate { if let Some(peerstate) = peerstate {
if !peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures) { ensure!(
verify_fail("The message was sent with non-verified encryption.".into()); peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures),
return 0; "The message was sent with non-verified encryption."
} );
} }
} }
@@ -1671,13 +1653,13 @@ unsafe fn check_verified_properties(
rows.collect::<std::result::Result<Vec<_>, _>>() rows.collect::<std::result::Result<Vec<_>, _>>()
.map_err(Into::into) .map_err(Into::into)
}, },
); )?;
if rows.is_err() { for (to_addr, _is_verified) in rows.into_iter() {
return 0; let mut is_verified = _is_verified != 0;
}
for (to_addr, mut is_verified) in rows.unwrap().into_iter() {
let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr); let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr);
// mark gossiped keys (if any) as verified
if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr) && peerstate.is_some() { if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr) && peerstate.is_some() {
let peerstate = peerstate.as_mut().unwrap(); let peerstate = peerstate.as_mut().unwrap();
@@ -1686,7 +1668,7 @@ unsafe fn check_verified_properties(
// - OR if the verified-key does not match public-key or gossip-key // - OR if the verified-key does not match public-key or gossip-key
// (otherwise a verified key can _only_ be updated through QR scan which might be annoying, // (otherwise a verified key can _only_ be updated through QR scan which might be annoying,
// see https://github.com/nextleap-project/countermitm/issues/46 for a discussion about this point) // see https://github.com/nextleap-project/countermitm/issues/46 for a discussion about this point)
if 0 == is_verified if !is_verified
|| peerstate.verified_key_fingerprint != peerstate.public_key_fingerprint || peerstate.verified_key_fingerprint != peerstate.public_key_fingerprint
&& peerstate.verified_key_fingerprint != peerstate.gossip_key_fingerprint && peerstate.verified_key_fingerprint != peerstate.gossip_key_fingerprint
{ {
@@ -1694,21 +1676,19 @@ unsafe fn check_verified_properties(
let fp = peerstate.gossip_key_fingerprint.clone(); let fp = peerstate.gossip_key_fingerprint.clone();
if let Some(fp) = fp { if let Some(fp) = fp {
peerstate.set_verified(0, &fp, 2); peerstate.set_verified(0, &fp, 2);
peerstate.save_to_db(&context.sql, false); peerstate.save_to_db(&context.sql, false).unwrap();
is_verified = 1; is_verified = true;
} }
} }
} }
if 0 == is_verified { if !is_verified {
verify_fail(format!( bail!(
"{} is not a member of this verified group", "{} is not a member of this verified group",
to_addr to_addr.to_string()
)); );
return 0;
} }
} }
Ok(())
1
} }
fn set_better_msg(mime_parser: &mut MimeParser, better_msg: impl AsRef<str>) { fn set_better_msg(mime_parser: &mut MimeParser, better_msg: impl AsRef<str>) {

View File

@@ -7,6 +7,7 @@ use std::ptr;
use std::str::FromStr; use std::str::FromStr;
use libc::{free, strcmp, strlen, strncmp}; use libc::{free, strcmp, strlen, strncmp};
use mmime::display::display_mime;
use mmime::clist::*; use mmime::clist::*;
use mmime::mailimf::types::*; use mmime::mailimf::types::*;
use mmime::mailimf::types_helper::*; use mmime::mailimf::types_helper::*;
@@ -305,9 +306,11 @@ impl E2eeHelper {
} }
} }
pub unsafe fn decrypt(&mut self, context: &Context, in_out_message: *mut Mailmime) { pub unsafe fn try_decrypt(
/* return values: 0=nothing to decrypt/cannot decrypt, 1=sth. decrypted &mut self,
(to detect parts that could not be decrypted, simply look for left "multipart/encrypted" MIME types */ context: &Context,
in_out_message: *mut Mailmime,
) -> Result<()> {
/*just a pointer into mailmime structure, must not be freed*/ /*just a pointer into mailmime structure, must not be freed*/
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message); let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
let mut message_time = 0; let mut message_time = 0;
@@ -343,16 +346,16 @@ impl E2eeHelper {
if let Some(ref mut peerstate) = peerstate { if let Some(ref mut peerstate) = peerstate {
if let Some(ref header) = autocryptheader { if let Some(ref header) = autocryptheader {
peerstate.apply_header(&header, message_time); peerstate.apply_header(&header, message_time);
peerstate.save_to_db(&context.sql, false); peerstate.save_to_db(&context.sql, false).unwrap();
} else if message_time > peerstate.last_seen_autocrypt } else if message_time > peerstate.last_seen_autocrypt
&& !contains_report(in_out_message) && !contains_report(in_out_message)
{ {
peerstate.degrade_encryption(message_time); peerstate.degrade_encryption(message_time);
peerstate.save_to_db(&context.sql, false); peerstate.save_to_db(&context.sql, false).unwrap();
} }
} else if let Some(ref header) = autocryptheader { } else if let Some(ref header) = autocryptheader {
let p = Peerstate::from_header(context, header, message_time); let p = Peerstate::from_header(context, header, message_time);
assert!(p.save_to_db(&context.sql, true)); p.save_to_db(&context.sql, true).unwrap();
peerstate = Some(p); peerstate = Some(p);
} }
} }
@@ -380,30 +383,22 @@ impl E2eeHelper {
public_keyring_for_validate.add_ref(key); public_keyring_for_validate.add_ref(key);
} }
} }
for iterations in 0..10 {
let mut has_unencrypted_parts: libc::c_int = 0i32; match decrypt_if_autocrypt_message(
if decrypt_recursive(
context, context,
in_out_message, in_out_message,
&private_keyring, &private_keyring,
&public_keyring_for_validate, &public_keyring_for_validate,
&mut self.signatures, &mut self.signatures,
&mut gossip_headers, &mut gossip_headers,
&mut has_unencrypted_parts, ) {
) Ok(res) => {
.is_err() self.encrypted = res;
{
break;
} }
/* if we're here, sth. was encrypted. if we're on top-level, Err(err) => {
and there are no additional unencrypted parts in the message bail!("failed to decrypt: {}", err);
the encryption was fine (signature is handled separately and
returned as `signatures`) */
if iterations == 0 && 0 == has_unencrypted_parts {
self.encrypted = true;
} }
} }
/* check for Autocrypt-Gossip */
if !gossip_headers.is_null() { if !gossip_headers.is_null() {
self.gossipped_addr = update_gossip_peerstates( self.gossipped_addr = update_gossip_peerstates(
context, context,
@@ -419,6 +414,7 @@ impl E2eeHelper {
if !gossip_headers.is_null() { if !gossip_headers.is_null() {
mailimf_fields_free(gossip_headers); mailimf_fields_free(gossip_headers);
} }
Ok(())
} }
} }
@@ -536,10 +532,10 @@ unsafe fn update_gossip_peerstates(
Peerstate::from_addr(context, &context.sql, &header.addr); Peerstate::from_addr(context, &context.sql, &header.addr);
if let Some(ref mut peerstate) = peerstate { if let Some(ref mut peerstate) = peerstate {
peerstate.apply_gossip(header, message_time); peerstate.apply_gossip(header, message_time);
peerstate.save_to_db(&context.sql, false); peerstate.save_to_db(&context.sql, false).unwrap();
} else { } else {
let p = Peerstate::from_gossip(context, header, message_time); let p = Peerstate::from_gossip(context, header, message_time);
p.save_to_db(&context.sql, true); p.save_to_db(&context.sql, true).unwrap();
peerstate = Some(p); peerstate = Some(p);
} }
if let Some(peerstate) = peerstate { if let Some(peerstate) = peerstate {
@@ -564,41 +560,75 @@ unsafe fn update_gossip_peerstates(
gossipped_addr gossipped_addr
} }
unsafe fn decrypt_recursive( fn decrypt_if_autocrypt_message(
context: &Context, context: &Context,
mime: *mut Mailmime, mime_undetermined: *mut Mailmime,
private_keyring: &Keyring, private_keyring: &Keyring,
public_keyring_for_validate: &Keyring, public_keyring_for_validate: &Keyring,
ret_valid_signatures: &mut HashSet<String>, ret_valid_signatures: &mut HashSet<String>,
ret_gossip_headers: *mut *mut mailimf_fields, ret_gossip_headers: *mut *mut mailimf_fields,
ret_has_unencrypted_parts: *mut libc::c_int, ) -> Result<(bool)> {
) -> Result<()> { /* The returned bool is true if we detected an Autocrypt-encrypted
ensure!(!mime.is_null(), "Invalid mime reference"); message and successfully decrypted it. Decryption modifies the
let ct: *mut mailmime_content; passed in mime structure in place. The returned bool is false
if it was not an Autocrypt message.
Errors are returned for failures related to decryption.
*/
ensure!(!mime_undetermined.is_null(), "Invalid mime reference");
let mime: *mut Mailmime;
unsafe {
println!("****** INCOMING MSG BEGIN");
display_mime(mime_undetermined);
println!("****** INCOMING MSG END");
if (*mime).mm_type == MAILMIME_MULTIPLE as libc::c_int { if (*mime_undetermined).mm_type != MAILMIME_MESSAGE as libc::c_int {
ct = (*mime).mm_content_type; return Ok(false);
if !ct.is_null() }
&& !(*ct).ct_subtype.is_null() mime = (*mime_undetermined).mm_data.mm_message.mm_msg_mime;
&& strcmp(
(*ct).ct_subtype, if (*mime).mm_type != MAILMIME_MULTIPLE as libc::c_int
b"encrypted\x00" as *const u8 as *const libc::c_char, || "encrypted" != wrapmime::get_ct_subtype(mime).unwrap_or_default()
) == 0i32
{ {
for cur_data in (*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter() { return Ok(false);
let mut decrypted_mime: *mut Mailmime = ptr::null_mut(); }
let decrypted = match decrypt_part( }
info!(context, "found OpenPGP-encrypted message");
// we may have a proper Multipart/Encrypted Autocrypt Level 1 message
// XXX: more precise check we have exactly this specified OpenPGP-mime structure
// https://tools.ietf.org/html/rfc3156.html#section-4
let mut parts: Vec<*mut libc::c_void> = Vec::new();
unsafe {
parts.extend((*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter());
}
ensure!(parts.len() == 2, "Invalid Autocrypt Level 1 Mime Parts");
info!(context, "decrypt_if_autocrypt_message found AC-encrypted message");
// ensure protocol-parameter "application/pgp-encrypted")
// ensure wrapmime::get_content_type(parts[1])) == "application/octetstream"
let encrypted_mime_payload = parts[1] as *mut mmime::mailmime::types::Mailmime;
let decrypted_mime = match decrypt_part(
context, context,
cur_data as *mut Mailmime, encrypted_mime_payload,
private_keyring, private_keyring,
public_keyring_for_validate, public_keyring_for_validate,
ret_valid_signatures, ret_valid_signatures,
&mut decrypted_mime,
) { ) {
Ok(res) => res, Ok(res) => res,
Err(err) => bail!("decrypt_part: {}", err), Err(err) => bail!("decrypt_part failed: {}", err),
}; };
if decrypted { /* decrypted_mime is a dangling pointer which we now put into
mailmime's Ownership */
unsafe {
mailmime_substitute(mime, decrypted_mime);
mailmime_free(mime);
}
/* finally, let's return any gossip headers */
unsafe {
if (*ret_gossip_headers).is_null() && ret_valid_signatures.len() > 0 { if (*ret_gossip_headers).is_null() && ret_valid_signatures.len() > 0 {
let mut dummy: libc::size_t = 0; let mut dummy: libc::size_t = 0;
let mut test: *mut mailimf_fields = ptr::null_mut(); let mut test: *mut mailimf_fields = ptr::null_mut();
@@ -613,141 +643,55 @@ unsafe fn decrypt_recursive(
*ret_gossip_headers = test *ret_gossip_headers = test
} }
} }
mailmime_substitute(mime, decrypted_mime);
mailmime_free(mime);
return Ok(());
} }
} return Ok(true);
*ret_has_unencrypted_parts = 1i32
} else {
for cur_data in (*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter() {
if decrypt_recursive(
context,
cur_data as *mut Mailmime,
private_keyring,
public_keyring_for_validate,
ret_valid_signatures,
ret_gossip_headers,
ret_has_unencrypted_parts,
)
.is_ok()
{
return Ok(());
}
}
}
} else if (*mime).mm_type == MAILMIME_MESSAGE as libc::c_int {
if decrypt_recursive(
context,
(*mime).mm_data.mm_message.mm_msg_mime,
private_keyring,
public_keyring_for_validate,
ret_valid_signatures,
ret_gossip_headers,
ret_has_unencrypted_parts,
)
.is_ok()
{
return Ok(());
}
} else {
*ret_has_unencrypted_parts = 1;
}
Err(format_err!("Failed to decrypt"))
} }
unsafe fn decrypt_part( fn decrypt_part(
_context: &Context, _context: &Context,
mime: *mut Mailmime, mime: *mut Mailmime,
private_keyring: &Keyring, private_keyring: &Keyring,
public_keyring_for_validate: &Keyring, public_keyring_for_validate: &Keyring,
ret_valid_signatures: &mut HashSet<String>, ret_valid_signatures: &mut HashSet<String>,
ret_decrypted_mime: *mut *mut Mailmime, ) -> Result<*mut Mailmime> {
) -> Result<bool> {
let mime_data: *mut mailmime_data; let mime_data: *mut mailmime_data;
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 mut sth_decrypted = false;
let cleanup = |transfer_decoding_buffer: *mut libc::c_char| { unsafe {
if !transfer_decoding_buffer.is_null() {
mmap_string_unref(transfer_decoding_buffer);
}
};
*ret_decrypted_mime = ptr::null_mut();
mime_data = (*mime).mm_data.mm_single; 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
{
return Ok(false);
} }
if !(*mime).mm_mime_fields.is_null() { if !wrapmime::has_decryptable_data_(mime_data) {
for cur_data in (*(*(*mime).mm_mime_fields).fld_list).into_iter() { return Ok(ptr::null_mut());
let field: *mut mailmime_field = cur_data as *mut _;
if (*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
}
}
}
/* regarding `Content-Transfer-Encoding:` */
/* mmap_string_unref()'d if set */
let mut transfer_decoding_buffer: *mut libc::c_char = ptr::null_mut();
let decoded_data: *const libc::c_char;
let mut decoded_data_bytes: libc::size_t = 0;
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
{
decoded_data = (*mime_data).dt_data.dt_text.dt_data;
decoded_data_bytes = (*mime_data).dt_data.dt_text.dt_length;
if decoded_data.is_null() || decoded_data_bytes <= 0 {
/* no error - but no data */
return Ok(false);
}
} else {
let r: libc::c_int;
let mut current_index: libc::size_t = 0;
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
{
cleanup(transfer_decoding_buffer);
bail!("mailmime_part_parse returned error or invalid data");
}
decoded_data = transfer_decoding_buffer;
} }
/* encrypted, decoded data in decoded_data now ... */ if let Some(enc) = wrapmime::get_mime_transfer_encoding(mime) {
mime_transfer_encoding = enc;
}
let (decoded_data, decoded_data_bytes) =
wrapmime::decode_dt_data(mime_data, mime_transfer_encoding)?;
/* encrypted, non-NULL decoded data in decoded_data now ...
Note that we need to take care of freeing decoded_data ourself.
Once decryption is finished we unref() can do this, so our caller does not
need to care for it.
*/
let mut ret_decrypted_mime = ptr::null_mut();
unsafe {
if has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int) { if has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int) {
let add_signatures = if ret_valid_signatures.is_empty() { /* we should only have one decryption happening */
Some(ret_valid_signatures) assert!(ret_valid_signatures.is_empty(), "corrupted");
} else {
None
};
/*if we already have fingerprints, do not add more; this ensures, only the fingerprints from the outer-most part are collected */
let plain = match dc_pgp_pk_decrypt( let plain = match dc_pgp_pk_decrypt(
std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes), std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes),
&private_keyring, &private_keyring,
&public_keyring_for_validate, &public_keyring_for_validate,
add_signatures, Some(ret_valid_signatures),
) { ) {
Ok(plain) => plain, Ok(plain) => plain,
Err(err) => { Err(err) => {
cleanup(transfer_decoding_buffer); mmap_string_unref(decoded_data);
bail!("could not decrypt: {}", err) bail!("could not decrypt: {}", err)
} }
}; };
@@ -768,16 +712,13 @@ unsafe fn decrypt_part(
mailmime_free(decrypted_mime); mailmime_free(decrypted_mime);
} }
} else { } else {
*ret_decrypted_mime = decrypted_mime; ret_decrypted_mime = decrypted_mime;
sth_decrypted = true;
} }
std::mem::forget(plain); std::mem::forget(plain);
} }
//mailmime_substitute(mime, new_mime); mmap_string_unref(decoded_data);
//s. mailprivacy_gnupg.c::pgp_decrypt() }
cleanup(transfer_decoding_buffer); Ok(ret_decrypted_mime)
Ok(sth_decrypted)
} }
unsafe fn has_decrypted_pgp_armor(str__: *const libc::c_char, mut str_bytes: libc::c_int) -> bool { unsafe fn has_decrypted_pgp_armor(str__: *const libc::c_char, mut str_bytes: libc::c_int) -> bool {

View File

@@ -7,6 +7,7 @@ use crate::aheader::*;
use crate::chat::*; use crate::chat::*;
use crate::constants::*; use crate::constants::*;
use crate::context::Context; use crate::context::Context;
use crate::error::*;
use crate::key::*; use crate::key::*;
use crate::sql::{self, Sql}; use crate::sql::{self, Sql};
@@ -408,28 +409,19 @@ impl<'a> Peerstate<'a> {
success success
} }
pub fn save_to_db(&self, sql: &Sql, create: bool) -> bool { pub fn save_to_db(&self, sql: &Sql, create: bool) -> Result<()> {
let mut success = false; ensure!(!self.addr.is_none(), "self.addr is not configured");
if self.addr.is_none() {
return success;
}
if create { if create {
if sql::execute( sql::execute(
self.context, self.context,
sql, sql,
"INSERT INTO acpeerstates (addr) VALUES(?);", "INSERT INTO acpeerstates (addr) VALUES(?);",
params![self.addr.as_ref().unwrap()], params![self.addr.as_ref().unwrap()],
) )?;
.is_err()
{
return false;
}
} }
if self.to_save == Some(ToSave::All) || create { if self.to_save == Some(ToSave::All) || create {
success = sql::execute( sql::execute(
self.context, self.context,
sql, sql,
"UPDATE acpeerstates \ "UPDATE acpeerstates \
@@ -450,10 +442,9 @@ impl<'a> Peerstate<'a> {
&self.verified_key_fingerprint, &self.verified_key_fingerprint,
&self.addr, &self.addr,
], ],
).is_ok(); )?
assert_eq!(success, true);
} else if self.to_save == Some(ToSave::Timestamps) { } else if self.to_save == Some(ToSave::Timestamps) {
success = sql::execute( sql::execute(
self.context, self.context,
sql, sql,
"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? \ "UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? \
@@ -464,15 +455,14 @@ impl<'a> Peerstate<'a> {
self.gossip_timestamp, self.gossip_timestamp,
&self.addr &self.addr
], ],
) )?;
.is_ok();
} }
if self.to_save == Some(ToSave::All) || create { if self.to_save == Some(ToSave::All) || create {
reset_gossiped_timestamp(self.context, 0); reset_gossiped_timestamp(self.context, 0);
} }
success Ok(())
} }
pub fn has_verified_key(&self, fingerprints: &HashSet<String>) -> bool { pub fn has_verified_key(&self, fingerprints: &HashSet<String>) -> bool {
@@ -522,7 +512,10 @@ mod tests {
degrade_event: None, degrade_event: None,
}; };
assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save"); assert!(
peerstate.save_to_db(&ctx.ctx.sql, true).is_ok(),
"failed to save to db"
);
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into()) let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into())
.expect("failed to load peerstate from db"); .expect("failed to load peerstate from db");
@@ -564,7 +557,10 @@ mod tests {
degrade_event: None, degrade_event: None,
}; };
assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save"); assert!(
peerstate.save_to_db(&ctx.ctx.sql, true).is_ok(),
"failed to save"
);
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into()) let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into())
.expect("failed to load peerstate from db"); .expect("failed to load peerstate from db");

View File

@@ -678,7 +678,7 @@ fn mark_peer_as_verified(context: &Context, fingerprint: impl AsRef<str>) -> Res
if peerstate.set_verified(1, fingerprint.as_ref(), 2) { if peerstate.set_verified(1, fingerprint.as_ref(), 2) {
peerstate.prefer_encrypt = EncryptPreference::Mutual; peerstate.prefer_encrypt = EncryptPreference::Mutual;
peerstate.to_save = Some(ToSave::All); peerstate.to_save = Some(ToSave::All);
peerstate.save_to_db(&context.sql, false); peerstate.save_to_db(&context.sql, false).unwrap();
return Ok(()); return Ok(());
} }
} }

View File

@@ -777,7 +777,7 @@ fn open(
if let Some(ref mut peerstate) = Peerstate::from_addr(context, sql, &addr?) if let Some(ref mut peerstate) = Peerstate::from_addr(context, sql, &addr?)
{ {
peerstate.recalc_fingerprint(); peerstate.recalc_fingerprint();
peerstate.save_to_db(sql, false); peerstate.save_to_db(sql, false).unwrap();
} }
} }
Ok(()) Ok(())

View File

@@ -1,10 +1,12 @@
use std::ffi::CString; use std::ffi::CString;
use std::ptr;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::error::Error; use crate::error::Error;
use mmime::clist::*; use mmime::clist::*;
use mmime::mailimf::types::*; use mmime::mailimf::types::*;
use mmime::mailimf::types_helper::*; use mmime::mailimf::types_helper::*;
use mmime::mailmime::content::*;
use mmime::mailmime::disposition::*; use mmime::mailmime::disposition::*;
use mmime::mailmime::types::*; use mmime::mailmime::types::*;
use mmime::mailmime::types_helper::*; use mmime::mailmime::types_helper::*;
@@ -25,6 +27,100 @@ macro_rules! clist_append {
}; };
} }
/**************************************
* mime parsing API
**************************************/
pub fn get_ct_subtype(mime: *mut Mailmime) -> Option<String> {
unsafe {
let ct: *mut mailmime_content = (*mime).mm_content_type;
if !ct.is_null() && !(*ct).ct_subtype.is_null() {
println!("ct_subtype: {}", to_string((*ct).ct_subtype));
Some(to_string((*ct).ct_subtype))
} else {
None
}
}
}
pub fn has_decryptable_data_(mime_data: *mut mailmime_data) -> bool {
/* MAILMIME_DATA_FILE indicates, the data is in a file; AFAIK this is not used on parsing */
unsafe {
(*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
}
}
pub fn get_mime_transfer_encoding(mime: *mut Mailmime) -> Option<libc::c_int> {
unsafe {
let mm_mime_fields = (*mime).mm_mime_fields;
if !mm_mime_fields.is_null() {
for cur_data in (*(*mm_mime_fields).fld_list).into_iter() {
let field: *mut mailmime_field = cur_data as *mut _;
if (*field).fld_type == MAILMIME_FIELD_TRANSFER_ENCODING as libc::c_int
&& !(*field).fld_data.fld_encoding.is_null()
{
return Some((*(*field).fld_data.fld_encoding).enc_type);
}
}
}
}
None
}
pub fn decode_dt_data(
mime_data: *mut mailmime_data,
mime_transfer_encoding: libc::c_int,
) -> Result<(*mut libc::c_char, libc::size_t), Error> {
// Decode data according to mime_transfer_encoding
// returns Ok with a (decoded_data,decoded_data_bytes) pointer
// where the caller must make sure to free it.
// It may return Ok(ptr::null_mut(), 0)
let mut transfer_decoding_buffer: *mut libc::c_char = ptr::null_mut();
let decoded_data: *mut libc::c_char;
let mut decoded_data_bytes: libc::size_t = 0;
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
{
unsafe {
decoded_data = (*mime_data).dt_data.dt_text.dt_data as *mut _;
decoded_data_bytes = (*mime_data).dt_data.dt_text.dt_length;
}
ensure!(
!decoded_data.is_null() && decoded_data_bytes > 0,
"could not decode mime message"
);
} else {
let mut current_index: libc::size_t = 0;
unsafe {
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
{
bail!("mailmime_part_parse returned error or invalid data");
}
decoded_data = transfer_decoding_buffer;
}
}
Ok((decoded_data, decoded_data_bytes))
}
/**************************************
* mime creation API
**************************************/
pub fn add_filename_part( pub fn add_filename_part(
message: *mut Mailmime, message: *mut Mailmime,
basename: &str, basename: &str,