mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
Compare commits
3 Commits
d6dacdcd27
...
mime_decod
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc88c53607 | ||
|
|
fdd21edf0b | ||
|
|
15fdef4464 |
@@ -123,7 +123,7 @@ unsafe fn display_mime_discrete_type(mut discrete_type: *mut mailmime_discrete_t
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_data(mut data: *mut mailmime_data) {
|
||||
pub unsafe fn display_mime_data(mut data: *mut mailmime_data) {
|
||||
match (*data).dt_type {
|
||||
0 => {
|
||||
println!(
|
||||
|
||||
@@ -11,7 +11,6 @@ use mmime::mailmime::content::*;
|
||||
use mmime::mailmime::disposition::*;
|
||||
use mmime::mailmime::types::*;
|
||||
use mmime::mailmime::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
|
||||
use crate::constants::Viewtype;
|
||||
@@ -25,6 +24,7 @@ use crate::error::Error;
|
||||
use crate::location;
|
||||
use crate::param::*;
|
||||
use crate::stock::StockMessage;
|
||||
use crate::wrapmime;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MimeParser<'a> {
|
||||
@@ -287,12 +287,12 @@ impl<'a> MimeParser<'a> {
|
||||
) == MAILIMF_NO_ERROR as libc::c_int
|
||||
&& !mb_list.is_null()
|
||||
{
|
||||
if let Some(dn_to_addr) = mailimf_find_first_addr(mb_list) {
|
||||
if let Some(dn_to_addr) = wrapmime::mailimf_find_first_addr(mb_list) {
|
||||
if let Some(from_field) = self.lookup_field("From") {
|
||||
if (*from_field).fld_type == MAILIMF_FIELD_FROM as libc::c_int
|
||||
&& !(*from_field).fld_data.fld_from.is_null()
|
||||
{
|
||||
let from_addr = mailimf_find_first_addr(
|
||||
let from_addr = wrapmime::mailimf_find_first_addr(
|
||||
(*(*from_field).fld_data.fld_from).frm_mb_list,
|
||||
);
|
||||
if let Some(from_addr) = from_addr {
|
||||
@@ -590,7 +590,7 @@ impl<'a> MimeParser<'a> {
|
||||
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,
|
||||
Err(_) => {
|
||||
// Note that it's now always an error - might be no data
|
||||
@@ -832,7 +832,7 @@ impl<'a> MimeParser<'a> {
|
||||
let mut fld_from: *const mailimf_from = ptr::null();
|
||||
|
||||
/* get From: and check there is exactly one sender */
|
||||
let fld = mailimf_find_field(self.header_root, MAILIMF_FIELD_FROM as libc::c_int);
|
||||
let fld = wrapmime::mailimf_find_field(self.header_root, MAILIMF_FIELD_FROM as libc::c_int);
|
||||
if !(fld.is_null()
|
||||
|| {
|
||||
fld_from = (*fld).fld_data.fld_from;
|
||||
@@ -850,7 +850,7 @@ impl<'a> MimeParser<'a> {
|
||||
|
||||
if !mb.is_null() {
|
||||
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.contains(from_addr_norm) {
|
||||
sender_equals_recipient = true;
|
||||
@@ -911,22 +911,6 @@ pub struct Part {
|
||||
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) {
|
||||
if in_0.is_null() {
|
||||
return;
|
||||
@@ -1148,214 +1132,6 @@ pub unsafe fn mailmime_find_ct_parameter(
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_transfer_decode(mime: *mut Mailmime) -> Result<Vec<u8>, Error> {
|
||||
ensure!(!mime.is_null(), "invalid inputs");
|
||||
|
||||
let mut mime_transfer_encoding = MAILMIME_MECHANISM_BINARY as libc::c_int;
|
||||
|
||||
let mime_data = (*mime).mm_data.mm_single;
|
||||
if !(*mime).mm_mime_fields.is_null() {
|
||||
for cur in (*(*(*mime).mm_mime_fields).fld_list).into_iter() {
|
||||
let field = cur as *mut mailmime_field;
|
||||
|
||||
if !field.is_null()
|
||||
&& (*field).fld_type == MAILMIME_FIELD_TRANSFER_ENCODING as libc::c_int
|
||||
&& !(*field).fld_data.fld_encoding.is_null()
|
||||
{
|
||||
mime_transfer_encoding = (*(*field).fld_data.fld_encoding).enc_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
let decoded_data = (*mime_data).dt_data.dt_text.dt_data;
|
||||
let decoded_data_bytes = (*mime_data).dt_data.dt_text.dt_length;
|
||||
|
||||
if decoded_data.is_null() || decoded_data_bytes <= 0 {
|
||||
bail!("No data to decode found");
|
||||
} else {
|
||||
let result = std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes);
|
||||
return Ok(result.to_vec());
|
||||
}
|
||||
}
|
||||
|
||||
let mut current_index = 0;
|
||||
let mut transfer_decoding_buffer = ptr::null_mut();
|
||||
let mut decoded_data_bytes = 0;
|
||||
|
||||
let r = mailmime_part_parse(
|
||||
(*mime_data).dt_data.dt_text.dt_data,
|
||||
(*mime_data).dt_data.dt_text.dt_length,
|
||||
&mut current_index,
|
||||
mime_transfer_encoding,
|
||||
&mut transfer_decoding_buffer,
|
||||
&mut decoded_data_bytes,
|
||||
);
|
||||
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int
|
||||
&& !transfer_decoding_buffer.is_null()
|
||||
&& decoded_data_bytes > 0
|
||||
{
|
||||
let result =
|
||||
std::slice::from_raw_parts(transfer_decoding_buffer as *const u8, decoded_data_bytes)
|
||||
.to_vec();
|
||||
mmap_string_unref(transfer_decoding_buffer);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
Err(format_err!("Failed to to decode"))
|
||||
}
|
||||
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -1371,14 +1147,13 @@ mod tests {
|
||||
let mut mime: *mut Mailmime = ptr::null_mut();
|
||||
let mut dummy = 0;
|
||||
let res = mailmime_parse(txt, strlen(txt), &mut dummy, &mut mime);
|
||||
|
||||
assert_eq!(res, MAIL_NO_ERROR as libc::c_int);
|
||||
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());
|
||||
|
||||
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,
|
||||
b"fielda\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
@@ -1398,7 +1173,7 @@ mod tests {
|
||||
"ValueA",
|
||||
);
|
||||
|
||||
of_a = mailimf_find_optional_field(
|
||||
of_a = wrapmime::mailimf_find_optional_field(
|
||||
fields,
|
||||
b"FIELDA\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
@@ -1418,7 +1193,7 @@ mod tests {
|
||||
"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,
|
||||
b"FieldB\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
@@ -1441,7 +1216,9 @@ mod tests {
|
||||
let context = dummy_context();
|
||||
let raw = include_bytes!("../test-data/message/issue_523.txt");
|
||||
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.parts.len(), 1);
|
||||
}
|
||||
@@ -1449,9 +1226,13 @@ mod tests {
|
||||
proptest! {
|
||||
#[test]
|
||||
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 mut mimeparser = MimeParser::new(&context.ctx);
|
||||
unsafe { mimeparser.parse(data.as_bytes()).unwrap() };
|
||||
unsafe {
|
||||
assert!(mimeparser.parse(data.as_bytes()).is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1480,7 +1261,7 @@ mod tests {
|
||||
fn test_mimeparser_with_context() {
|
||||
unsafe {
|
||||
let context = dummy_context();
|
||||
let raw = b"Content-Type: multipart/mixed; boundary=\"==break==\";\nSubject: outer-subject\nX-Special-A: special-a\nFoo: Bar\nChat-Version: 0.0\n\n--==break==\nContent-Type: text/plain; protected-headers=\"v1\";\nSubject: inner-subject\nX-Special-B: special-b\nFoo: Xy\nChat-Version: 1.0\n\ntest1\n\n--==break==--\n\n\x00";
|
||||
let 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);
|
||||
mimeparser.parse(&raw[..]).unwrap();
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ use crate::peerstate::*;
|
||||
use crate::securejoin::handle_securejoin_handshake;
|
||||
use crate::sql;
|
||||
use crate::stock::StockMessage;
|
||||
use crate::wrapmime;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum CreateEvent {
|
||||
@@ -795,7 +796,7 @@ unsafe fn handle_reports(
|
||||
b"disposition-notification\x00" as *const u8 as *const libc::c_char,
|
||||
) == 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 dummy = 0;
|
||||
|
||||
@@ -807,13 +808,14 @@ unsafe fn handle_reports(
|
||||
) == MAIL_NO_ERROR as libc::c_int
|
||||
&& !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() {
|
||||
let of_disposition = mailimf_find_optional_field(
|
||||
let of_disposition = wrapmime::mailimf_find_optional_field(
|
||||
report_fields,
|
||||
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,
|
||||
b"Original-Message-ID\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
|
||||
168
src/e2ee.rs
168
src/e2ee.rs
@@ -22,7 +22,6 @@ use num_traits::FromPrimitive;
|
||||
use crate::aheader::*;
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::dc_mimeparser::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::*;
|
||||
use crate::key::*;
|
||||
@@ -266,103 +265,80 @@ pub fn try_decrypt(
|
||||
context: &Context,
|
||||
in_out_message: *mut Mailmime,
|
||||
) -> 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 signatures = HashSet::default();
|
||||
let mut gossipped_addr = HashSet::default();
|
||||
|
||||
// just a pointer into mailmime structure, must not be freed
|
||||
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();
|
||||
let self_addr = context.get_config(Config::ConfiguredAddr);
|
||||
|
||||
// XXX do wrapmime:: helper for the next block
|
||||
if !(in_out_message.is_null() || imffields.is_null()) {
|
||||
let mut 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 };
|
||||
from = mailimf_find_first_addr(mb_list);
|
||||
}
|
||||
|
||||
field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int);
|
||||
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()
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 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)?;
|
||||
}
|
||||
let mut gossip_headers = ptr::null_mut();
|
||||
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)?;
|
||||
unsafe { mailimf_fields_free(gossip_headers) };
|
||||
}
|
||||
}
|
||||
}
|
||||
if !gossip_headers.is_null() {
|
||||
unsafe { mailimf_fields_free(gossip_headers) };
|
||||
}
|
||||
|
||||
Ok((encrypted, signatures, gossipped_addr))
|
||||
}
|
||||
|
||||
@@ -600,22 +576,16 @@ fn decrypt_part(
|
||||
mime_transfer_encoding = enc;
|
||||
}
|
||||
|
||||
let (decoded_data, decoded_data_bytes) =
|
||||
wrapmime::decode_dt_data(mime_data, mime_transfer_encoding)?;
|
||||
let data: Vec<u8> = 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,
|
||||
// after encryption has been attempted.
|
||||
let mut ret_decrypted_mime = ptr::null_mut();
|
||||
|
||||
ensure!(!decoded_data.is_null(), "Missing data");
|
||||
let data = unsafe { std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes) };
|
||||
if has_decrypted_pgp_armor(data) {
|
||||
if has_decrypted_pgp_armor(&data) {
|
||||
// we should only have one decryption happening
|
||||
ensure!(ret_valid_signatures.is_empty(), "corrupt signatures");
|
||||
|
||||
let plain = match dc_pgp_pk_decrypt(
|
||||
data,
|
||||
&data,
|
||||
&private_keyring,
|
||||
&public_keyring_for_validate,
|
||||
Some(ret_valid_signatures),
|
||||
@@ -624,10 +594,7 @@ fn decrypt_part(
|
||||
ensure!(!ret_valid_signatures.is_empty(), "no valid signatures");
|
||||
plain
|
||||
}
|
||||
Err(err) => {
|
||||
unsafe { mmap_string_unref(decoded_data) };
|
||||
bail!("could not decrypt: {}", err)
|
||||
}
|
||||
Err(err) => bail!("could not decrypt: {}", err),
|
||||
};
|
||||
let plain_bytes = plain.len();
|
||||
let plain_buf = plain.as_ptr() as *const libc::c_char;
|
||||
@@ -655,7 +622,6 @@ fn decrypt_part(
|
||||
ret_decrypted_mime = decrypted_mime;
|
||||
}
|
||||
}
|
||||
unsafe { mmap_string_unref(decoded_data) };
|
||||
|
||||
Ok(ret_decrypted_mime)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::chat::{self, Chat};
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
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_tools::*;
|
||||
use crate::e2ee::*;
|
||||
@@ -645,7 +645,7 @@ impl<'a> MimeFactory<'a> {
|
||||
);
|
||||
|
||||
/*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!(
|
||||
!imffields_unprotected.is_null(),
|
||||
"could not find mime fields"
|
||||
|
||||
283
src/wrapmime.rs
283
src/wrapmime.rs
@@ -1,9 +1,12 @@
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use crate::contact::addr_normalize;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use mmime::clist::*;
|
||||
// use mmime::display::*;
|
||||
use mmime::mailimf::types::*;
|
||||
use mmime::mailimf::types_helper::*;
|
||||
use mmime::mailmime::content::*;
|
||||
@@ -11,6 +14,7 @@ use mmime::mailmime::disposition::*;
|
||||
use mmime::mailmime::types::*;
|
||||
use mmime::mailmime::types_helper::*;
|
||||
use mmime::mailmime::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
|
||||
#[macro_export]
|
||||
@@ -88,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> {
|
||||
unsafe {
|
||||
let mm_mime_fields = (*mime).mm_mime_fields;
|
||||
@@ -108,48 +298,77 @@ pub fn get_mime_transfer_encoding(mime: *mut Mailmime) -> Option<libc::c_int> {
|
||||
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> {
|
||||
) -> Result<Vec<u8>, 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;
|
||||
let decoded_data = unsafe { (*mime_data).dt_data.dt_text.dt_data };
|
||||
let decoded_data_bytes = unsafe { (*mime_data).dt_data.dt_text.dt_length };
|
||||
|
||||
if decoded_data.is_null() || decoded_data_bytes <= 0 {
|
||||
bail!("No data to decode found");
|
||||
} else {
|
||||
let result = unsafe {
|
||||
std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes)
|
||||
};
|
||||
return Ok(result.to_vec());
|
||||
}
|
||||
}
|
||||
Ok((decoded_data, decoded_data_bytes))
|
||||
// unsafe { display_mime_data(mime_data) };
|
||||
|
||||
let mut current_index = 0;
|
||||
let mut transfer_decoding_buffer = ptr::null_mut();
|
||||
let mut decoded_data_bytes = 0;
|
||||
|
||||
let r = unsafe {
|
||||
mailmime_part_parse(
|
||||
(*mime_data).dt_data.dt_text.dt_data,
|
||||
(*mime_data).dt_data.dt_text.dt_length,
|
||||
&mut current_index,
|
||||
mime_transfer_encoding,
|
||||
&mut transfer_decoding_buffer,
|
||||
&mut decoded_data_bytes,
|
||||
)
|
||||
};
|
||||
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int
|
||||
&& !transfer_decoding_buffer.is_null()
|
||||
&& decoded_data_bytes > 0
|
||||
{
|
||||
let result = unsafe {
|
||||
std::slice::from_raw_parts(transfer_decoding_buffer as *const u8, decoded_data_bytes)
|
||||
}
|
||||
.to_vec();
|
||||
// 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
|
||||
// allocated it fresh.
|
||||
unsafe { mmap_string_unref(transfer_decoding_buffer) };
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/**************************************
|
||||
|
||||
Reference in New Issue
Block a user