mirror of
https://github.com/chatmail/core.git
synced 2026-05-07 17:06:35 +03:00
majorly rustify and simplify the incoming decryption pipeline
This commit is contained in:
387
mmime/src/display.rs
Normal file
387
mmime/src/display.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
383
mmime/src/lib.rs
383
mmime/src/lib.rs
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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()));
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
warn!(context, "verification problem: {}", err);
|
||||||
mime_parser,
|
let s = format!("{}. See 'Info' for more details", err);
|
||||||
from_id as u32,
|
mime_parser.repl_msg_by_error(s);
|
||||||
to_ids,
|
}
|
||||||
&mut 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 -
|
// 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>) {
|
||||||
|
|||||||
377
src/e2ee.rs
377
src/e2ee.rs
@@ -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) => {
|
||||||
)
|
self.encrypted = res;
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
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,220 +560,165 @@ 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()
|
|
||||||
&& strcmp(
|
|
||||||
(*ct).ct_subtype,
|
|
||||||
b"encrypted\x00" as *const u8 as *const libc::c_char,
|
|
||||||
) == 0i32
|
|
||||||
{
|
|
||||||
for cur_data in (*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter() {
|
|
||||||
let mut decrypted_mime: *mut Mailmime = ptr::null_mut();
|
|
||||||
let decrypted = match decrypt_part(
|
|
||||||
context,
|
|
||||||
cur_data as *mut Mailmime,
|
|
||||||
private_keyring,
|
|
||||||
public_keyring_for_validate,
|
|
||||||
ret_valid_signatures,
|
|
||||||
&mut decrypted_mime,
|
|
||||||
) {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err(err) => bail!("decrypt_part: {}", err),
|
|
||||||
};
|
|
||||||
if decrypted {
|
|
||||||
if (*ret_gossip_headers).is_null() && ret_valid_signatures.len() > 0 {
|
|
||||||
let mut dummy: libc::size_t = 0;
|
|
||||||
let mut test: *mut mailimf_fields = ptr::null_mut();
|
|
||||||
if mailimf_envelope_and_optional_fields_parse(
|
|
||||||
(*decrypted_mime).mm_mime_start,
|
|
||||||
(*decrypted_mime).mm_length,
|
|
||||||
&mut dummy,
|
|
||||||
&mut test,
|
|
||||||
) == MAILIMF_NO_ERROR as libc::c_int
|
|
||||||
&& !test.is_null()
|
|
||||||
{
|
|
||||||
*ret_gossip_headers = test
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mailmime_substitute(mime, decrypted_mime);
|
|
||||||
mailmime_free(mime);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*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 {
|
mime = (*mime_undetermined).mm_data.mm_message.mm_msg_mime;
|
||||||
if decrypt_recursive(
|
|
||||||
context,
|
if (*mime).mm_type != MAILMIME_MULTIPLE as libc::c_int
|
||||||
(*mime).mm_data.mm_message.mm_msg_mime,
|
|| "encrypted" != wrapmime::get_ct_subtype(mime).unwrap_or_default()
|
||||||
private_keyring,
|
|
||||||
public_keyring_for_validate,
|
|
||||||
ret_valid_signatures,
|
|
||||||
ret_gossip_headers,
|
|
||||||
ret_has_unencrypted_parts,
|
|
||||||
)
|
|
||||||
.is_ok()
|
|
||||||
{
|
{
|
||||||
return Ok(());
|
return Ok(false);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
*ret_has_unencrypted_parts = 1;
|
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,
|
||||||
|
encrypted_mime_payload,
|
||||||
|
private_keyring,
|
||||||
|
public_keyring_for_validate,
|
||||||
|
ret_valid_signatures,
|
||||||
|
) {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(err) => bail!("decrypt_part failed: {}", err),
|
||||||
|
};
|
||||||
|
/* decrypted_mime is a dangling pointer which we now put into
|
||||||
|
mailmime's Ownership */
|
||||||
|
unsafe {
|
||||||
|
mailmime_substitute(mime, decrypted_mime);
|
||||||
|
mailmime_free(mime);
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(format_err!("Failed to decrypt"))
|
/* finally, let's return any gossip headers */
|
||||||
|
unsafe {
|
||||||
|
if (*ret_gossip_headers).is_null() && ret_valid_signatures.len() > 0 {
|
||||||
|
let mut dummy: libc::size_t = 0;
|
||||||
|
let mut test: *mut mailimf_fields = ptr::null_mut();
|
||||||
|
if mailimf_envelope_and_optional_fields_parse(
|
||||||
|
(*decrypted_mime).mm_mime_start,
|
||||||
|
(*decrypted_mime).mm_length,
|
||||||
|
&mut dummy,
|
||||||
|
&mut test,
|
||||||
|
) == MAILIMF_NO_ERROR as libc::c_int
|
||||||
|
&& !test.is_null()
|
||||||
|
{
|
||||||
|
*ret_gossip_headers = test
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
mime_data = (*mime).mm_data.mm_single;
|
||||||
mmap_string_unref(transfer_decoding_buffer);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
*ret_decrypted_mime = ptr::null_mut();
|
|
||||||
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()
|
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) {
|
||||||
|
/* we should only have one decryption happening */
|
||||||
|
assert!(ret_valid_signatures.is_empty(), "corrupted");
|
||||||
|
|
||||||
|
let plain = match dc_pgp_pk_decrypt(
|
||||||
|
std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes),
|
||||||
|
&private_keyring,
|
||||||
|
&public_keyring_for_validate,
|
||||||
|
Some(ret_valid_signatures),
|
||||||
|
) {
|
||||||
|
Ok(plain) => plain,
|
||||||
|
Err(err) => {
|
||||||
|
mmap_string_unref(decoded_data);
|
||||||
|
bail!("could not decrypt: {}", err)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let plain_bytes = plain.len();
|
||||||
|
let plain_buf = plain.as_ptr() as *const libc::c_char;
|
||||||
|
|
||||||
|
let mut index: libc::size_t = 0;
|
||||||
|
let mut decrypted_mime: *mut Mailmime = ptr::null_mut();
|
||||||
|
if mailmime_parse(
|
||||||
|
plain_buf as *const _,
|
||||||
|
plain_bytes,
|
||||||
|
&mut index,
|
||||||
|
&mut decrypted_mime,
|
||||||
|
) != MAIL_NO_ERROR as libc::c_int
|
||||||
|
|| decrypted_mime.is_null()
|
||||||
{
|
{
|
||||||
mime_transfer_encoding = (*(*field).fld_data.fld_encoding).enc_type
|
if !decrypted_mime.is_null() {
|
||||||
|
mailmime_free(decrypted_mime);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret_decrypted_mime = decrypted_mime;
|
||||||
}
|
}
|
||||||
|
std::mem::forget(plain);
|
||||||
}
|
}
|
||||||
|
mmap_string_unref(decoded_data);
|
||||||
}
|
}
|
||||||
/* regarding `Content-Transfer-Encoding:` */
|
Ok(ret_decrypted_mime)
|
||||||
/* 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 has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int) {
|
|
||||||
let add_signatures = if ret_valid_signatures.is_empty() {
|
|
||||||
Some(ret_valid_signatures)
|
|
||||||
} 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(
|
|
||||||
std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes),
|
|
||||||
&private_keyring,
|
|
||||||
&public_keyring_for_validate,
|
|
||||||
add_signatures,
|
|
||||||
) {
|
|
||||||
Ok(plain) => plain,
|
|
||||||
Err(err) => {
|
|
||||||
cleanup(transfer_decoding_buffer);
|
|
||||||
bail!("could not decrypt: {}", err)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let plain_bytes = plain.len();
|
|
||||||
let plain_buf = plain.as_ptr() as *const libc::c_char;
|
|
||||||
|
|
||||||
let mut index: libc::size_t = 0;
|
|
||||||
let mut decrypted_mime: *mut Mailmime = ptr::null_mut();
|
|
||||||
if mailmime_parse(
|
|
||||||
plain_buf as *const _,
|
|
||||||
plain_bytes,
|
|
||||||
&mut index,
|
|
||||||
&mut decrypted_mime,
|
|
||||||
) != MAIL_NO_ERROR as libc::c_int
|
|
||||||
|| decrypted_mime.is_null()
|
|
||||||
{
|
|
||||||
if !decrypted_mime.is_null() {
|
|
||||||
mailmime_free(decrypted_mime);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*ret_decrypted_mime = decrypted_mime;
|
|
||||||
sth_decrypted = true;
|
|
||||||
}
|
|
||||||
std::mem::forget(plain);
|
|
||||||
}
|
|
||||||
//mailmime_substitute(mime, new_mime);
|
|
||||||
//s. mailprivacy_gnupg.c::pgp_decrypt()
|
|
||||||
cleanup(transfer_decoding_buffer);
|
|
||||||
|
|
||||||
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 {
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(())
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user