mirror of
https://github.com/chatmail/core.git
synced 2026-05-07 08:56:30 +03:00
shift most mmime functions to wrapmime
This commit is contained in:
@@ -287,12 +287,12 @@ impl<'a> MimeParser<'a> {
|
|||||||
) == MAILIMF_NO_ERROR as libc::c_int
|
) == MAILIMF_NO_ERROR as libc::c_int
|
||||||
&& !mb_list.is_null()
|
&& !mb_list.is_null()
|
||||||
{
|
{
|
||||||
if let Some(dn_to_addr) = mailimf_find_first_addr(mb_list) {
|
if let Some(dn_to_addr) = wrapmime::mailimf_find_first_addr(mb_list) {
|
||||||
if let Some(from_field) = self.lookup_field("From") {
|
if let Some(from_field) = self.lookup_field("From") {
|
||||||
if (*from_field).fld_type == MAILIMF_FIELD_FROM as libc::c_int
|
if (*from_field).fld_type == MAILIMF_FIELD_FROM as libc::c_int
|
||||||
&& !(*from_field).fld_data.fld_from.is_null()
|
&& !(*from_field).fld_data.fld_from.is_null()
|
||||||
{
|
{
|
||||||
let from_addr = mailimf_find_first_addr(
|
let from_addr = wrapmime::mailimf_find_first_addr(
|
||||||
(*(*from_field).fld_data.fld_from).frm_mb_list,
|
(*(*from_field).fld_data.fld_from).frm_mb_list,
|
||||||
);
|
);
|
||||||
if let Some(from_addr) = from_addr {
|
if let Some(from_addr) = from_addr {
|
||||||
@@ -590,7 +590,7 @@ impl<'a> MimeParser<'a> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut decoded_data = match mailmime_transfer_decode(mime) {
|
let mut decoded_data = match wrapmime::mailmime_transfer_decode(mime) {
|
||||||
Ok(decoded_data) => decoded_data,
|
Ok(decoded_data) => decoded_data,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// Note that it's now always an error - might be no data
|
// Note that it's now always an error - might be no data
|
||||||
@@ -838,7 +838,7 @@ impl<'a> MimeParser<'a> {
|
|||||||
let mut fld_from: *const mailimf_from = ptr::null();
|
let mut fld_from: *const mailimf_from = ptr::null();
|
||||||
|
|
||||||
/* get From: and check there is exactly one sender */
|
/* get From: and check there is exactly one sender */
|
||||||
let fld = mailimf_find_field(self.header_root, MAILIMF_FIELD_FROM as libc::c_int);
|
let fld = wrapmime::mailimf_find_field(self.header_root, MAILIMF_FIELD_FROM as libc::c_int);
|
||||||
if !(fld.is_null()
|
if !(fld.is_null()
|
||||||
|| {
|
|| {
|
||||||
fld_from = (*fld).fld_data.fld_from;
|
fld_from = (*fld).fld_data.fld_from;
|
||||||
@@ -856,7 +856,7 @@ impl<'a> MimeParser<'a> {
|
|||||||
|
|
||||||
if !mb.is_null() {
|
if !mb.is_null() {
|
||||||
let from_addr_norm = addr_normalize(as_str((*mb).mb_addr_spec));
|
let from_addr_norm = addr_normalize(as_str((*mb).mb_addr_spec));
|
||||||
let recipients = mailimf_get_recipients(self.header_root);
|
let recipients = wrapmime::mailimf_get_recipients(self.header_root);
|
||||||
if recipients.len() == 1 {
|
if recipients.len() == 1 {
|
||||||
if recipients.contains(from_addr_norm) {
|
if recipients.contains(from_addr_norm) {
|
||||||
sender_equals_recipient = true;
|
sender_equals_recipient = true;
|
||||||
@@ -917,22 +917,6 @@ pub struct Part {
|
|||||||
pub param: Params,
|
pub param: Params,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mailimf_find_first_addr(mb_list: *const mailimf_mailbox_list) -> Option<String> {
|
|
||||||
if mb_list.is_null() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
for cur in unsafe { (*(*mb_list).mb_list).into_iter() } {
|
|
||||||
let mb = cur as *mut mailimf_mailbox;
|
|
||||||
if !mb.is_null() && !unsafe { (*mb).mb_addr_spec.is_null() } {
|
|
||||||
let addr = unsafe { as_str((*mb).mb_addr_spec) };
|
|
||||||
return Some(addr_normalize(addr).to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn hash_header(out: &mut HashMap<String, *mut mailimf_field>, in_0: *const mailimf_fields) {
|
unsafe fn hash_header(out: &mut HashMap<String, *mut mailimf_field>, in_0: *const mailimf_fields) {
|
||||||
if in_0.is_null() {
|
if in_0.is_null() {
|
||||||
return;
|
return;
|
||||||
@@ -1154,162 +1138,6 @@ pub unsafe fn mailmime_find_ct_parameter(
|
|||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mailmime_transfer_decode(mime: *mut Mailmime) -> Result<Vec<u8>, Error> {
|
|
||||||
ensure!(!mime.is_null(), "invalid inputs");
|
|
||||||
|
|
||||||
let mime_transfer_encoding =
|
|
||||||
wrapmime::get_mime_transfer_encoding(mime).unwrap_or(MAILMIME_MECHANISM_BINARY as i32);
|
|
||||||
|
|
||||||
let mime_data = unsafe { (*mime).mm_data.mm_single };
|
|
||||||
|
|
||||||
wrapmime::decode_dt_data(mime_data, mime_transfer_encoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet<String> {
|
|
||||||
/* returned addresses are normalized. */
|
|
||||||
let mut recipients: HashSet<String> = Default::default();
|
|
||||||
|
|
||||||
for cur in unsafe { (*(*imffields).fld_list).into_iter() } {
|
|
||||||
let fld = cur as *mut mailimf_field;
|
|
||||||
|
|
||||||
let fld_to: *mut mailimf_to;
|
|
||||||
let fld_cc: *mut mailimf_cc;
|
|
||||||
|
|
||||||
let mut addr_list: *mut mailimf_address_list = ptr::null_mut();
|
|
||||||
if fld.is_null() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fld = unsafe { *fld };
|
|
||||||
|
|
||||||
// TODO match on enums /rtn
|
|
||||||
match fld.fld_type {
|
|
||||||
13 => {
|
|
||||||
fld_to = unsafe { fld.fld_data.fld_to };
|
|
||||||
if !fld_to.is_null() {
|
|
||||||
addr_list = unsafe { (*fld_to).to_addr_list };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14 => {
|
|
||||||
fld_cc = unsafe { fld.fld_data.fld_cc };
|
|
||||||
if !fld_cc.is_null() {
|
|
||||||
addr_list = unsafe { (*fld_cc).cc_addr_list };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !addr_list.is_null() {
|
|
||||||
for cur2 in unsafe { &(*(*addr_list).ad_list) } {
|
|
||||||
let adr = cur2 as *mut mailimf_address;
|
|
||||||
|
|
||||||
if adr.is_null() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let adr = unsafe { *adr };
|
|
||||||
|
|
||||||
if adr.ad_type == MAILIMF_ADDRESS_MAILBOX as libc::c_int {
|
|
||||||
mailimf_get_recipients_add_addr(&mut recipients, unsafe {
|
|
||||||
adr.ad_data.ad_mailbox
|
|
||||||
});
|
|
||||||
} else if adr.ad_type == MAILIMF_ADDRESS_GROUP as libc::c_int {
|
|
||||||
let group = unsafe { adr.ad_data.ad_group };
|
|
||||||
if !group.is_null() && unsafe { !(*group).grp_mb_list.is_null() } {
|
|
||||||
for cur3 in unsafe { &(*(*(*group).grp_mb_list).mb_list) } {
|
|
||||||
mailimf_get_recipients_add_addr(
|
|
||||||
&mut recipients,
|
|
||||||
cur3 as *mut mailimf_mailbox,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
recipients
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mailimf_get_recipients_add_addr(recipients: &mut HashSet<String>, mb: *mut mailimf_mailbox) {
|
|
||||||
if !mb.is_null() {
|
|
||||||
let addr_norm = addr_normalize(as_str(unsafe { (*mb).mb_addr_spec }));
|
|
||||||
recipients.insert(addr_norm.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*the result is a pointer to mime, must not be freed*/
|
|
||||||
pub fn mailimf_find_field(
|
|
||||||
header: *mut mailimf_fields,
|
|
||||||
wanted_fld_type: libc::c_int,
|
|
||||||
) -> *mut mailimf_field {
|
|
||||||
if header.is_null() {
|
|
||||||
return ptr::null_mut();
|
|
||||||
}
|
|
||||||
|
|
||||||
let header = unsafe { (*header) };
|
|
||||||
if header.fld_list.is_null() {
|
|
||||||
return ptr::null_mut();
|
|
||||||
}
|
|
||||||
|
|
||||||
for cur in unsafe { &(*header.fld_list) } {
|
|
||||||
let field = cur as *mut mailimf_field;
|
|
||||||
if !field.is_null() {
|
|
||||||
if unsafe { (*field).fld_type } == wanted_fld_type {
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr::null_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*the result is a pointer to mime, must not be freed*/
|
|
||||||
pub unsafe fn mailmime_find_mailimf_fields(mime: *mut Mailmime) -> *mut mailimf_fields {
|
|
||||||
if mime.is_null() {
|
|
||||||
return ptr::null_mut();
|
|
||||||
}
|
|
||||||
|
|
||||||
match (*mime).mm_type as _ {
|
|
||||||
MAILMIME_MULTIPLE => {
|
|
||||||
for cur_data in (*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter() {
|
|
||||||
let header = mailmime_find_mailimf_fields(cur_data as *mut _);
|
|
||||||
if !header.is_null() {
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MAILMIME_MESSAGE => return (*mime).mm_data.mm_message.mm_fields,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr::null_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn mailimf_find_optional_field(
|
|
||||||
header: *mut mailimf_fields,
|
|
||||||
wanted_fld_name: *const libc::c_char,
|
|
||||||
) -> *mut mailimf_optional_field {
|
|
||||||
if header.is_null() || (*header).fld_list.is_null() {
|
|
||||||
return ptr::null_mut();
|
|
||||||
}
|
|
||||||
for cur_data in (*(*header).fld_list).into_iter() {
|
|
||||||
let field: *mut mailimf_field = cur_data as *mut _;
|
|
||||||
|
|
||||||
if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
|
|
||||||
let optional_field: *mut mailimf_optional_field = (*field).fld_data.fld_optional_field;
|
|
||||||
if !optional_field.is_null()
|
|
||||||
&& !(*optional_field).fld_name.is_null()
|
|
||||||
&& !(*optional_field).fld_value.is_null()
|
|
||||||
&& strcasecmp((*optional_field).fld_name, wanted_fld_name) == 0i32
|
|
||||||
{
|
|
||||||
return optional_field;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr::null_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -1325,14 +1153,13 @@ mod tests {
|
|||||||
let mut mime: *mut Mailmime = ptr::null_mut();
|
let mut mime: *mut Mailmime = ptr::null_mut();
|
||||||
let mut dummy = 0;
|
let mut dummy = 0;
|
||||||
let res = mailmime_parse(txt, strlen(txt), &mut dummy, &mut mime);
|
let res = mailmime_parse(txt, strlen(txt), &mut dummy, &mut mime);
|
||||||
|
|
||||||
assert_eq!(res, MAIL_NO_ERROR as libc::c_int);
|
assert_eq!(res, MAIL_NO_ERROR as libc::c_int);
|
||||||
assert!(!mime.is_null());
|
assert!(!mime.is_null());
|
||||||
|
|
||||||
let fields: *mut mailimf_fields = mailmime_find_mailimf_fields(mime);
|
let fields: *mut mailimf_fields = wrapmime::mailmime_find_mailimf_fields(mime);
|
||||||
assert!(!fields.is_null());
|
assert!(!fields.is_null());
|
||||||
|
|
||||||
let mut of_a: *mut mailimf_optional_field = mailimf_find_optional_field(
|
let mut of_a: *mut mailimf_optional_field = wrapmime::mailimf_find_optional_field(
|
||||||
fields,
|
fields,
|
||||||
b"fielda\x00" as *const u8 as *const libc::c_char,
|
b"fielda\x00" as *const u8 as *const libc::c_char,
|
||||||
);
|
);
|
||||||
@@ -1352,7 +1179,7 @@ mod tests {
|
|||||||
"ValueA",
|
"ValueA",
|
||||||
);
|
);
|
||||||
|
|
||||||
of_a = mailimf_find_optional_field(
|
of_a = wrapmime::mailimf_find_optional_field(
|
||||||
fields,
|
fields,
|
||||||
b"FIELDA\x00" as *const u8 as *const libc::c_char,
|
b"FIELDA\x00" as *const u8 as *const libc::c_char,
|
||||||
);
|
);
|
||||||
@@ -1372,7 +1199,7 @@ mod tests {
|
|||||||
"ValueA",
|
"ValueA",
|
||||||
);
|
);
|
||||||
|
|
||||||
let of_b: *mut mailimf_optional_field = mailimf_find_optional_field(
|
let of_b: *mut mailimf_optional_field = wrapmime::mailimf_find_optional_field(
|
||||||
fields,
|
fields,
|
||||||
b"FieldB\x00" as *const u8 as *const libc::c_char,
|
b"FieldB\x00" as *const u8 as *const libc::c_char,
|
||||||
);
|
);
|
||||||
@@ -1395,7 +1222,9 @@ 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[..]).unwrap() };
|
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);
|
||||||
}
|
}
|
||||||
@@ -1403,9 +1232,13 @@ mod tests {
|
|||||||
proptest! {
|
proptest! {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dc_mailmime_parse_crash_fuzzy(data in "[!-~\t ]{2000,}") {
|
fn test_dc_mailmime_parse_crash_fuzzy(data in "[!-~\t ]{2000,}") {
|
||||||
|
// this test doesn't exercise much of dc_mimeparser anymore
|
||||||
|
// because a missing From-field early aborts parsing
|
||||||
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()).unwrap() };
|
unsafe {
|
||||||
|
assert!(mimeparser.parse(data.as_bytes()).is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1434,7 +1267,7 @@ mod tests {
|
|||||||
fn test_mimeparser_with_context() {
|
fn test_mimeparser_with_context() {
|
||||||
unsafe {
|
unsafe {
|
||||||
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"From: hello\nContent-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[..]).unwrap();
|
mimeparser.parse(&raw[..]).unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ use crate::peerstate::*;
|
|||||||
use crate::securejoin::handle_securejoin_handshake;
|
use crate::securejoin::handle_securejoin_handshake;
|
||||||
use crate::sql;
|
use crate::sql;
|
||||||
use crate::stock::StockMessage;
|
use crate::stock::StockMessage;
|
||||||
|
use crate::wrapmime;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
enum CreateEvent {
|
enum CreateEvent {
|
||||||
@@ -795,7 +796,7 @@ unsafe fn handle_reports(
|
|||||||
b"disposition-notification\x00" as *const u8 as *const libc::c_char,
|
b"disposition-notification\x00" as *const u8 as *const libc::c_char,
|
||||||
) == 0
|
) == 0
|
||||||
{
|
{
|
||||||
if let Ok(report_body) = mailmime_transfer_decode(report_data) {
|
if let Ok(report_body) = wrapmime::mailmime_transfer_decode(report_data) {
|
||||||
let mut report_parsed = std::ptr::null_mut();
|
let mut report_parsed = std::ptr::null_mut();
|
||||||
let mut dummy = 0;
|
let mut dummy = 0;
|
||||||
|
|
||||||
@@ -807,13 +808,14 @@ unsafe fn handle_reports(
|
|||||||
) == MAIL_NO_ERROR as libc::c_int
|
) == MAIL_NO_ERROR as libc::c_int
|
||||||
&& !report_parsed.is_null()
|
&& !report_parsed.is_null()
|
||||||
{
|
{
|
||||||
let report_fields = mailmime_find_mailimf_fields(report_parsed);
|
let report_fields =
|
||||||
|
wrapmime::mailmime_find_mailimf_fields(report_parsed);
|
||||||
if !report_fields.is_null() {
|
if !report_fields.is_null() {
|
||||||
let of_disposition = mailimf_find_optional_field(
|
let of_disposition = wrapmime::mailimf_find_optional_field(
|
||||||
report_fields,
|
report_fields,
|
||||||
b"Disposition\x00" as *const u8 as *const libc::c_char,
|
b"Disposition\x00" as *const u8 as *const libc::c_char,
|
||||||
);
|
);
|
||||||
let of_org_msgid = mailimf_find_optional_field(
|
let of_org_msgid = wrapmime::mailimf_find_optional_field(
|
||||||
report_fields,
|
report_fields,
|
||||||
b"Original-Message-ID\x00" as *const u8 as *const libc::c_char,
|
b"Original-Message-ID\x00" as *const u8 as *const libc::c_char,
|
||||||
);
|
);
|
||||||
|
|||||||
150
src/e2ee.rs
150
src/e2ee.rs
@@ -22,7 +22,6 @@ use num_traits::FromPrimitive;
|
|||||||
use crate::aheader::*;
|
use crate::aheader::*;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::dc_mimeparser::*;
|
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::key::*;
|
use crate::key::*;
|
||||||
@@ -266,103 +265,80 @@ pub fn try_decrypt(
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
in_out_message: *mut Mailmime,
|
in_out_message: *mut Mailmime,
|
||||||
) -> Result<(bool, HashSet<String>, HashSet<String>)> {
|
) -> Result<(bool, HashSet<String>, HashSet<String>)> {
|
||||||
|
// just a pointer into mailmime structure, must not be freed
|
||||||
|
let imffields = unsafe { mailmime_find_mailimf_fields(in_out_message) };
|
||||||
|
ensure!(
|
||||||
|
!in_out_message.is_null() && !imffields.is_null(),
|
||||||
|
"corrupt invalid mime inputs"
|
||||||
|
);
|
||||||
|
|
||||||
|
let from = wrapmime::get_field_from(imffields)?;
|
||||||
|
let message_time = wrapmime::get_field_date(imffields)?;
|
||||||
|
|
||||||
|
let mut peerstate = None;
|
||||||
|
let autocryptheader = Aheader::from_imffields(&from, imffields);
|
||||||
|
|
||||||
|
if message_time > 0 {
|
||||||
|
peerstate = Peerstate::from_addr(context, &context.sql, &from);
|
||||||
|
|
||||||
|
if let Some(ref mut peerstate) = peerstate {
|
||||||
|
if let Some(ref header) = autocryptheader {
|
||||||
|
peerstate.apply_header(&header, message_time);
|
||||||
|
peerstate.save_to_db(&context.sql, false).unwrap();
|
||||||
|
} else if message_time > peerstate.last_seen_autocrypt
|
||||||
|
&& !contains_report(in_out_message)
|
||||||
|
{
|
||||||
|
peerstate.degrade_encryption(message_time);
|
||||||
|
peerstate.save_to_db(&context.sql, false).unwrap();
|
||||||
|
}
|
||||||
|
} else if let Some(ref header) = autocryptheader {
|
||||||
|
let p = Peerstate::from_header(context, header, message_time);
|
||||||
|
p.save_to_db(&context.sql, true).unwrap();
|
||||||
|
peerstate = Some(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* possibly perform decryption */
|
||||||
|
let mut private_keyring = Keyring::default();
|
||||||
|
let mut public_keyring_for_validate = Keyring::default();
|
||||||
let mut encrypted = false;
|
let mut encrypted = false;
|
||||||
let mut signatures = HashSet::default();
|
let mut signatures = HashSet::default();
|
||||||
let mut gossipped_addr = HashSet::default();
|
let mut gossipped_addr = HashSet::default();
|
||||||
|
|
||||||
// just a pointer into mailmime structure, must not be freed
|
let self_addr = context.get_config(Config::ConfiguredAddr);
|
||||||
let imffields = unsafe { mailmime_find_mailimf_fields(in_out_message) };
|
|
||||||
let mut message_time = 0;
|
|
||||||
let mut from = None;
|
|
||||||
let mut private_keyring = Keyring::default();
|
|
||||||
let mut public_keyring_for_validate = Keyring::default();
|
|
||||||
let mut gossip_headers = ptr::null_mut();
|
|
||||||
|
|
||||||
// XXX do wrapmime:: helper for the next block
|
if let Some(self_addr) = self_addr {
|
||||||
if !(in_out_message.is_null() || imffields.is_null()) {
|
if private_keyring.load_self_private_for_decrypting(context, self_addr, &context.sql) {
|
||||||
let mut field = mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int);
|
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
|
||||||
|
peerstate = Peerstate::from_addr(&context, &context.sql, &from);
|
||||||
if !field.is_null() && unsafe { !(*field).fld_data.fld_from.is_null() } {
|
}
|
||||||
let mb_list = unsafe { (*(*field).fld_data.fld_from).frm_mb_list };
|
if let Some(ref peerstate) = peerstate {
|
||||||
from = mailimf_find_first_addr(mb_list);
|
if peerstate.degrade_event.is_some() {
|
||||||
}
|
handle_degrade_event(context, &peerstate)?;
|
||||||
|
}
|
||||||
field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int);
|
if let Some(ref key) = peerstate.gossip_key {
|
||||||
if !field.is_null() && unsafe { !(*field).fld_data.fld_orig_date.is_null() } {
|
public_keyring_for_validate.add_ref(key);
|
||||||
let orig_date = unsafe { (*field).fld_data.fld_orig_date };
|
}
|
||||||
|
if let Some(ref key) = peerstate.public_key {
|
||||||
if !orig_date.is_null() {
|
public_keyring_for_validate.add_ref(key);
|
||||||
let dt = unsafe { (*orig_date).dt_date_time };
|
|
||||||
message_time = dc_timestamp_from_date(dt);
|
|
||||||
if message_time != 0 && message_time > time() {
|
|
||||||
message_time = time()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
let mut peerstate = None;
|
|
||||||
let autocryptheader = from
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|from| Aheader::from_imffields(from, imffields));
|
|
||||||
if message_time > 0 {
|
|
||||||
if let Some(ref from) = from {
|
|
||||||
peerstate = Peerstate::from_addr(context, &context.sql, from);
|
|
||||||
|
|
||||||
if let Some(ref mut peerstate) = peerstate {
|
let mut gossip_headers = ptr::null_mut();
|
||||||
if let Some(ref header) = autocryptheader {
|
encrypted = decrypt_if_autocrypt_message(
|
||||||
peerstate.apply_header(&header, message_time);
|
context,
|
||||||
peerstate.save_to_db(&context.sql, false).unwrap();
|
in_out_message,
|
||||||
} else if message_time > peerstate.last_seen_autocrypt
|
&private_keyring,
|
||||||
&& !contains_report(in_out_message)
|
&public_keyring_for_validate,
|
||||||
{
|
&mut signatures,
|
||||||
peerstate.degrade_encryption(message_time);
|
&mut gossip_headers,
|
||||||
peerstate.save_to_db(&context.sql, false).unwrap();
|
)?;
|
||||||
}
|
if !gossip_headers.is_null() {
|
||||||
} else if let Some(ref header) = autocryptheader {
|
gossipped_addr =
|
||||||
let p = Peerstate::from_header(context, header, message_time);
|
update_gossip_peerstates(context, message_time, imffields, gossip_headers)?;
|
||||||
p.save_to_db(&context.sql, true).unwrap();
|
unsafe { mailimf_fields_free(gossip_headers) };
|
||||||
peerstate = Some(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* load private key for decryption */
|
|
||||||
let self_addr = context.get_config(Config::ConfiguredAddr);
|
|
||||||
if let Some(self_addr) = self_addr {
|
|
||||||
if private_keyring.load_self_private_for_decrypting(context, self_addr, &context.sql) {
|
|
||||||
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
|
|
||||||
peerstate =
|
|
||||||
Peerstate::from_addr(&context, &context.sql, &from.unwrap_or_default());
|
|
||||||
}
|
|
||||||
if let Some(ref peerstate) = peerstate {
|
|
||||||
if peerstate.degrade_event.is_some() {
|
|
||||||
handle_degrade_event(context, &peerstate)?;
|
|
||||||
}
|
|
||||||
if let Some(ref key) = peerstate.gossip_key {
|
|
||||||
public_keyring_for_validate.add_ref(key);
|
|
||||||
}
|
|
||||||
if let Some(ref key) = peerstate.public_key {
|
|
||||||
public_keyring_for_validate.add_ref(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encrypted = decrypt_if_autocrypt_message(
|
|
||||||
context,
|
|
||||||
in_out_message,
|
|
||||||
&private_keyring,
|
|
||||||
&public_keyring_for_validate,
|
|
||||||
&mut signatures,
|
|
||||||
&mut gossip_headers,
|
|
||||||
)?;
|
|
||||||
if !gossip_headers.is_null() {
|
|
||||||
gossipped_addr =
|
|
||||||
update_gossip_peerstates(context, message_time, imffields, gossip_headers)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !gossip_headers.is_null() {
|
|
||||||
unsafe { mailimf_fields_free(gossip_headers) };
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((encrypted, signatures, gossipped_addr))
|
Ok((encrypted, signatures, gossipped_addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use crate::chat::{self, Chat};
|
|||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use crate::contact::*;
|
use crate::contact::*;
|
||||||
use crate::context::{get_version_str, Context};
|
use crate::context::{get_version_str, Context};
|
||||||
use crate::dc_mimeparser::{mailmime_find_mailimf_fields, SystemMessage};
|
use crate::dc_mimeparser::SystemMessage;
|
||||||
use crate::dc_strencode::*;
|
use crate::dc_strencode::*;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
use crate::e2ee::*;
|
use crate::e2ee::*;
|
||||||
@@ -645,7 +645,7 @@ impl<'a> MimeFactory<'a> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/*just a pointer into mailmime structure, must not be freed*/
|
/*just a pointer into mailmime structure, must not be freed*/
|
||||||
let imffields_unprotected = mailmime_find_mailimf_fields(message);
|
let imffields_unprotected = wrapmime::mailmime_find_mailimf_fields(message);
|
||||||
ensure!(
|
ensure!(
|
||||||
!imffields_unprotected.is_null(),
|
!imffields_unprotected.is_null(),
|
||||||
"could not find mime fields"
|
"could not find mime fields"
|
||||||
|
|||||||
233
src/wrapmime.rs
233
src/wrapmime.rs
@@ -1,10 +1,12 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
use crate::contact::addr_normalize;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use mmime::clist::*;
|
use mmime::clist::*;
|
||||||
use mmime::display::*;
|
// use mmime::display::*;
|
||||||
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::content::*;
|
||||||
@@ -90,6 +92,192 @@ pub fn has_decryptable_data(mime_data: *mut mailmime_data) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_field_from(imffields: *mut mailimf_fields) -> Result<String, Error> {
|
||||||
|
let field = mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int);
|
||||||
|
if !field.is_null() && unsafe { !(*field).fld_data.fld_from.is_null() } {
|
||||||
|
let mb_list = unsafe { (*(*field).fld_data.fld_from).frm_mb_list };
|
||||||
|
if let Some(addr) = mailimf_find_first_addr(mb_list) {
|
||||||
|
return Ok(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bail!("not From field found");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_field_date(imffields: *mut mailimf_fields) -> Result<i64, Error> {
|
||||||
|
let field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int);
|
||||||
|
let mut message_time = 0;
|
||||||
|
|
||||||
|
if !field.is_null() && unsafe { !(*field).fld_data.fld_orig_date.is_null() } {
|
||||||
|
let orig_date = unsafe { (*field).fld_data.fld_orig_date };
|
||||||
|
|
||||||
|
if !orig_date.is_null() {
|
||||||
|
let dt = unsafe { (*orig_date).dt_date_time };
|
||||||
|
message_time = dc_timestamp_from_date(dt);
|
||||||
|
if message_time != 0 && message_time > time() {
|
||||||
|
message_time = time()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(message_time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mailimf_get_recipients_add_addr(recipients: &mut HashSet<String>, mb: *mut mailimf_mailbox) {
|
||||||
|
if !mb.is_null() {
|
||||||
|
let addr_norm = addr_normalize(as_str(unsafe { (*mb).mb_addr_spec }));
|
||||||
|
recipients.insert(addr_norm.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*the result is a pointer to mime, must not be freed*/
|
||||||
|
pub fn mailimf_find_field(
|
||||||
|
header: *mut mailimf_fields,
|
||||||
|
wanted_fld_type: libc::c_int,
|
||||||
|
) -> *mut mailimf_field {
|
||||||
|
if header.is_null() {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let header = unsafe { (*header) };
|
||||||
|
if header.fld_list.is_null() {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
for cur in unsafe { &(*header.fld_list) } {
|
||||||
|
let field = cur as *mut mailimf_field;
|
||||||
|
if !field.is_null() {
|
||||||
|
if unsafe { (*field).fld_type } == wanted_fld_type {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*the result is a pointer to mime, must not be freed*/
|
||||||
|
pub unsafe fn mailmime_find_mailimf_fields(mime: *mut Mailmime) -> *mut mailimf_fields {
|
||||||
|
if mime.is_null() {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
match (*mime).mm_type as _ {
|
||||||
|
MAILMIME_MULTIPLE => {
|
||||||
|
for cur_data in (*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter() {
|
||||||
|
let header = mailmime_find_mailimf_fields(cur_data as *mut _);
|
||||||
|
if !header.is_null() {
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MAILMIME_MESSAGE => return (*mime).mm_data.mm_message.mm_fields,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn mailimf_find_optional_field(
|
||||||
|
header: *mut mailimf_fields,
|
||||||
|
wanted_fld_name: *const libc::c_char,
|
||||||
|
) -> *mut mailimf_optional_field {
|
||||||
|
if header.is_null() || (*header).fld_list.is_null() {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
for cur_data in (*(*header).fld_list).into_iter() {
|
||||||
|
let field: *mut mailimf_field = cur_data as *mut _;
|
||||||
|
|
||||||
|
if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
|
||||||
|
let optional_field: *mut mailimf_optional_field = (*field).fld_data.fld_optional_field;
|
||||||
|
if !optional_field.is_null()
|
||||||
|
&& !(*optional_field).fld_name.is_null()
|
||||||
|
&& !(*optional_field).fld_value.is_null()
|
||||||
|
&& strcasecmp((*optional_field).fld_name, wanted_fld_name) == 0i32
|
||||||
|
{
|
||||||
|
return optional_field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet<String> {
|
||||||
|
/* returned addresses are normalized. */
|
||||||
|
let mut recipients: HashSet<String> = Default::default();
|
||||||
|
|
||||||
|
for cur in unsafe { (*(*imffields).fld_list).into_iter() } {
|
||||||
|
let fld = cur as *mut mailimf_field;
|
||||||
|
|
||||||
|
let fld_to: *mut mailimf_to;
|
||||||
|
let fld_cc: *mut mailimf_cc;
|
||||||
|
|
||||||
|
let mut addr_list: *mut mailimf_address_list = ptr::null_mut();
|
||||||
|
if fld.is_null() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fld = unsafe { *fld };
|
||||||
|
|
||||||
|
// TODO match on enums /rtn
|
||||||
|
match fld.fld_type {
|
||||||
|
13 => {
|
||||||
|
fld_to = unsafe { fld.fld_data.fld_to };
|
||||||
|
if !fld_to.is_null() {
|
||||||
|
addr_list = unsafe { (*fld_to).to_addr_list };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
14 => {
|
||||||
|
fld_cc = unsafe { fld.fld_data.fld_cc };
|
||||||
|
if !fld_cc.is_null() {
|
||||||
|
addr_list = unsafe { (*fld_cc).cc_addr_list };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !addr_list.is_null() {
|
||||||
|
for cur2 in unsafe { &(*(*addr_list).ad_list) } {
|
||||||
|
let adr = cur2 as *mut mailimf_address;
|
||||||
|
|
||||||
|
if adr.is_null() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let adr = unsafe { *adr };
|
||||||
|
|
||||||
|
if adr.ad_type == MAILIMF_ADDRESS_MAILBOX as libc::c_int {
|
||||||
|
mailimf_get_recipients_add_addr(&mut recipients, unsafe {
|
||||||
|
adr.ad_data.ad_mailbox
|
||||||
|
});
|
||||||
|
} else if adr.ad_type == MAILIMF_ADDRESS_GROUP as libc::c_int {
|
||||||
|
let group = unsafe { adr.ad_data.ad_group };
|
||||||
|
if !group.is_null() && unsafe { !(*group).grp_mb_list.is_null() } {
|
||||||
|
for cur3 in unsafe { &(*(*(*group).grp_mb_list).mb_list) } {
|
||||||
|
mailimf_get_recipients_add_addr(
|
||||||
|
&mut recipients,
|
||||||
|
cur3 as *mut mailimf_mailbox,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recipients
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mailmime_transfer_decode(mime: *mut Mailmime) -> Result<Vec<u8>, Error> {
|
||||||
|
ensure!(!mime.is_null(), "invalid inputs");
|
||||||
|
|
||||||
|
let mime_transfer_encoding =
|
||||||
|
get_mime_transfer_encoding(mime).unwrap_or(MAILMIME_MECHANISM_BINARY as i32);
|
||||||
|
|
||||||
|
let mime_data = unsafe { (*mime).mm_data.mm_single };
|
||||||
|
|
||||||
|
decode_dt_data(mime_data, mime_transfer_encoding)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_mime_transfer_encoding(mime: *mut Mailmime) -> Option<libc::c_int> {
|
pub fn get_mime_transfer_encoding(mime: *mut Mailmime) -> Option<libc::c_int> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mm_mime_fields = (*mime).mm_mime_fields;
|
let mm_mime_fields = (*mime).mm_mime_fields;
|
||||||
@@ -131,29 +319,30 @@ pub fn decode_dt_data(
|
|||||||
return Ok(result.to_vec());
|
return Ok(result.to_vec());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { display_mime_data(mime_data) };
|
// unsafe { display_mime_data(mime_data) };
|
||||||
|
|
||||||
let mut current_index = 0;
|
let mut current_index = 0;
|
||||||
let mut transfer_decoding_buffer = ptr::null_mut();
|
let mut transfer_decoding_buffer = ptr::null_mut();
|
||||||
let mut decoded_data_bytes = 0;
|
let mut decoded_data_bytes = 0;
|
||||||
|
|
||||||
let r = unsafe { mailmime_part_parse(
|
let r = unsafe {
|
||||||
(*mime_data).dt_data.dt_text.dt_data,
|
mailmime_part_parse(
|
||||||
(*mime_data).dt_data.dt_text.dt_length,
|
(*mime_data).dt_data.dt_text.dt_data,
|
||||||
&mut current_index,
|
(*mime_data).dt_data.dt_text.dt_length,
|
||||||
mime_transfer_encoding,
|
&mut current_index,
|
||||||
&mut transfer_decoding_buffer,
|
mime_transfer_encoding,
|
||||||
&mut decoded_data_bytes,
|
&mut transfer_decoding_buffer,
|
||||||
) };
|
&mut decoded_data_bytes,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
if r == MAILIMF_NO_ERROR as libc::c_int
|
if r == MAILIMF_NO_ERROR as libc::c_int
|
||||||
&& !transfer_decoding_buffer.is_null()
|
&& !transfer_decoding_buffer.is_null()
|
||||||
&& decoded_data_bytes > 0
|
&& decoded_data_bytes > 0
|
||||||
{
|
{
|
||||||
let result = unsafe { std::slice::from_raw_parts(
|
let result = unsafe {
|
||||||
transfer_decoding_buffer as *const u8,
|
std::slice::from_raw_parts(transfer_decoding_buffer as *const u8, decoded_data_bytes)
|
||||||
decoded_data_bytes,
|
}
|
||||||
) }
|
|
||||||
.to_vec();
|
.to_vec();
|
||||||
// we return a fresh vec and transfer_decoding_buffer is not used or passed anywhere
|
// we return a fresh vec and transfer_decoding_buffer is not used or passed anywhere
|
||||||
// so it's safe to free it right away, as mailman_part_parse has
|
// so it's safe to free it right away, as mailman_part_parse has
|
||||||
@@ -166,6 +355,22 @@ pub fn decode_dt_data(
|
|||||||
Err(format_err!("Failed to to decode"))
|
Err(format_err!("Failed to to decode"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mailimf_find_first_addr(mb_list: *const mailimf_mailbox_list) -> Option<String> {
|
||||||
|
if mb_list.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
for cur in unsafe { (*(*mb_list).mb_list).into_iter() } {
|
||||||
|
let mb = cur as *mut mailimf_mailbox;
|
||||||
|
if !mb.is_null() && !unsafe { (*mb).mb_addr_spec.is_null() } {
|
||||||
|
let addr = unsafe { as_str((*mb).mb_addr_spec) };
|
||||||
|
return Some(addr_normalize(addr).to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************
|
/**************************************
|
||||||
* mime creation API
|
* mime creation API
|
||||||
**************************************/
|
**************************************/
|
||||||
|
|||||||
Reference in New Issue
Block a user