Compare commits

..

14 Commits

Author SHA1 Message Date
dignifiedquire
5c6df6dbf6 no more memory corruption 2019-09-29 17:41:04 -06:00
dignifiedquire
416a1751a2 things compile 2019-09-29 09:06:32 -06:00
dignifiedquire
475ad0f93a compile 2019-09-28 23:05:10 -06:00
dignifiedquire
625bc90c30 start refactor of fields 2019-09-28 16:30:22 -06:00
dignifiedquire
347a4d110a refactor(mmime): rustify address_list 2019-09-28 14:51:00 -06:00
dignifiedquire
50ca75398f refactor(mmime): rustify mailbox 2019-09-28 14:42:06 -06:00
dignifiedquire
c18bdc39e5 refactor(mmime): rustify mailbox_list 2019-09-28 14:35:33 -06:00
dignifiedquire
8aa1a0cb3a refactor(mmime): rustify mailimf_group 2019-09-28 14:15:55 -06:00
dignifiedquire
c78753e8fa refactor(mmime): rustify mailimf_data_time 2019-09-28 14:09:53 -06:00
dignifiedquire
2abfd037ca refactor(mmime): rustify mailmime_address 2019-09-28 13:31:12 -06:00
Friedel Ziegelmayer
34b3ddf63b refactor(e2ee): reduce unsafe spread 2019-09-28 13:20:33 -06:00
holger krekel
ca76cac314 address @flub's review comment from https://github.com/deltachat/deltachat-core-rust/pull/622 2019-09-28 03:01:52 +02:00
B. Petersen
3a16ad89bd make ffi-string-parameter const
typically, nearly all string-parameters in the ffi should be const.
one of the few exceptions is dc_str_unref() that really modifies the given data.
2019-09-28 02:56:27 +02:00
dignifiedquire
fb9369f333 refactor(imex): almost all unsafe gone here 2019-09-28 02:55:42 +02:00
29 changed files with 2301 additions and 4418 deletions

View File

@@ -1528,9 +1528,17 @@ pub unsafe extern "C" fn dc_imex(
eprintln!("ignoring careless call to dc_imex()");
return;
}
let what = match imex::ImexMode::from_i32(what as i32) {
Some(what) => what,
None => {
eprintln!("ignoring invalid argument {} to dc_imex", what);
return;
}
};
let ffi_context = &*context;
ffi_context
.with_inner(|ctx| dc_imex::dc_imex(ctx, what, as_opt_str(param1)))
.with_inner(|ctx| imex::imex(ctx, what, as_opt_str(param1)))
.ok();
}
@@ -1545,7 +1553,7 @@ pub unsafe extern "C" fn dc_imex_has_backup(
}
let ffi_context = &*context;
ffi_context
.with_inner(|ctx| match dc_imex::dc_imex_has_backup(ctx, as_str(dir)) {
.with_inner(|ctx| match imex::has_backup(ctx, as_str(dir)) {
Ok(res) => res.strdup(),
Err(err) => {
error!(ctx, "dc_imex_has_backup: {}", err);
@@ -1563,7 +1571,7 @@ pub unsafe extern "C" fn dc_initiate_key_transfer(context: *mut dc_context_t) ->
}
let ffi_context = &*context;
ffi_context
.with_inner(|ctx| match dc_imex::dc_initiate_key_transfer(ctx) {
.with_inner(|ctx| match imex::initiate_key_transfer(ctx) {
Ok(res) => res.strdup(),
Err(err) => {
error!(ctx, "dc_initiate_key_transfer(): {}", err);
@@ -1588,15 +1596,15 @@ pub unsafe extern "C" fn dc_continue_key_transfer(
}
let ffi_context = &*context;
ffi_context
.with_inner(|ctx| {
match dc_imex::dc_continue_key_transfer(ctx, msg_id, as_str(setup_code)) {
.with_inner(
|ctx| match imex::continue_key_transfer(ctx, msg_id, as_str(setup_code)) {
Ok(()) => 1,
Err(err) => {
error!(ctx, "dc_continue_key_transfer: {}", err);
0
}
}
})
},
)
.unwrap_or(0)
}

View File

@@ -8,10 +8,10 @@ use deltachat::configure::*;
use deltachat::constants::*;
use deltachat::contact::*;
use deltachat::context::*;
use deltachat::dc_imex::*;
use deltachat::dc_receive_imf::*;
use deltachat::dc_tools::*;
use deltachat::error::Error;
use deltachat::imex::*;
use deltachat::job::*;
use deltachat::location;
use deltachat::lot::LotState;
@@ -102,7 +102,7 @@ fn dc_poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(),
/// Import a file to the database.
/// For testing, import a folder with eml-files, a single eml-file, e-mail plus public key and so on.
/// For normal importing, use dc_imex().
/// For normal importing, use imex().
///
/// @private @memberof Context
/// @param context The context as created by dc_context_new().
@@ -405,7 +405,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
============================================="
),
},
"initiate-key-transfer" => match dc_initiate_key_transfer(context) {
"initiate-key-transfer" => match initiate_key_transfer(context) {
Ok(setup_code) => println!(
"Setup code for the transferred setup message: {}",
setup_code,
@@ -432,28 +432,28 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
!arg1.is_empty() && !arg2.is_empty(),
"Arguments <msg-id> <setup-code> expected"
);
dc_continue_key_transfer(context, arg1.parse()?, &arg2)?;
continue_key_transfer(context, arg1.parse()?, &arg2)?;
}
"has-backup" => {
dc_imex_has_backup(context, blobdir)?;
has_backup(context, blobdir)?;
}
"export-backup" => {
dc_imex(context, 11, Some(blobdir));
imex(context, ImexMode::ExportBackup, Some(blobdir));
}
"import-backup" => {
ensure!(!arg1.is_empty(), "Argument <backup-file> missing.");
dc_imex(context, 12, Some(arg1));
imex(context, ImexMode::ImportBackup, Some(arg1));
}
"export-keys" => {
dc_imex(context, 1, Some(blobdir));
imex(context, ImexMode::ExportSelfKeys, Some(blobdir));
}
"import-keys" => {
dc_imex(context, 2, Some(blobdir));
imex(context, ImexMode::ImportSelfKeys, Some(blobdir));
}
"export-setup" => {
let setup_code = dc_create_setup_code(context);
let setup_code = create_setup_code(context);
let file_name = blobdir.join("autocrypt-setup-message.html");
let file_content = dc_render_setup_file(context, &setup_code)?;
let file_content = render_setup_file(context, &setup_code)?;
std::fs::write(&file_name, file_content)?;
println!(
"Setup message written to: {}\nSetup code: {}",

View File

@@ -50,10 +50,7 @@ pub unsafe fn display_mime(mut mime: *mut Mailmime) {
}
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()
{
if !(*(*mime).mm_data.mm_message.mm_fields).0.is_empty() {
println!("headers begin");
display_fields((*mime).mm_data.mm_message.mm_fields);
println!("headers end");
@@ -207,115 +204,66 @@ unsafe fn display_mime_fields(mut fields: *mut mailmime_fields) {
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,
(*d).day,
(*d).month,
(*d).year,
(*d).hour,
(*d).min,
(*d).sec,
(*d).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()
);
if !(*mb).display_name.is_null() {
print!("{}", CStr::from_ptr((*mb).display_name).to_str().unwrap());
}
print!("<{}>", CStr::from_ptr((*mb).mb_addr_spec).to_str().unwrap());
print!("<{}>", CStr::from_ptr((*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()
{
for (i, mb) in (*mb_list).0.iter().enumerate() {
display_mailbox(*mb);
if i < (*mb_list).0.len() - 1 {
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()
CStr::from_ptr((*group).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
}
for mb in &(*(*group).mb_list).0 {
display_mailbox(*mb);
}
print!("; ");
}
unsafe fn display_address(mut a: *mut mailimf_address) {
match (*a).ad_type {
2 => {
display_group((*a).ad_data.ad_group);
unsafe fn display_address(a: *mut mailimf_address) {
match *a {
mailimf_address::Group(data) => {
display_group(data);
}
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
mailimf_address::Mailbox(data) => {
display_mailbox(data);
}
}
}
unsafe fn display_address_list(addr_list: *mut mailimf_address_list) {
for (i, addr) in (*addr_list).0.iter().enumerate() {
display_address(*addr);
if i < (*addr_list).0.len() - 1 {
print!(", ");
}
}
}
unsafe fn display_from(mut from: *mut mailimf_from) {
display_mailbox_list((*from).frm_mb_list);
}
@@ -328,59 +276,44 @@ unsafe fn display_cc(mut cc: *mut mailimf_cc) {
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 => {
unsafe fn display_field(field: &mailimf_field) {
match *field {
mailimf_field::OrigDate(date) => {
print!("Date: ");
display_orig_date((*field).fld_data.fld_orig_date);
display_orig_date(date);
println!("");
}
10 => {
mailimf_field::From(from) => {
print!("From: ");
display_from((*field).fld_data.fld_from);
display_from(from);
println!("");
}
13 => {
mailimf_field::To(to) => {
print!("To: ");
display_to((*field).fld_data.fld_to);
display_to(to);
println!("");
}
14 => {
mailimf_field::Cc(cc) => {
print!("Cc: ");
display_cc((*field).fld_data.fld_cc);
display_cc(cc);
println!("");
}
19 => {
mailimf_field::Subject(subject) => {
print!("Subject: ");
display_subject((*field).fld_data.fld_subject);
display_subject(subject);
println!("");
}
16 => {
mailimf_field::MessageId(message_id) => {
println!(
"Message-ID: {}",
CStr::from_ptr((*(*field).fld_data.fld_message_id).mid_value)
.to_str()
.unwrap(),
CStr::from_ptr((*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;
unsafe fn display_fields(fields: *mut mailimf_fields) {
for f in &(*fields).0 {
display_field(f);
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,43 +1,20 @@
use crate::clist::*;
use crate::mailimf::types::*;
use crate::other::*;
/*
this function creates a new mailimf_fields structure with no fields
*/
pub unsafe fn mailimf_fields_new_empty() -> *mut mailimf_fields {
let mut list: *mut clist = 0 as *mut clist;
let mut fields_list: *mut mailimf_fields = 0 as *mut mailimf_fields;
list = clist_new();
if list.is_null() {
return 0 as *mut mailimf_fields;
}
fields_list = mailimf_fields_new(list);
if fields_list.is_null() {
return 0 as *mut mailimf_fields;
}
return fields_list;
mailimf_fields_new(Vec::new())
}
/*
this function adds a field to the mailimf_fields structure
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
pub unsafe fn mailimf_fields_add(
mut fields: *mut mailimf_fields,
mut field: *mut mailimf_field,
) -> libc::c_int {
let mut r: libc::c_int = 0;
r = clist_insert_after(
(*fields).fld_list,
(*(*fields).fld_list).last,
field as *mut libc::c_void,
);
if r < 0i32 {
return MAILIMF_ERROR_MEMORY as libc::c_int;
}
return MAILIMF_NO_ERROR as libc::c_int;
pub unsafe fn mailimf_fields_add(fields: *mut mailimf_fields, field: mailimf_field) {
(*fields).0.push(field)
}
/*
@@ -47,43 +24,11 @@ pub unsafe fn mailimf_fields_add(
@param value should be allocated with malloc()
*/
pub unsafe fn mailimf_field_new_custom(
mut name: *mut libc::c_char,
mut value: *mut libc::c_char,
) -> *mut mailimf_field {
let mut opt_field: *mut mailimf_optional_field = 0 as *mut mailimf_optional_field;
let mut field: *mut mailimf_field = 0 as *mut mailimf_field;
opt_field = mailimf_optional_field_new(name, value);
if !opt_field.is_null() {
field = mailimf_field_new(
MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int,
0 as *mut mailimf_return,
0 as *mut mailimf_orig_date,
0 as *mut mailimf_from,
0 as *mut mailimf_sender,
0 as *mut mailimf_to,
0 as *mut mailimf_cc,
0 as *mut mailimf_bcc,
0 as *mut mailimf_message_id,
0 as *mut mailimf_orig_date,
0 as *mut mailimf_from,
0 as *mut mailimf_sender,
0 as *mut mailimf_reply_to,
0 as *mut mailimf_to,
0 as *mut mailimf_cc,
0 as *mut mailimf_bcc,
0 as *mut mailimf_message_id,
0 as *mut mailimf_in_reply_to,
0 as *mut mailimf_references,
0 as *mut mailimf_subject,
0 as *mut mailimf_comments,
0 as *mut mailimf_keywords,
opt_field,
);
if field.is_null() {
mailimf_optional_field_free(opt_field);
} else {
return field;
}
}
return 0 as *mut mailimf_field;
name: *mut libc::c_char,
value: *mut libc::c_char,
) -> mailimf_field {
let opt_field = mailimf_optional_field_new(name, value);
assert!(!opt_field.is_null(), "failed memory allocation");
mailimf_field::OptionalField(opt_field)
}

View File

@@ -166,35 +166,19 @@ pub unsafe fn mailimf_fields_write_driver(
mut do_write: Option<
unsafe fn(_: *mut libc::c_void, _: *const libc::c_char, _: size_t) -> libc::c_int,
>,
mut data: *mut libc::c_void,
mut col: *mut libc::c_int,
mut fields: *mut mailimf_fields,
data: *mut libc::c_void,
col: *mut libc::c_int,
fields: *mut mailimf_fields,
) -> libc::c_int {
let mut cur: *mut clistiter = 0 as *mut clistiter;
cur = (*(*fields).fld_list).first;
while !cur.is_null() {
let mut r: libc::c_int = 0;
r = mailimf_field_write_driver(
do_write,
data,
col,
(if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailimf_field,
);
for cur in &(*fields).0 {
let r = mailimf_field_write_driver(do_write, data, col, cur);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
return MAILIMF_NO_ERROR as libc::c_int;
MAILIMF_NO_ERROR as libc::c_int
}
/*
mailimf_field_write writes a field to a given stream
@@ -207,118 +191,38 @@ pub unsafe fn mailimf_field_write_driver(
mut do_write: Option<
unsafe fn(_: *mut libc::c_void, _: *const libc::c_char, _: size_t) -> libc::c_int,
>,
mut data: *mut libc::c_void,
mut col: *mut libc::c_int,
mut field: *mut mailimf_field,
data: *mut libc::c_void,
col: *mut libc::c_int,
field: &mailimf_field,
) -> libc::c_int {
let mut r: libc::c_int = 0;
match (*field).fld_type {
1 => {
r = mailimf_return_write_driver(do_write, data, col, (*field).fld_data.fld_return_path)
}
2 => {
r = mailimf_resent_date_write_driver(
do_write,
data,
col,
(*field).fld_data.fld_resent_date,
)
}
3 => {
r = mailimf_resent_from_write_driver(
do_write,
data,
col,
(*field).fld_data.fld_resent_from,
)
}
4 => {
r = mailimf_resent_sender_write_driver(
do_write,
data,
col,
(*field).fld_data.fld_resent_sender,
)
}
5 => {
r = mailimf_resent_to_write_driver(do_write, data, col, (*field).fld_data.fld_resent_to)
}
6 => {
r = mailimf_resent_cc_write_driver(do_write, data, col, (*field).fld_data.fld_resent_cc)
}
7 => {
r = mailimf_resent_bcc_write_driver(
do_write,
data,
col,
(*field).fld_data.fld_resent_bcc,
)
}
8 => {
r = mailimf_resent_msg_id_write_driver(
do_write,
data,
col,
(*field).fld_data.fld_resent_msg_id,
)
}
9 => {
r = mailimf_orig_date_write_driver(do_write, data, col, (*field).fld_data.fld_orig_date)
}
10 => r = mailimf_from_write_driver(do_write, data, col, (*field).fld_data.fld_from),
11 => r = mailimf_sender_write_driver(do_write, data, col, (*field).fld_data.fld_sender),
12 => {
r = mailimf_reply_to_write_driver(do_write, data, col, (*field).fld_data.fld_reply_to)
}
13 => r = mailimf_to_write_driver(do_write, data, col, (*field).fld_data.fld_to),
14 => r = mailimf_cc_write_driver(do_write, data, col, (*field).fld_data.fld_cc),
15 => r = mailimf_bcc_write_driver(do_write, data, col, (*field).fld_data.fld_bcc),
16 => {
r = mailimf_message_id_write_driver(
do_write,
data,
col,
(*field).fld_data.fld_message_id,
)
}
17 => {
r = mailimf_in_reply_to_write_driver(
do_write,
data,
col,
(*field).fld_data.fld_in_reply_to,
)
}
18 => {
r = mailimf_references_write_driver(
do_write,
data,
col,
(*field).fld_data.fld_references,
)
}
19 => r = mailimf_subject_write_driver(do_write, data, col, (*field).fld_data.fld_subject),
20 => {
r = mailimf_comments_write_driver(do_write, data, col, (*field).fld_data.fld_comments)
}
21 => {
r = mailimf_keywords_write_driver(do_write, data, col, (*field).fld_data.fld_keywords)
}
22 => {
r = mailimf_optional_field_write_driver(
do_write,
data,
col,
(*field).fld_data.fld_optional_field,
)
}
_ => r = MAILIMF_ERROR_INVAL as libc::c_int,
use mailimf_field::*;
match field {
ReturnPath(path) => mailimf_return_write_driver(do_write, data, col, *path),
ResentDate(date) => mailimf_resent_date_write_driver(do_write, data, col, *date),
ResentFrom(from) => mailimf_resent_from_write_driver(do_write, data, col, *from),
ResentSender(sender) => mailimf_resent_sender_write_driver(do_write, data, col, *sender),
ResentTo(to) => mailimf_resent_to_write_driver(do_write, data, col, *to),
ResentCc(cc) => mailimf_resent_cc_write_driver(do_write, data, col, *cc),
ResentBcc(bcc) => mailimf_resent_bcc_write_driver(do_write, data, col, *bcc),
ResentMsgId(id) => mailimf_resent_msg_id_write_driver(do_write, data, col, *id),
OrigDate(date) => mailimf_orig_date_write_driver(do_write, data, col, *date),
From(from) => mailimf_from_write_driver(do_write, data, col, *from),
Sender(sender) => mailimf_sender_write_driver(do_write, data, col, *sender),
ReplyTo(to) => mailimf_reply_to_write_driver(do_write, data, col, *to),
To(to) => mailimf_to_write_driver(do_write, data, col, *to),
Cc(cc) => mailimf_cc_write_driver(do_write, data, col, *cc),
Bcc(bcc) => mailimf_bcc_write_driver(do_write, data, col, *bcc),
MessageId(id) => mailimf_message_id_write_driver(do_write, data, col, *id),
InReplyTo(to) => mailimf_in_reply_to_write_driver(do_write, data, col, *to),
References(refs) => mailimf_references_write_driver(do_write, data, col, *refs),
Subject(s) => mailimf_subject_write_driver(do_write, data, col, *s),
Comments(c) => mailimf_comments_write_driver(do_write, data, col, *c),
Keywords(k) => mailimf_keywords_write_driver(do_write, data, col, *k),
OptionalField(f) => mailimf_optional_field_write_driver(do_write, data, col, *f),
}
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
return MAILIMF_NO_ERROR as libc::c_int;
}
unsafe fn mailimf_optional_field_write_driver(
mut do_write: Option<
unsafe fn(_: *mut libc::c_void, _: *const libc::c_char, _: size_t) -> libc::c_int,
@@ -328,16 +232,10 @@ unsafe fn mailimf_optional_field_write_driver(
mut field: *mut mailimf_optional_field,
) -> libc::c_int {
let mut r: libc::c_int = 0;
if strlen((*field).fld_name).wrapping_add(2i32 as libc::size_t) > 998i32 as libc::size_t {
if strlen((*field).name).wrapping_add(2i32 as libc::size_t) > 998i32 as libc::size_t {
return MAILIMF_ERROR_INVAL as libc::c_int;
}
r = mailimf_string_write_driver(
do_write,
data,
col,
(*field).fld_name,
strlen((*field).fld_name),
);
r = mailimf_string_write_driver(do_write, data, col, (*field).name, strlen((*field).name));
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
@@ -355,8 +253,8 @@ unsafe fn mailimf_optional_field_write_driver(
do_write,
data,
col,
(*field).fld_value,
strlen((*field).fld_value),
(*field).value,
strlen((*field).value),
);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
@@ -684,7 +582,7 @@ unsafe fn mailimf_references_write_driver(
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
r = mailimf_msg_id_list_write_driver(do_write, data, col, (*references).mid_list);
r = mailimf_msg_id_list_write_driver(do_write, data, col, &(*references).0);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
@@ -701,28 +599,19 @@ unsafe fn mailimf_references_write_driver(
return MAILIMF_NO_ERROR as libc::c_int;
}
unsafe fn mailimf_msg_id_list_write_driver(
mut do_write: Option<
do_write: Option<
unsafe fn(_: *mut libc::c_void, _: *const libc::c_char, _: size_t) -> libc::c_int,
>,
mut data: *mut libc::c_void,
mut col: *mut libc::c_int,
mut mid_list: *mut clist,
data: *mut libc::c_void,
col: *mut libc::c_int,
mid_list: &Vec<*mut libc::c_char>,
) -> libc::c_int {
let mut cur: *mut clistiter = 0 as *mut clistiter;
let mut r: libc::c_int = 0;
let mut first: libc::c_int = 0;
first = 1i32;
cur = (*mid_list).first;
while !cur.is_null() {
let mut msgid: *mut libc::c_char = 0 as *mut libc::c_char;
let mut len: size_t = 0;
msgid = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut libc::c_char;
len = strlen(msgid);
if 0 == first {
let mut r = 0;
let mut first = true;
for msgid in mid_list {
let len = strlen(*msgid);
if !first {
if *col > 1i32 {
if (*col as libc::size_t).wrapping_add(len) >= 72i32 as libc::size_t {
r = mailimf_string_write_driver(
@@ -735,11 +624,11 @@ unsafe fn mailimf_msg_id_list_write_driver(
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
first = 1i32
first = true;
}
}
}
if 0 == first {
if !first {
r = mailimf_string_write_driver(
do_write,
data,
@@ -751,7 +640,7 @@ unsafe fn mailimf_msg_id_list_write_driver(
return r;
}
} else {
first = 0i32
first = false;
}
r = mailimf_string_write_driver(
do_write,
@@ -763,7 +652,7 @@ unsafe fn mailimf_msg_id_list_write_driver(
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
r = mailimf_string_write_driver(do_write, data, col, msgid, len);
r = mailimf_string_write_driver(do_write, data, col, *msgid, len);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
@@ -777,14 +666,11 @@ unsafe fn mailimf_msg_id_list_write_driver(
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
return MAILIMF_NO_ERROR as libc::c_int;
MAILIMF_NO_ERROR as libc::c_int
}
unsafe fn mailimf_in_reply_to_write_driver(
mut do_write: Option<
unsafe fn(_: *mut libc::c_void, _: *const libc::c_char, _: size_t) -> libc::c_int,
@@ -804,7 +690,7 @@ unsafe fn mailimf_in_reply_to_write_driver(
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
r = mailimf_msg_id_list_write_driver(do_write, data, col, (*in_reply_to).mid_list);
r = mailimf_msg_id_list_write_driver(do_write, data, col, &(*in_reply_to).0);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
@@ -930,14 +816,8 @@ pub unsafe fn mailimf_address_list_write_driver(
let mut r: libc::c_int = 0;
let mut first: libc::c_int = 0;
first = 1i32;
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;
for addr in &(*addr_list).0 {
if 0 == first {
r = mailimf_string_write_driver(
do_write,
@@ -952,18 +832,14 @@ pub unsafe fn mailimf_address_list_write_driver(
} else {
first = 0i32
}
r = mailimf_address_write_driver(do_write, data, col, addr);
r = mailimf_address_write_driver(do_write, data, col, *addr);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
return MAILIMF_NO_ERROR as libc::c_int;
MAILIMF_NO_ERROR as libc::c_int
}
unsafe fn mailimf_address_write_driver(
mut do_write: Option<
unsafe fn(_: *mut libc::c_void, _: *const libc::c_char, _: size_t) -> libc::c_int,
@@ -972,24 +848,24 @@ unsafe fn mailimf_address_write_driver(
mut col: *mut libc::c_int,
mut addr: *mut mailimf_address,
) -> libc::c_int {
let mut r: libc::c_int = 0;
match (*addr).ad_type {
1 => {
r = mailimf_mailbox_write_driver(do_write, data, col, (*addr).ad_data.ad_mailbox);
match *addr {
mailimf_address::Mailbox(mb_data) => {
let r = mailimf_mailbox_write_driver(do_write, data, col, mb_data);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
}
2 => {
r = mailimf_group_write_driver(do_write, data, col, (*addr).ad_data.ad_group);
mailimf_address::Group(gr_data) => {
let r = mailimf_group_write_driver(do_write, data, col, gr_data);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
}
_ => {}
}
return MAILIMF_NO_ERROR as libc::c_int;
MAILIMF_NO_ERROR as libc::c_int
}
unsafe fn mailimf_group_write_driver(
mut do_write: Option<
unsafe fn(_: *mut libc::c_void, _: *const libc::c_char, _: size_t) -> libc::c_int,
@@ -1003,8 +879,8 @@ unsafe fn mailimf_group_write_driver(
do_write,
data,
col,
(*group).grp_display_name,
strlen((*group).grp_display_name),
(*group).display_name,
strlen((*group).display_name),
);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
@@ -1019,8 +895,8 @@ unsafe fn mailimf_group_write_driver(
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
if !(*group).grp_mb_list.is_null() {
r = mailimf_mailbox_list_write_driver(do_write, data, col, (*group).grp_mb_list);
if !(*group).mb_list.is_null() {
r = mailimf_mailbox_list_write_driver(do_write, data, col, (*group).mb_list);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
@@ -1050,14 +926,8 @@ pub unsafe fn mailimf_mailbox_list_write_driver(
let mut r: libc::c_int = 0;
let mut first: libc::c_int = 0;
first = 1i32;
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;
for mb in &(*mb_list).0 {
if 0 == first {
r = mailimf_string_write_driver(
do_write,
@@ -1072,18 +942,14 @@ pub unsafe fn mailimf_mailbox_list_write_driver(
} else {
first = 0i32
}
r = mailimf_mailbox_write_driver(do_write, data, col, mb);
r = mailimf_mailbox_write_driver(do_write, data, col, *mb);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
return MAILIMF_NO_ERROR as libc::c_int;
MAILIMF_NO_ERROR as libc::c_int
}
unsafe fn mailimf_mailbox_write_driver(
mut do_write: Option<
unsafe fn(_: *mut libc::c_void, _: *const libc::c_char, _: size_t) -> libc::c_int,
@@ -1094,21 +960,21 @@ unsafe fn mailimf_mailbox_write_driver(
) -> libc::c_int {
let mut r: libc::c_int = 0;
let mut do_fold: libc::c_int = 0;
if !(*mb).mb_display_name.is_null() {
if 0 != is_atext((*mb).mb_display_name) {
if !(*mb).display_name.is_null() {
if 0 != is_atext((*mb).display_name) {
r = mailimf_header_string_write_driver(
do_write,
data,
col,
(*mb).mb_display_name,
strlen((*mb).mb_display_name),
(*mb).display_name,
strlen((*mb).display_name),
);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
}
} else {
if !(*mb).mb_display_name.is_null() {
if (*col as libc::size_t).wrapping_add(strlen((*mb).mb_display_name))
if !(*mb).display_name.is_null() {
if (*col as libc::size_t).wrapping_add(strlen((*mb).display_name))
>= 72i32 as libc::size_t
{
r = mailimf_string_write_driver(
@@ -1123,15 +989,15 @@ unsafe fn mailimf_mailbox_write_driver(
}
}
}
if strlen((*mb).mb_display_name) > (998i32 / 2i32) as libc::size_t {
if strlen((*mb).display_name) > (998i32 / 2i32) as libc::size_t {
return MAILIMF_ERROR_INVAL as libc::c_int;
}
r = mailimf_quoted_string_write_driver(
do_write,
data,
col,
(*mb).mb_display_name,
strlen((*mb).mb_display_name),
(*mb).display_name,
strlen((*mb).display_name),
);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
@@ -1140,7 +1006,7 @@ unsafe fn mailimf_mailbox_write_driver(
do_fold = 0i32;
if *col > 1i32 {
if (*col as libc::size_t)
.wrapping_add(strlen((*mb).mb_addr_spec))
.wrapping_add(strlen((*mb).addr_spec))
.wrapping_add(3i32 as libc::size_t)
>= 72i32 as libc::size_t
{
@@ -1181,8 +1047,8 @@ unsafe fn mailimf_mailbox_write_driver(
do_write,
data,
col,
(*mb).mb_addr_spec,
strlen((*mb).mb_addr_spec),
(*mb).addr_spec,
strlen((*mb).addr_spec),
);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
@@ -1198,8 +1064,7 @@ unsafe fn mailimf_mailbox_write_driver(
return r;
}
} else {
if (*col as libc::size_t).wrapping_add(strlen((*mb).mb_addr_spec)) >= 72i32 as libc::size_t
{
if (*col as libc::size_t).wrapping_add(strlen((*mb).addr_spec)) >= 72i32 as libc::size_t {
r = mailimf_string_write_driver(
do_write,
data,
@@ -1215,8 +1080,8 @@ unsafe fn mailimf_mailbox_write_driver(
do_write,
data,
col,
(*mb).mb_addr_spec,
strlen((*mb).mb_addr_spec),
(*mb).addr_spec,
strlen((*mb).addr_spec),
);
if r != MAILIMF_NO_ERROR as libc::c_int {
return r;
@@ -1581,22 +1446,18 @@ unsafe fn mailimf_date_time_write_driver(
mut col: *mut libc::c_int,
mut date_time: *mut mailimf_date_time,
) -> libc::c_int {
let wday = dayofweek(
(*date_time).dt_year,
(*date_time).dt_month,
(*date_time).dt_day,
);
let wday = dayofweek((*date_time).year, (*date_time).month, (*date_time).day);
let date_str = format!(
"{}, {} {} {} {:02}:{:02}:{:02} {:+05}",
week_of_day_str[wday as usize],
(*date_time).dt_day,
month_str[((*date_time).dt_month - 1i32) as usize],
(*date_time).dt_year,
(*date_time).dt_hour,
(*date_time).dt_min,
(*date_time).dt_sec,
(*date_time).dt_zone,
wday,
(*date_time).day,
month_str[((*date_time).month - 1) as usize],
(*date_time).year,
(*date_time).hour,
(*date_time).min,
(*date_time).sec,
(*date_time).zone,
);
let date_str_c = std::ffi::CString::new(date_str).unwrap();
let r = mailimf_string_write_driver(
@@ -1611,27 +1472,16 @@ unsafe fn mailimf_date_time_write_driver(
}
return MAILIMF_NO_ERROR as libc::c_int;
}
static mut month_str: [&'static str; 12] = [
static mut month_str: [&str; 12] = [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
];
static mut week_of_day_str: [&'static str; 7] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
/* 0 = Sunday */
/* y > 1752 */
unsafe fn dayofweek(
mut year: libc::c_int,
mut month: libc::c_int,
mut day: libc::c_int,
) -> libc::c_int {
static mut offset: [libc::c_int; 12] = [
0i32, 3i32, 2i32, 5i32, 0i32, 3i32, 5i32, 1i32, 4i32, 6i32, 2i32, 4i32,
];
year -= (month < 3i32) as libc::c_int;
return (year + year / 4i32 - year / 100i32
+ year / 400i32
+ offset[(month - 1i32) as usize]
+ day)
% 7i32;
fn dayofweek(year: i32, month: u32, day: u32) -> String {
chrono::NaiveDate::from_ymd(year, month, day)
.format("%a")
.to_string()
}
unsafe fn mailimf_resent_msg_id_write_driver(
mut do_write: Option<
unsafe fn(_: *mut libc::c_void, _: *const libc::c_char, _: size_t) -> libc::c_int,

View File

@@ -1243,30 +1243,21 @@ unsafe fn mailmime_preamble_parse(
*indx = cur_token;
return MAILIMF_NO_ERROR as libc::c_int;
}
unsafe fn remove_unparsed_mime_headers(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 field: *mut mailimf_field = 0 as *mut mailimf_field;
let mut delete: libc::c_int = 0;
field = (if !cur.is_null() {
(*cur).data
} else {
0 as *mut libc::c_void
}) as *mut mailimf_field;
match (*field).fld_type {
22 => {
delete = 0i32;
unsafe fn remove_unparsed_mime_headers(fields: *mut mailimf_fields) {
(*fields).0.retain(|field| {
let mut delete = false;
match field {
mailimf_field::OptionalField(data) => {
delete = false;
if strncasecmp(
(*(*field).fld_data.fld_optional_field).fld_name,
(**data).name,
b"Content-\x00" as *const u8 as *const libc::c_char,
8i32 as libc::size_t,
) == 0i32
{
let mut name: *mut libc::c_char = 0 as *mut libc::c_char;
name = (*(*field).fld_data.fld_optional_field)
.fld_name
.offset(8isize);
name = (**data).name.offset(8isize);
if strcasecmp(name, b"Type\x00" as *const u8 as *const libc::c_char) == 0i32
|| strcasecmp(
name,
@@ -1280,35 +1271,22 @@ unsafe fn remove_unparsed_mime_headers(mut fields: *mut mailimf_fields) {
|| strcasecmp(name, b"Language\x00" as *const u8 as *const libc::c_char)
== 0i32
{
delete = 1i32
delete = true;
}
} else if strcasecmp(
(*(*field).fld_data.fld_optional_field).fld_name,
(**data).name,
b"MIME-Version\x00" as *const u8 as *const libc::c_char,
) == 0i32
{
delete = 1i32
}
if 0 != delete {
cur = clist_delete((*fields).fld_list, cur);
mailimf_field_free(field);
} else {
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
}
_ => {
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
delete = true;
}
}
_ => {}
}
}
// retain keeps everything true
!delete
});
}
pub unsafe fn mailmime_extract_boundary(

View File

@@ -684,8 +684,8 @@ unsafe fn mailmime_mechanism_parse(
}
pub unsafe fn mailmime_field_parse(
mut field: *mut mailimf_optional_field,
mut result: *mut *mut mailmime_field,
field: *mut mailimf_optional_field,
result: *mut *mut mailmime_field,
) -> libc::c_int {
let mut name: *mut libc::c_char = 0 as *mut libc::c_char;
let mut value: *mut libc::c_char = 0 as *mut libc::c_char;
@@ -702,8 +702,8 @@ pub unsafe fn mailmime_field_parse(
let mut location: *mut libc::c_char = 0 as *mut libc::c_char;
let mut res: libc::c_int = 0;
let mut r: libc::c_int = 0;
name = (*field).fld_name;
value = (*field).fld_value;
name = (*field).name;
value = (*field).value;
cur_token = 0i32 as size_t;
content = 0 as *mut mailmime_content;
encoding = 0 as *mut mailmime_mechanism;
@@ -1068,8 +1068,6 @@ pub unsafe fn mailmime_fields_parse(
mut fields: *mut mailimf_fields,
mut result: *mut *mut mailmime_fields,
) -> libc::c_int {
let mut current_block: u64;
let mut cur: *mut clistiter = 0 as *mut clistiter;
let mut mime_fields: *mut mailmime_fields = 0 as *mut mailmime_fields;
let mut list: *mut clist = 0 as *mut clist;
let mut r: libc::c_int = 0;
@@ -1078,58 +1076,27 @@ pub unsafe fn mailmime_fields_parse(
if list.is_null() {
res = MAILIMF_ERROR_MEMORY as libc::c_int
} else {
cur = (*(*fields).fld_list).first;
loop {
if cur.is_null() {
current_block = 1109700713171191020;
break;
}
let mut field: *mut mailimf_field = 0 as *mut mailimf_field;
let mut mime_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 mailimf_field;
if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
r = mailmime_field_parse((*field).fld_data.fld_optional_field, &mut mime_field);
for field in &(*fields).0 {
let mut mime_field = 0 as *mut mailmime_field;
if let mailimf_field::OptionalField(opt_field) = field {
r = mailmime_field_parse(*opt_field, &mut mime_field);
if r == MAILIMF_NO_ERROR as libc::c_int {
r = clist_insert_after(list, (*list).last, mime_field as *mut libc::c_void);
if r < 0i32 {
mailmime_field_free(mime_field);
res = MAILIMF_ERROR_MEMORY as libc::c_int;
current_block = 17592539310030730040;
break;
}
} else if !(r == MAILIMF_ERROR_PARSE as libc::c_int) {
/* do nothing */
res = r;
current_block = 17592539310030730040;
break;
}
}
cur = if !cur.is_null() {
(*cur).next
} else {
0 as *mut clistcell
}
}
match current_block {
1109700713171191020 => {
if (*list).first.is_null() {
res = MAILIMF_ERROR_PARSE as libc::c_int
} else {
mime_fields = mailmime_fields_new(list);
if mime_fields.is_null() {
res = MAILIMF_ERROR_MEMORY as libc::c_int
} else {
*result = mime_fields;
return MAILIMF_NO_ERROR as libc::c_int;
}
}
}
_ => {}
}
clist_foreach(
list,
::std::mem::transmute::<Option<unsafe fn(_: *mut mailmime_field) -> ()>, clist_func>(

View File

@@ -705,7 +705,29 @@ pub unsafe fn mailmime_new(
}
_ => {}
}
return mime;
mime
}
pub unsafe fn mailmime_new_simple(
mut mm_type: libc::c_int,
mut mm_mime_fields: *mut mailmime_fields,
mut mm_content_type: *mut mailmime_content,
mut mm_fields: *mut mailimf_fields,
mut mm_msg_mime: *mut Mailmime,
) -> *mut Mailmime {
mailmime_new(
mm_type,
std::ptr::null(),
0,
mm_mime_fields,
mm_content_type,
std::ptr::null_mut(),
std::ptr::null_mut(),
std::ptr::null_mut(),
std::ptr::null_mut(),
mm_fields,
mm_msg_mime,
)
}
pub unsafe fn mailmime_free(mut mime: *mut Mailmime) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,4 @@
use std::collections::BTreeMap;
use std::ffi::CStr;
use std::str::FromStr;
use std::{fmt, str};
@@ -7,6 +6,7 @@ use mmime::mailimf::types::*;
use crate::constants::*;
use crate::contact::*;
use crate::dc_tools::as_str;
use crate::key::*;
/// Possible values for encryption preference
@@ -69,24 +69,13 @@ impl Aheader {
}
let mut fine_header = None;
let mut cur = unsafe { (*(*header).fld_list).first };
while !cur.is_null() {
let field = unsafe { (*cur).data as *mut mailimf_field };
if !field.is_null()
&& unsafe { (*field).fld_type } == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int
{
let optional_field = unsafe { (*field).fld_data.fld_optional_field };
for field in unsafe { &(*header).0 } {
if let mailimf_field::OptionalField(optional_field) = *field {
if !optional_field.is_null()
&& unsafe { !(*optional_field).fld_name.is_null() }
&& unsafe { CStr::from_ptr((*optional_field).fld_name).to_str().unwrap() }
== "Autocrypt"
&& unsafe { !(*optional_field).name.is_null() }
&& unsafe { as_str((*optional_field).name) } == "Autocrypt"
{
let value = unsafe {
CStr::from_ptr((*optional_field).fld_value)
.to_str()
.unwrap()
};
let value = unsafe { as_str((*optional_field).value) };
match Self::from_str(value) {
Ok(test) => {
@@ -103,8 +92,6 @@ impl Aheader {
}
}
}
cur = unsafe { (*cur).next };
}
fine_header

View File

@@ -64,15 +64,6 @@ pub const DC_GCL_ADD_SELF: usize = 0x02;
pub(crate) const DC_FP_NO_AUTOCRYPT_HEADER: i32 = 2;
pub(crate) const DC_FP_ADD_AUTOCRYPT_HEADER: i32 = 1;
/// param1 is a directory where the keys are written to
pub const DC_IMEX_EXPORT_SELF_KEYS: i32 = 1;
/// param1 is a directory where the keys are searched in and read from
pub const DC_IMEX_IMPORT_SELF_KEYS: i32 = 2;
/// param1 is a directory where the backup is written to
pub const DC_IMEX_EXPORT_BACKUP: i32 = 11;
/// param1 is the file with the backup to import
pub const DC_IMEX_IMPORT_BACKUP: i32 = 12;
/// virtual chat showing all messages belonging to chats flagged with chats.blocked=2
pub(crate) const DC_CHAT_ID_DEADDROP: u32 = 1;
/// messages that should be deleted get this chat_id; the messages are deleted from the working thread later then. This is also needed as rfc724_mid should be preset as long as the message is not deleted on the server (otherwise it is downloaded again)

View File

@@ -5,7 +5,6 @@ use std::ptr;
use charset::Charset;
use deltachat_derive::{FromSql, ToSql};
use libc::{strcmp, strlen, strncmp};
use mmime::clist::*;
use mmime::mailimf::types::*;
use mmime::mailimf::*;
use mmime::mailmime::content::*;
@@ -21,7 +20,7 @@ use crate::context::Context;
use crate::dc_simplify::*;
use crate::dc_strencode::*;
use crate::dc_tools::*;
use crate::e2ee::*;
use crate::e2ee;
use crate::error::Error;
use crate::location;
use crate::param::*;
@@ -32,13 +31,15 @@ pub struct MimeParser<'a> {
pub context: &'a Context,
pub parts: Vec<Part>,
pub mimeroot: *mut Mailmime,
pub header: HashMap<String, *mut mailimf_field>,
pub header: HashMap<String, mailimf_field>,
pub header_root: *mut mailimf_fields,
pub header_protected: *mut mailimf_fields,
pub subject: Option<String>,
pub is_send_by_messenger: bool,
pub decrypting_failed: bool,
pub e2ee_helper: E2eeHelper,
pub encrypted: bool,
pub signatures: HashSet<String>,
pub gossipped_addr: HashSet<String>,
pub is_forwarded: bool,
pub reports: Vec<*mut Mailmime>,
pub is_system_message: SystemMessage,
@@ -92,7 +93,9 @@ impl<'a> MimeParser<'a> {
subject: None,
is_send_by_messenger: false,
decrypting_failed: false,
e2ee_helper: Default::default(),
encrypted: false,
signatures: Default::default(),
gossipped_addr: Default::default(),
is_forwarded: false,
context,
reports: Vec::new(),
@@ -113,12 +116,16 @@ impl<'a> MimeParser<'a> {
);
if r == MAILIMF_NO_ERROR as libc::c_int && !self.mimeroot.is_null() {
self.e2ee_helper.try_decrypt(self.context, self.mimeroot)?;
let (encrypted, signatures, gossipped_addr) =
e2ee::try_decrypt(self.context, self.mimeroot)?;
self.encrypted = encrypted;
self.signatures = signatures;
self.gossipped_addr = gossipped_addr;
self.parse_mime_recursive(self.mimeroot);
if let Some(field) = self.lookup_field("Subject") {
if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
let subj = (*(*field).fld_data.fld_subject).sbj_value;
if let mailimf_field::Subject(subject) = *field {
let subj = (*subject).sbj_value;
self.subject = as_opt_str(subj).map(dc_decode_header_words_safe);
}
@@ -282,12 +289,9 @@ impl<'a> MimeParser<'a> {
{
if let Some(dn_to_addr) = mailimf_find_first_addr(mb_list) {
if let Some(from_field) = self.lookup_field("From") {
if (*from_field).fld_type == MAILIMF_FIELD_FROM as libc::c_int
&& !(*from_field).fld_data.fld_from.is_null()
{
let from_addr = mailimf_find_first_addr(
(*(*from_field).fld_data.fld_from).frm_mb_list,
);
if let mailimf_field::From(from) = *from_field {
let from_addr =
mailimf_find_first_addr((*from).frm_mb_list);
if let Some(from_addr) = from_addr {
if from_addr == dn_to_addr {
if let Some(part_4) = self.get_last_nonmeta() {
@@ -326,44 +330,24 @@ impl<'a> MimeParser<'a> {
/* the following functions can be used only after a call to parse() */
pub fn lookup_field(&self, field_name: &str) -> Option<*mut mailimf_field> {
match self.header.get(field_name) {
Some(v) => {
if v.is_null() {
None
} else {
Some(*v)
}
}
None => None,
}
pub fn lookup_field(&self, field_name: &str) -> Option<&mailimf_field> {
self.header.get(field_name)
}
pub fn lookup_optional_field(&self, field_name: &str) -> Option<String> {
if let Some(field) = self.lookup_field_typ(field_name, MAILIMF_FIELD_OPTIONAL_FIELD) {
let val = unsafe { (*field).fld_data.fld_optional_field };
if val.is_null() {
return None;
} else {
return Some(unsafe { to_string_lossy((*val).fld_value) });
if let Some(field) = self.lookup_field(field_name) {
if let mailimf_field::OptionalField(val) = *field {
if val.is_null() {
return None;
} else {
return Some(unsafe { to_string_lossy((*val).value) });
}
}
}
None
}
pub fn lookup_field_typ(&self, name: &str, typ: u32) -> Option<*const mailimf_field> {
if let Some(field) = self.lookup_field(name) {
if unsafe { (*field).fld_type } == typ as libc::c_int {
Some(field)
} else {
None
}
} else {
None
}
}
unsafe fn parse_mime_recursive(&mut self, mime: *mut Mailmime) -> bool {
if mime.is_null() {
return false;
@@ -794,9 +778,9 @@ impl<'a> MimeParser<'a> {
}
fn do_add_single_part(&mut self, mut part: Part) {
if self.e2ee_helper.encrypted && self.e2ee_helper.signatures.len() > 0 {
if self.encrypted && self.signatures.len() > 0 {
part.param.set_int(Param::GuranteeE2ee, 1);
} else if self.e2ee_helper.encrypted {
} else if self.encrypted {
part.param.set_int(Param::ErroneousE2ee, 0x2);
}
self.parts.push(part);
@@ -822,31 +806,22 @@ impl<'a> MimeParser<'a> {
}
let mut sender_equals_recipient = false;
let mut fld_from: *const mailimf_from = ptr::null();
/* get From: and check there is exactly one sender */
let fld = mailimf_find_field(self.header_root, MAILIMF_FIELD_FROM as libc::c_int);
if !(fld.is_null()
|| {
fld_from = (*fld).fld_data.fld_from;
fld_from.is_null()
}
|| (*fld_from).frm_mb_list.is_null()
|| (*(*fld_from).frm_mb_list).mb_list.is_null()
|| (*(*(*fld_from).frm_mb_list).mb_list).count != 1i32)
{
let mb = (if !(*(*(*fld_from).frm_mb_list).mb_list).first.is_null() {
(*(*(*(*fld_from).frm_mb_list).mb_list).first).data
} else {
ptr::null_mut()
}) as *mut mailimf_mailbox;
if let Some(fld_from) = mailimf_find_from_field(self.header_root) {
if (*fld_from).frm_mb_list.is_null() || (*(*(*fld_from).frm_mb_list).0).len() != 1 {
let mb = (*(*(*fld_from).frm_mb_list).0)
.first()
.map(|v| *v)
.unwrap_or_else(|| ptr::null_mut());
if !mb.is_null() {
let from_addr_norm = addr_normalize(as_str((*mb).mb_addr_spec));
let recipients = mailimf_get_recipients(self.header_root);
if recipients.len() == 1 {
if recipients.contains(from_addr_norm) {
sender_equals_recipient = true;
if !mb.is_null() {
let from_addr_norm = addr_normalize(as_str((*mb).addr_spec));
let recipients = mailimf_get_recipients(self.header_root);
if recipients.len() == 1 {
if recipients.contains(from_addr_norm) {
sender_equals_recipient = true;
}
}
}
}
@@ -870,11 +845,10 @@ impl<'a> MimeParser<'a> {
pub fn get_rfc724_mid(&mut self) -> Option<String> {
// get Message-ID from header
if let Some(field) = self.lookup_field_typ("Message-ID", MAILIMF_FIELD_MESSAGE_ID) {
unsafe {
let fld_message_id = (*field).fld_data.fld_message_id;
if !fld_message_id.is_null() {
return Some(to_string((*fld_message_id).mid_value));
if let Some(field) = self.lookup_field("Message-ID") {
if let mailimf_field::MessageId(id) = *field {
if !id.is_null() {
return Some(unsafe { to_string((*id).mid_value) });
}
}
}
@@ -909,10 +883,10 @@ pub fn mailimf_find_first_addr(mb_list: *const mailimf_mailbox_list) -> Option<S
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) };
for mb in unsafe { &(*mb_list).0 } {
let mb = *mb;
if !mb.is_null() && !unsafe { (*mb).addr_spec.is_null() } {
let addr = unsafe { as_str((*mb).addr_spec) };
return Some(addr_normalize(addr).to_string());
}
}
@@ -920,31 +894,28 @@ pub fn mailimf_find_first_addr(mb_list: *const mailimf_mailbox_list) -> Option<S
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, mailimf_field>, in_0: *const mailimf_fields) {
if in_0.is_null() {
return;
}
for cur in (*(*in_0).fld_list).into_iter() {
let field = cur as *mut mailimf_field;
// TODO match on enums /rtn
let key = match (*field).fld_type as libc::c_uint {
MAILIMF_FIELD_RETURN_PATH => Some("Return-Path".to_string()),
MAILIMF_FIELD_ORIG_DATE => Some("Date".to_string()),
MAILIMF_FIELD_FROM => Some("From".to_string()),
MAILIMF_FIELD_SENDER => Some("Sender".to_string()),
MAILIMF_FIELD_REPLY_TO => Some("Reply-To".to_string()),
MAILIMF_FIELD_TO => Some("To".to_string()),
MAILIMF_FIELD_CC => Some("Cc".to_string()),
MAILIMF_FIELD_BCC => Some("Bcc".to_string()),
MAILIMF_FIELD_MESSAGE_ID => Some("Message-ID".to_string()),
MAILIMF_FIELD_IN_REPLY_TO => Some("In-Reply-To".to_string()),
MAILIMF_FIELD_REFERENCES => Some("References".to_string()),
MAILIMF_FIELD_SUBJECT => Some("Subject".to_string()),
MAILIMF_FIELD_OPTIONAL_FIELD => {
for field in &(*in_0).0 {
use mailimf_field::*;
let key = match *field {
ReturnPath(_) => Some("Return-Path".to_string()),
OrigDate(_) => Some("Date".to_string()),
From(_) => Some("From".to_string()),
Sender(_) => Some("Sender".to_string()),
ReplyTo(_) => Some("Reply-To".to_string()),
To(_) => Some("To".to_string()),
Cc(_) => Some("Cc".to_string()),
Bcc(_) => Some("Bcc".to_string()),
MessageId(_) => Some("Message-ID".to_string()),
InReplyTo(_) => Some("In-Reply-To".to_string()),
References(_) => Some("References".to_string()),
Subject(_) => Some("Subject".to_string()),
OptionalField(optional_field) => {
// MAILIMF_FIELD_OPTIONAL_FIELD
let optional_field = (*field).fld_data.fld_optional_field;
// XXX the optional field sometimes contains invalid UTF8
// which should not happen (according to the mime standard).
// This might point to a bug in our mime parsing/processing
@@ -952,7 +923,7 @@ unsafe fn hash_header(out: &mut HashMap<String, *mut mailimf_field>, in_0: *cons
// anyway we just use a lossy conversion.
if !optional_field.is_null() {
Some(to_string_lossy((*optional_field).fld_name))
Some(to_string_lossy((*optional_field).name))
} else {
None
}
@@ -961,9 +932,9 @@ unsafe fn hash_header(out: &mut HashMap<String, *mut mailimf_field>, in_0: *cons
};
if let Some(key) = key {
if !out.contains_key(&key) || // key already exists, only overwrite known types (protected headers)
(*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as i32 || key.starts_with("Chat-")
field.is_optional_field() || key.starts_with("Chat-")
{
out.insert(key, field);
out.insert(key, *field);
}
}
}
@@ -1204,49 +1175,41 @@ pub unsafe fn mailmime_transfer_decode(mime: *mut Mailmime) -> Result<Vec<u8>, E
Err(format_err!("Failed to to decode"))
}
pub unsafe fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet<String> {
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 (*(*imffields).fld_list).into_iter() {
let fld = cur as *mut mailimf_field;
let fld_to: *mut mailimf_to;
let fld_cc: *mut mailimf_cc;
for fld in unsafe { &(*imffields).0 } {
let mut addr_list: *mut mailimf_address_list = ptr::null_mut();
// TODO match on enums /rtn
match (*fld).fld_type {
13 => {
fld_to = (*fld).fld_data.fld_to;
match *fld {
mailimf_field::To(fld_to) => {
if !fld_to.is_null() {
addr_list = (*fld_to).to_addr_list
addr_list = unsafe { (*fld_to).to_addr_list };
}
}
14 => {
fld_cc = (*fld).fld_data.fld_cc;
mailimf_field::Cc(fld_cc) => {
if !fld_cc.is_null() {
addr_list = (*fld_cc).cc_addr_list
addr_list = unsafe { (*fld_cc).cc_addr_list };
}
}
_ => {}
}
if !addr_list.is_null() {
for cur2 in (*(*addr_list).ad_list).into_iter() {
let adr = cur2 as *mut mailimf_address;
for adr in unsafe { &(*(*addr_list).0) } {
if adr.is_null() {
continue;
}
if !adr.is_null() {
if (*adr).ad_type == MAILIMF_ADDRESS_MAILBOX as libc::c_int {
mailimf_get_recipients_add_addr(&mut recipients, (*adr).ad_data.ad_mailbox);
} else if (*adr).ad_type == MAILIMF_ADDRESS_GROUP as libc::c_int {
let group: *mut mailimf_group = (*adr).ad_data.ad_group;
if !group.is_null() && !(*group).grp_mb_list.is_null() {
for cur3 in (*(*(*group).grp_mb_list).mb_list).into_iter() {
mailimf_get_recipients_add_addr(
&mut recipients,
cur3 as *mut mailimf_mailbox,
);
match unsafe { &**adr } {
mailimf_address::Mailbox(mailbox) => {
mailimf_get_recipients_add_addr(&mut recipients, *mailbox);
}
mailimf_address::Group(group) => {
if !group.is_null() && unsafe { !(**group).mb_list.is_null() } {
for mb in unsafe { &((*(**group).mb_list).0) } {
mailimf_get_recipients_add_addr(&mut recipients, *mb);
}
}
}
@@ -1260,39 +1223,37 @@ pub unsafe fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet<
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 }));
let addr_norm = addr_normalize(as_str(unsafe { (*mb).addr_spec }));
recipients.insert(addr_norm.into());
}
}
/*the result is a pointer to mime, must not be freed*/
pub unsafe fn mailimf_find_field(
header: *mut mailimf_fields,
wanted_fld_type: libc::c_int,
) -> *mut mailimf_field {
if header.is_null() || (*header).fld_list.is_null() {
return ptr::null_mut();
}
let mut cur1: *mut clistiter = (*(*header).fld_list).first;
while !cur1.is_null() {
let field: *mut mailimf_field = (if !cur1.is_null() {
(*cur1).data
} else {
ptr::null_mut()
}) as *mut mailimf_field;
if !field.is_null() {
if (*field).fld_type == wanted_fld_type {
return field;
}
}
cur1 = if !cur1.is_null() {
(*cur1).next
} else {
ptr::null_mut()
}
pub fn mailimf_find_from_field(header: *mut mailimf_fields) -> Option<*mut mailimf_from> {
if header.is_null() {
return None;
}
ptr::null_mut()
unsafe { (*header).0.iter() }.find_map(|field| {
if let mailimf_field::From(f) = field {
Some(*f)
} else {
None
}
})
}
pub fn mailimf_find_orig_date_field(header: *mut mailimf_fields) -> Option<*mut mailimf_orig_date> {
if header.is_null() {
return None;
}
unsafe { (*header).0.iter() }.find_map(|field| {
if let mailimf_field::OrigDate(d) = field {
Some(*d)
} else {
None
}
})
}
/*the result is a pointer to mime, must not be freed*/
@@ -1321,18 +1282,15 @@ 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() {
if header.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;
for field in &(*header).0 {
if let mailimf_field::OptionalField(optional_field) = *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
&& !(*optional_field).name.is_null()
&& !(*optional_field).value.is_null()
&& strcasecmp((*optional_field).name, wanted_fld_name) == 0i32
{
return optional_field;
}
@@ -1347,7 +1305,6 @@ mod tests {
use super::*;
use crate::test_utils::*;
use proptest::prelude::*;
use std::ffi::CStr;
#[test]
fn test_mailmime_parse() {
@@ -1370,19 +1327,9 @@ mod tests {
);
assert!(!of_a.is_null());
assert!(!(*of_a).fld_value.is_null());
assert_eq!(
CStr::from_ptr((*of_a).fld_name as *const libc::c_char)
.to_str()
.unwrap(),
"FieldA",
);
assert_eq!(
CStr::from_ptr((*of_a).fld_value as *const libc::c_char)
.to_str()
.unwrap(),
"ValueA",
);
assert!(!(*of_a).value.is_null());
assert_eq!(as_str((*of_a).name), "FieldA");
assert_eq!(as_str((*of_a).value), "ValueA");
of_a = mailimf_find_optional_field(
fields,
@@ -1390,33 +1337,18 @@ mod tests {
);
assert!(!of_a.is_null());
assert!(!(*of_a).fld_value.is_null());
assert_eq!(
CStr::from_ptr((*of_a).fld_name as *const libc::c_char)
.to_str()
.unwrap(),
"FieldA",
);
assert_eq!(
CStr::from_ptr((*of_a).fld_value as *const libc::c_char)
.to_str()
.unwrap(),
"ValueA",
);
assert!(!(*of_a).value.is_null());
assert_eq!(as_str((*of_a).name), "FieldA");
assert_eq!(as_str((*of_a).value), "ValueA");
let of_b: *mut mailimf_optional_field = mailimf_find_optional_field(
let of_b = mailimf_find_optional_field(
fields,
b"FieldB\x00" as *const u8 as *const libc::c_char,
);
assert!(!of_b.is_null());
assert!(!(*of_b).fld_value.is_null());
assert_eq!(
CStr::from_ptr((*of_b).fld_value as *const libc::c_char)
.to_str()
.unwrap(),
"ValueB",
);
assert!(!(*of_b).value.is_null());
assert_eq!(as_str((*of_b).value), "ValueB");
mailmime_free(mime);
}

View File

@@ -3,7 +3,6 @@ use std::ptr;
use itertools::join;
use libc::{free, strcmp, strlen};
use mmime::clist::*;
use mmime::mailimf::types::*;
use mmime::mailimf::*;
use mmime::mailmime::content::*;
@@ -119,61 +118,65 @@ pub unsafe fn dc_receive_imf(
}
};
if let Some(field) = mime_parser.lookup_field_typ("Date", MAILIMF_FIELD_ORIG_DATE) {
let orig_date = (*field).fld_data.fld_orig_date;
if !orig_date.is_null() {
// is not yet checked against bad times! we do this later if we have the database information.
sent_timestamp = dc_timestamp_from_date((*orig_date).dt_date_time)
if let Some(field) = mime_parser.lookup_field("Date") {
if let mailimf_field::OrigDate(orig_date) = *field {
if !orig_date.is_null() {
// is not yet checked against bad times! we do this later if we have the database information.
sent_timestamp = dc_timestamp_from_date((*orig_date).dt_date_time)
}
}
}
// get From: and check if it is known (for known From:'s we add the other To:/Cc: in the 3rd pass)
// or if From: is equal to SELF (in this case, it is any outgoing messages,
// we do not check Return-Path any more as this is unreliable, see issue #150
if let Some(field) = mime_parser.lookup_field_typ("From", MAILIMF_FIELD_FROM) {
let fld_from = (*field).fld_data.fld_from;
if !fld_from.is_null() {
let mut check_self = 0;
let mut from_list = Vec::with_capacity(16);
dc_add_or_lookup_contacts_by_mailbox_list(
context,
(*fld_from).frm_mb_list,
Origin::IncomingUnknownFrom,
&mut from_list,
&mut check_self,
);
if 0 != check_self {
incoming = 0;
if mime_parser.sender_equals_recipient() {
from_id = DC_CONTACT_ID_SELF;
if let Some(field) = mime_parser.lookup_field("From") {
if let mailimf_field::From(fld_from) = *field {
if !fld_from.is_null() {
let mut check_self = 0;
let mut from_list = Vec::with_capacity(16);
dc_add_or_lookup_contacts_by_mailbox_list(
context,
(*fld_from).frm_mb_list,
Origin::IncomingUnknownFrom,
&mut from_list,
&mut check_self,
);
if 0 != check_self {
incoming = 0;
if mime_parser.sender_equals_recipient() {
from_id = DC_CONTACT_ID_SELF;
}
} else if from_list.len() >= 1 {
// if there is no from given, from_id stays 0 which is just fine. These messages
// are very rare, however, we have to add them to the database (they go to the
// "deaddrop" chat) to avoid a re-download from the server. See also [**]
from_id = from_list[0];
incoming_origin =
Contact::get_origin_by_id(context, from_id, &mut from_id_blocked)
}
} else if from_list.len() >= 1 {
// if there is no from given, from_id stays 0 which is just fine. These messages
// are very rare, however, we have to add them to the database (they go to the
// "deaddrop" chat) to avoid a re-download from the server. See also [**]
from_id = from_list[0];
incoming_origin = Contact::get_origin_by_id(context, from_id, &mut from_id_blocked)
}
}
}
// Make sure, to_ids starts with the first To:-address (Cc: is added in the loop below pass)
if let Some(field) = mime_parser.lookup_field_typ("To", MAILIMF_FIELD_TO) {
let fld_to = (*field).fld_data.fld_to;
if !fld_to.is_null() {
dc_add_or_lookup_contacts_by_address_list(
context,
(*fld_to).to_addr_list,
if 0 == incoming {
Origin::OutgoingTo
} else if incoming_origin.is_verified() {
Origin::IncomingTo
} else {
Origin::IncomingUnknownTo
},
&mut to_ids,
&mut to_self,
);
if let Some(field) = mime_parser.lookup_field("To") {
if let mailimf_field::To(fld_to) = *field {
if !fld_to.is_null() {
dc_add_or_lookup_contacts_by_address_list(
context,
(*fld_to).to_addr_list,
if 0 == incoming {
Origin::OutgoingTo
} else if incoming_origin.is_verified() {
Origin::IncomingTo
} else {
Origin::IncomingUnknownTo
},
&mut to_ids,
&mut to_self,
);
}
}
}
@@ -327,22 +330,23 @@ unsafe fn add_parts(
// collect the rest information, CC: is added to the to-list, BCC: is ignored
// (we should not add BCC to groups as this would split groups. We could add them as "known contacts",
// however, the benefit is very small and this may leak data that is expected to be hidden)
if let Some(field) = mime_parser.lookup_field_typ("Cc", MAILIMF_FIELD_CC) {
let fld_cc = (*field).fld_data.fld_cc;
if !fld_cc.is_null() {
dc_add_or_lookup_contacts_by_address_list(
context,
(*fld_cc).cc_addr_list,
if 0 == incoming {
Origin::OutgoingCc
} else if incoming_origin.is_verified() {
Origin::IncomingCc
} else {
Origin::IncomingUnknownCc
},
to_ids,
std::ptr::null_mut(),
);
if let Some(field) = mime_parser.lookup_field("Cc") {
if let mailimf_field::Cc(fld_cc) = *field {
if !fld_cc.is_null() {
dc_add_or_lookup_contacts_by_address_list(
context,
(*fld_cc).cc_addr_list,
if 0 == incoming {
Origin::OutgoingCc
} else if incoming_origin.is_verified() {
Origin::IncomingCc
} else {
Origin::IncomingUnknownCc
},
to_ids,
std::ptr::null_mut(),
);
}
}
}
@@ -583,23 +587,25 @@ unsafe fn add_parts(
// if the mime-headers should be saved, find out its size
// (the mime-header ends with an empty line)
let save_mime_headers = context.sql.get_config_bool(context, "save_mime_headers");
if let Some(field) = mime_parser.lookup_field_typ("In-Reply-To", MAILIMF_FIELD_IN_REPLY_TO) {
let fld_in_reply_to = (*field).fld_data.fld_in_reply_to;
if !fld_in_reply_to.is_null() {
mime_in_reply_to = dc_str_from_clist(
(*(*field).fld_data.fld_in_reply_to).mid_list,
b" \x00" as *const u8 as *const libc::c_char,
)
if let Some(field) = mime_parser.lookup_field("In-Reply-To") {
if let mailimf_field::InReplyTo(fld_in_reply_to) = *field {
if !fld_in_reply_to.is_null() {
mime_in_reply_to = dc_str_from_vec(
&(*fld_in_reply_to).0,
b" \x00" as *const u8 as *const libc::c_char,
);
}
}
}
if let Some(field) = mime_parser.lookup_field_typ("References", MAILIMF_FIELD_REFERENCES) {
let fld_references = (*field).fld_data.fld_references;
if !fld_references.is_null() {
mime_references = dc_str_from_clist(
(*(*field).fld_data.fld_references).mid_list,
b" \x00" as *const u8 as *const libc::c_char,
)
if let Some(field) = mime_parser.lookup_field("References") {
if let mailimf_field::References(fld_references) = *field {
if !fld_references.is_null() {
mime_references = dc_str_from_vec(
&(*fld_references).0,
b" \x00" as *const u8 as *const libc::c_char,
)
}
}
}
@@ -610,7 +616,7 @@ unsafe fn add_parts(
let icnt = mime_parser.parts.len();
let mut txt_raw = None;
let is_ok = context
context
.sql
.prepare(
"INSERT INTO msgs \
@@ -697,13 +703,10 @@ unsafe fn add_parts(
Ok(())
},
)
.is_ok();
if !is_ok {
// i/o error - there is nothing more we can do - in other cases, we try to write at least an empty record
cleanup(mime_in_reply_to, mime_references);
bail!("Cannot write DB.");
}
.map_err(|err| {
cleanup(mime_in_reply_to, mime_references);
err
})?;
info!(
context,
@@ -821,16 +824,16 @@ unsafe fn handle_reports(
b"Original-Message-ID\x00" as *const u8 as *const libc::c_char,
);
if !of_disposition.is_null()
&& !(*of_disposition).fld_value.is_null()
&& !(*of_disposition).value.is_null()
&& !of_org_msgid.is_null()
&& !(*of_org_msgid).fld_value.is_null()
&& !(*of_org_msgid).value.is_null()
{
let mut rfc724_mid_0 = std::ptr::null_mut();
dummy = 0;
if mailimf_msg_id_parse(
(*of_org_msgid).fld_value,
strlen((*of_org_msgid).fld_value),
(*of_org_msgid).value,
strlen((*of_org_msgid).value),
&mut dummy,
&mut rfc724_mid_0,
) == MAIL_NO_ERROR as libc::c_int
@@ -1025,38 +1028,36 @@ unsafe fn create_or_lookup_group(
}
if grpid.is_empty() {
if let Some(field) = mime_parser.lookup_field_typ("Message-ID", MAILIMF_FIELD_MESSAGE_ID) {
let fld_message_id = (*field).fld_data.fld_message_id;
if !fld_message_id.is_null() {
if let Some(extracted_grpid) =
dc_extract_grpid_from_rfc724_mid(as_str((*fld_message_id).mid_value))
{
grpid = extracted_grpid.to_string();
} else {
grpid = "".to_string();
if let Some(field) = mime_parser.lookup_field("Message-ID") {
if let mailimf_field::MessageId(fld_message_id) = *field {
if !fld_message_id.is_null() {
if let Some(extracted_grpid) =
dc_extract_grpid_from_rfc724_mid(as_str((*fld_message_id).mid_value))
{
grpid = extracted_grpid.to_string();
} else {
grpid = "".to_string();
}
}
}
}
if grpid.is_empty() {
if let Some(field) =
mime_parser.lookup_field_typ("In-Reply-To", MAILIMF_FIELD_IN_REPLY_TO)
{
let fld_in_reply_to = (*field).fld_data.fld_in_reply_to;
if !fld_in_reply_to.is_null() {
grpid = to_string(dc_extract_grpid_from_rfc724_mid_list(
(*fld_in_reply_to).mid_list,
));
if let Some(field) = mime_parser.lookup_field("In-Reply-To") {
if let mailimf_field::InReplyTo(fld_in_reply_to) = *field {
if !fld_in_reply_to.is_null() {
grpid =
to_string(dc_extract_grpid_from_rfc724_mid_list(&(*fld_in_reply_to).0));
}
}
}
if grpid.is_empty() {
if let Some(field) =
mime_parser.lookup_field_typ("References", MAILIMF_FIELD_REFERENCES)
{
let fld_references = (*field).fld_data.fld_references;
if !fld_references.is_null() {
grpid = to_string(dc_extract_grpid_from_rfc724_mid_list(
(*fld_references).mid_list,
));
if let Some(field) = mime_parser.lookup_field("References") {
if let mailimf_field::References(fld_references) = *field {
if !fld_references.is_null() {
grpid = to_string(dc_extract_grpid_from_rfc724_mid_list(
&(*fld_references).0,
));
}
}
}
@@ -1609,10 +1610,7 @@ fn check_verified_properties(
) -> Result<()> {
let contact = Contact::load_from_db(context, from_id)?;
ensure!(
mimeparser.e2ee_helper.encrypted,
"This message is not encrypted."
);
ensure!(mimeparser.encrypted, "This message is not encrypted.");
// ensure, the contact is verified
// and the message is signed with a verified key of the sender.
@@ -1633,7 +1631,7 @@ fn check_verified_properties(
if let Some(peerstate) = peerstate {
ensure!(
peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures),
peerstate.has_verified_key(&mimeparser.signatures),
"The message was sent with non-verified encryption."
);
}
@@ -1660,7 +1658,7 @@ fn check_verified_properties(
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.gossipped_addr.contains(&to_addr) && peerstate.is_some() {
let peerstate = peerstate.as_mut().unwrap();
// if we're here, we know the gossip key is verified:
@@ -1712,13 +1710,9 @@ unsafe fn dc_is_reply_to_known_message(context: &Context, mime_parser: &MimePars
}
if let Some(field) = mime_parser.lookup_field("In-Reply-To") {
if (*field).fld_type == MAILIMF_FIELD_IN_REPLY_TO as libc::c_int {
let fld_in_reply_to = (*field).fld_data.fld_in_reply_to;
if let mailimf_field::InReplyTo(fld_in_reply_to) = *field {
if !fld_in_reply_to.is_null() {
if is_known_rfc724_mid_in_list(
context,
(*(*field).fld_data.fld_in_reply_to).mid_list,
) {
if is_known_rfc724_mid_in_list(context, &(*fld_in_reply_to).0) {
return 1;
}
}
@@ -1726,13 +1720,9 @@ unsafe fn dc_is_reply_to_known_message(context: &Context, mime_parser: &MimePars
}
if let Some(field) = mime_parser.lookup_field("References") {
if (*field).fld_type == MAILIMF_FIELD_REFERENCES as libc::c_int {
let fld_references = (*field).fld_data.fld_references;
if let mailimf_field::References(fld_references) = *field {
if !fld_references.is_null() {
if is_known_rfc724_mid_in_list(
context,
(*(*field).fld_data.fld_references).mid_list,
) {
if is_known_rfc724_mid_in_list(context, &(*fld_references).0) {
return 1;
}
}
@@ -1742,13 +1732,12 @@ unsafe fn dc_is_reply_to_known_message(context: &Context, mime_parser: &MimePars
0
}
unsafe fn is_known_rfc724_mid_in_list(context: &Context, mid_list: *const clist) -> bool {
if mid_list.is_null() {
return false;
}
for data in &*mid_list {
if 0 != is_known_rfc724_mid(context, data.cast()) {
unsafe fn is_known_rfc724_mid_in_list(
context: &Context,
mid_list: &Vec<*mut libc::c_char>,
) -> bool {
for data in mid_list {
if 0 != is_known_rfc724_mid(context, *data) {
return true;
}
}
@@ -1784,13 +1773,9 @@ unsafe fn dc_is_reply_to_messenger_message(
- no check for the Chat-* headers (function is only called if it is no messenger message itself) */
if let Some(field) = mime_parser.lookup_field("In-Reply-To") {
if (*field).fld_type == MAILIMF_FIELD_IN_REPLY_TO as libc::c_int {
let fld_in_reply_to = (*field).fld_data.fld_in_reply_to;
if let mailimf_field::InReplyTo(fld_in_reply_to) = *field {
if !fld_in_reply_to.is_null() {
if 0 != is_msgrmsg_rfc724_mid_in_list(
context,
(*(*field).fld_data.fld_in_reply_to).mid_list,
) {
if 0 != is_msgrmsg_rfc724_mid_in_list(context, &(*fld_in_reply_to).0) {
return 1;
}
}
@@ -1798,13 +1783,9 @@ unsafe fn dc_is_reply_to_messenger_message(
}
if let Some(field) = mime_parser.lookup_field("References") {
if (*field).fld_type == MAILIMF_FIELD_REFERENCES as libc::c_int {
let fld_references: *mut mailimf_references = (*field).fld_data.fld_references;
if let mailimf_field::References(fld_references) = *field {
if !fld_references.is_null() {
if 0 != is_msgrmsg_rfc724_mid_in_list(
context,
(*(*field).fld_data.fld_references).mid_list,
) {
if 0 != is_msgrmsg_rfc724_mid_in_list(context, &(*fld_references).0) {
return 1;
}
}
@@ -1814,25 +1795,13 @@ unsafe fn dc_is_reply_to_messenger_message(
0
}
unsafe fn is_msgrmsg_rfc724_mid_in_list(context: &Context, mid_list: *const clist) -> libc::c_int {
if !mid_list.is_null() {
let mut cur: *mut clistiter = (*mid_list).first;
while !cur.is_null() {
if 0 != is_msgrmsg_rfc724_mid(
context,
if !cur.is_null() {
as_str((*cur).data as *const libc::c_char)
} else {
""
},
) {
return 1;
}
cur = if !cur.is_null() {
(*cur).next
} else {
ptr::null_mut()
}
unsafe fn is_msgrmsg_rfc724_mid_in_list(
context: &Context,
mid_list: &Vec<*mut libc::c_char>,
) -> libc::c_int {
for cur in mid_list {
if 0 != is_msgrmsg_rfc724_mid(context, if !cur.is_null() { as_str(*cur) } else { "" }) {
return 1;
}
}
0
@@ -1862,43 +1831,36 @@ unsafe fn dc_add_or_lookup_contacts_by_address_list(
if adr_list.is_null() {
return;
}
let mut cur: *mut clistiter = (*(*adr_list).ad_list).first;
while !cur.is_null() {
let adr: *mut mailimf_address = (if !cur.is_null() {
(*cur).data
} else {
ptr::null_mut()
}) as *mut mailimf_address;
if !adr.is_null() {
if (*adr).ad_type == MAILIMF_ADDRESS_MAILBOX as libc::c_int {
let mb: *mut mailimf_mailbox = (*adr).ad_data.ad_mailbox;
for adr in &(*(*adr_list).0) {
if adr.is_null() {
continue;
}
match **adr {
mailimf_address::Mailbox(mb) => {
if !mb.is_null() {
add_or_lookup_contact_by_addr(
context,
(*mb).mb_display_name,
(*mb).mb_addr_spec,
origin,
ids,
check_self,
);
}
} else if (*adr).ad_type == MAILIMF_ADDRESS_GROUP as libc::c_int {
let group: *mut mailimf_group = (*adr).ad_data.ad_group;
if !group.is_null() && !(*group).grp_mb_list.is_null() {
dc_add_or_lookup_contacts_by_mailbox_list(
context,
(*group).grp_mb_list,
(*mb).display_name,
(*mb).addr_spec,
origin,
ids,
check_self,
);
}
}
mailimf_address::Group(group) => {
if !group.is_null() && !(*group).mb_list.is_null() {
dc_add_or_lookup_contacts_by_mailbox_list(
context,
(*group).mb_list,
origin,
ids,
check_self,
);
}
}
}
cur = if !cur.is_null() {
(*cur).next
} else {
ptr::null_mut()
}
}
}
@@ -1913,28 +1875,18 @@ unsafe fn dc_add_or_lookup_contacts_by_mailbox_list(
if mb_list.is_null() {
return;
}
let mut cur: *mut clistiter = (*(*mb_list).mb_list).first;
while !cur.is_null() {
let mb: *mut mailimf_mailbox = (if !cur.is_null() {
(*cur).data
} else {
ptr::null_mut()
}) as *mut mailimf_mailbox;
for mb in &(*mb_list).0 {
let mb = *mb;
if !mb.is_null() {
add_or_lookup_contact_by_addr(
context,
(*mb).mb_display_name,
(*mb).mb_addr_spec,
(*mb).display_name,
(*mb).addr_spec,
origin,
ids,
check_self,
);
}
cur = if !cur.is_null() {
(*cur).next
} else {
ptr::null_mut()
}
}
}

View File

@@ -10,7 +10,6 @@ use std::{fmt, fs, ptr};
use chrono::{Local, TimeZone};
use libc::{memcpy, strlen};
use mmime::clist::*;
use mmime::mailimf::types::*;
use rand::{thread_rng, Rng};
@@ -149,46 +148,26 @@ pub(crate) fn dc_truncate(buf: &str, approx_chars: usize, do_unwrap: bool) -> Co
}
}
pub(crate) unsafe fn dc_str_from_clist(
list: *const clist,
pub(crate) unsafe fn dc_str_from_vec(
list: &Vec<*mut libc::c_char>,
delimiter: *const libc::c_char,
) -> *mut libc::c_char {
let mut res = String::new();
if !list.is_null() {
let mut cur: *mut clistiter = (*list).first;
while !cur.is_null() {
let rfc724_mid = (if !cur.is_null() {
(*cur).data
} else {
ptr::null_mut()
}) as *const libc::c_char;
if !rfc724_mid.is_null() {
if !res.is_empty() && !delimiter.is_null() {
res += as_str(delimiter);
}
res += as_str(rfc724_mid);
}
cur = if !cur.is_null() {
(*cur).next
} else {
ptr::null_mut()
for val in list {
if !val.is_null() {
if !res.is_empty() && !delimiter.is_null() {
res += as_str(delimiter);
}
res += as_str(*val);
}
}
res.strdup()
}
pub(crate) fn dc_str_to_clist(str: &str, delimiter: &str) -> *mut clist {
unsafe {
let list: *mut clist = clist_new();
for cur in str.split(&delimiter) {
clist_insert_after(list, (*list).last, cur.strdup().cast());
}
list
}
pub(crate) fn dc_str_to_vec(s: &str, delimiter: &str) -> Vec<*mut libc::c_char> {
s.split(&delimiter).map(|s| unsafe { s.strdup() }).collect()
}
/* the colors must fulfill some criterions as:
@@ -217,26 +196,26 @@ pub(crate) fn dc_str_to_color(s: impl AsRef<str>) -> u32 {
/* date/time tools */
/* the result is UTC or DC_INVALID_TIMESTAMP */
pub(crate) unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
let sec = (*date_time).dt_sec;
let min = (*date_time).dt_min;
let hour = (*date_time).dt_hour;
let day = (*date_time).dt_day;
let month = (*date_time).dt_month;
let year = (*date_time).dt_year;
pub(crate) fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
assert!(!date_time.is_null());
let dt = unsafe { &*date_time };
let sec = dt.sec;
let min = dt.min;
let hour = dt.hour;
let day = dt.day;
let month = dt.month;
let year = dt.year;
let ts = chrono::NaiveDateTime::new(
chrono::NaiveDate::from_ymd(year, month as u32, day as u32),
chrono::NaiveTime::from_hms(hour as u32, min as u32, sec as u32),
chrono::NaiveDate::from_ymd(year, month, day),
chrono::NaiveTime::from_hms(hour, min, sec),
);
let (zone_hour, zone_min) = if (*date_time).dt_zone >= 0 {
((*date_time).dt_zone / 100, (*date_time).dt_zone % 100)
let (zone_hour, zone_min) = if dt.zone >= 0 {
(dt.zone / 100, dt.zone % 100)
} else {
(
-(-(*date_time).dt_zone / 100),
-(-(*date_time).dt_zone % 100),
)
(-(-dt.zone / 100), -(-dt.zone % 100))
};
ts.timestamp() - (zone_hour * 3600 + zone_min * 60) as i64
@@ -392,15 +371,15 @@ pub(crate) fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> {
None
}
pub(crate) fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut libc::c_char {
if !list.is_null() {
unsafe {
for cur in (*list).into_iter() {
let mid = as_str(cur as *const libc::c_char);
pub(crate) fn dc_extract_grpid_from_rfc724_mid_list(
list: &Vec<*mut libc::c_char>,
) -> *mut libc::c_char {
unsafe {
for cur in list {
let mid = as_str(*cur);
if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(mid) {
return grpid.strdup();
}
if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(mid) {
return grpid.strdup();
}
}
}
@@ -1129,21 +1108,6 @@ mod tests {
);
}
/* calls free() for each item content */
unsafe fn clist_free_content(haystack: *const clist) {
let mut iter = (*haystack).first;
while !iter.is_null() {
free((*iter).data);
(*iter).data = ptr::null_mut();
iter = if !iter.is_null() {
(*iter).next
} else {
ptr::null_mut()
}
}
}
fn strndup(s: *const libc::c_char, n: libc::c_ulong) -> *mut libc::c_char {
if s.is_null() {
return std::ptr::null_mut();
@@ -1159,35 +1123,6 @@ mod tests {
}
}
#[test]
fn test_dc_str_to_clist_1() {
unsafe {
let list = dc_str_to_clist("", " ");
assert_eq!((*list).count, 1);
clist_free_content(list);
clist_free(list);
}
}
#[test]
fn test_dc_str_to_clist_4() {
unsafe {
let list: *mut clist = dc_str_to_clist("foo bar test", " ");
assert_eq!((*list).count, 3);
let str: *mut libc::c_char =
dc_str_from_clist(list, b" \x00" as *const u8 as *const libc::c_char);
assert_eq!(
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
"foo bar test"
);
clist_free_content(list);
clist_free(list);
free(str as *mut libc::c_void);
}
}
#[test]
fn test_dc_create_id() {
let buf = dc_create_id();

View File

@@ -1,12 +1,10 @@
//! End-to-end encryption support.
use std::collections::HashSet;
use std::ffi::CStr;
use std::ptr;
use std::str::FromStr;
use libc::{strcmp, strlen, strncmp};
use mmime::clist::*;
use libc::strlen;
use mmime::mailimf::types::*;
use mmime::mailimf::types_helper::*;
use mmime::mailimf::*;
@@ -18,6 +16,7 @@ use mmime::mailmime::*;
use mmime::mailprivacy_prepare_mime;
use mmime::mmapstring::*;
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
use num_traits::FromPrimitive;
use crate::aheader::*;
use crate::config::Config;
@@ -47,12 +46,12 @@ pub struct EncryptHelper {
impl EncryptHelper {
pub fn new(context: &Context) -> Result<EncryptHelper> {
let e2ee = context.sql.get_config_int(&context, "e2ee_enabled");
let prefer_encrypt = if 0 != e2ee.unwrap_or_default() {
EncryptPreference::Mutual
} else {
EncryptPreference::NoPreference
};
let prefer_encrypt = context
.sql
.get_config_int(&context, "e2ee_enabled")
.and_then(EncryptPreference::from_i32)
.unwrap_or_default();
let addr = match context.get_config(Config::ConfiguredAddr) {
None => {
bail!("addr not configured!");
@@ -61,6 +60,7 @@ impl EncryptHelper {
};
let public_key = load_or_generate_self_public_key(context, &addr)?;
Ok(EncryptHelper {
prefer_encrypt,
addr,
@@ -83,11 +83,13 @@ impl EncryptHelper {
mut in_out_message: *mut Mailmime,
imffields_unprotected: *mut mailimf_fields,
) -> Result<bool> {
/* libEtPan's pgp_encrypt_mime() takes the parent as the new root.
We just expect the root as being given to this function. */
if in_out_message.is_null() || unsafe { !(*in_out_message).mm_parent.is_null() } {
bail!("corrupted inputs");
}
// libEtPan's pgp_encrypt_mime() takes the parent as the new root.
// We just expect the root as being given to this function.
ensure!(
!in_out_message.is_null() && unsafe { (*in_out_message).mm_parent.is_null() },
"corrupted inputs"
);
if !(self.prefer_encrypt == EncryptPreference::Mutual || e2ee_guaranteed) {
return Ok(false);
}
@@ -106,13 +108,14 @@ impl EncryptHelper {
None => {
let msg = format!("peerstate for {} missing, cannot encrypt", recipient_addr);
if e2ee_guaranteed {
bail!("{}", msg);
return Err(format_err!("{}", msg));
} else {
info!(context, "{}", msg);
return Ok(false);
}
}
};
if peerstate.prefer_encrypt != EncryptPreference::Mutual && !e2ee_guaranteed {
info!(context, "peerstate for {} is no-encrypt", recipient_addr);
return Ok(false);
@@ -136,30 +139,24 @@ impl EncryptHelper {
let sign_key = {
keyring.add_ref(&self.public_key);
let key = Key::from_self_private(context, self.addr.clone(), &context.sql);
if key.is_none() {
bail!("no own private key found")
}
ensure!(key.is_some(), "no own private key found");
key
};
/* encrypt message */
// encrypt message
unsafe {
mailprivacy_prepare_mime(in_out_message);
let mut part_to_encrypt: *mut Mailmime =
(*in_out_message).mm_data.mm_message.mm_msg_mime;
let mut part_to_encrypt = (*in_out_message).mm_data.mm_message.mm_msg_mime;
(*part_to_encrypt).mm_parent = ptr::null_mut();
let imffields_encrypted: *mut mailimf_fields = mailimf_fields_new_empty();
/* mailmime_new_message_data() calls mailmime_fields_new_with_version() which would add the unwanted MIME-Version:-header */
let message_to_encrypt: *mut Mailmime = mailmime_new(
let imffields_encrypted = mailimf_fields_new_empty();
// mailmime_new_message_data() calls mailmime_fields_new_with_version()
// which would add the unwanted MIME-Version:-header
let message_to_encrypt = mailmime_new_simple(
MAILMIME_MESSAGE as libc::c_int,
ptr::null(),
0 as libc::size_t,
mailmime_fields_new_empty(),
mailmime_get_content_message(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
imffields_encrypted,
part_to_encrypt,
);
@@ -168,19 +165,17 @@ impl EncryptHelper {
wrapmime::new_custom_field(imffields_encrypted, "Autocrypt-Gossip", &header)
}
/* memoryhole headers: move some headers into encrypted part */
// XXX note we can't use clist's into_iter() because the loop body also removes items
let mut cur: *mut clistiter = (*(*imffields_unprotected).fld_list).first;
while !cur.is_null() {
let field: *mut mailimf_field = (*cur).data as *mut mailimf_field;
// memoryhole headers: move some headers into encrypted part
(*imffields_unprotected).0.retain(|field| {
let mut move_to_encrypted = false;
if !field.is_null() {
if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
match *field {
mailimf_field::Subject(_) => {
move_to_encrypted = true;
} else if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
let opt_field = (*field).fld_data.fld_optional_field;
if !opt_field.is_null() && !(*opt_field).fld_name.is_null() {
let fld_name = to_string_lossy((*opt_field).fld_name);
}
mailimf_field::OptionalField(opt_field) => {
if !opt_field.is_null() && !(*opt_field).name.is_null() {
let fld_name = to_string_lossy((*opt_field).name);
if fld_name.starts_with("Secure-Join")
|| (fld_name.starts_with("Chat-") && fld_name != "Chat-Version")
{
@@ -188,56 +183,34 @@ impl EncryptHelper {
}
}
}
_ => {}
}
if move_to_encrypted {
mailimf_fields_add(imffields_encrypted, field);
cur = clist_delete((*imffields_unprotected).fld_list, cur);
mailimf_fields_add(imffields_encrypted, *field);
false
} else {
cur = (*cur).next;
true
}
}
let subject: *mut mailimf_subject = mailimf_subject_new("...".strdup());
mailimf_fields_add(
imffields_unprotected,
mailimf_field_new(
MAILIMF_FIELD_SUBJECT as libc::c_int,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
subject,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
),
);
});
let subject = mailimf_subject_new("...".strdup());
mailimf_fields_add(imffields_unprotected, mailimf_field::Subject(subject));
wrapmime::append_ct_param(
(*part_to_encrypt).mm_content_type,
"protected-headers",
"v1",
)?;
let plain: *mut MMAPString =
mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
let mut col: libc::c_int = 0i32;
let plain = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
let mut col = 0;
mailmime_write_mem(plain, &mut col, message_to_encrypt);
mailmime_free(message_to_encrypt);
if (*plain).str_0.is_null() || (*plain).len <= 0 {
bail!("could not write/allocate");
}
ensure!(
!(*plain).str_0.is_null() && (*plain).len > 0,
"could not write/allocate"
);
let ctext = dc_pgp_pk_encrypt(
std::slice::from_raw_parts((*plain).str_0 as *const u8, (*plain).len),
@@ -246,165 +219,143 @@ impl EncryptHelper {
);
mmap_string_free(plain);
if let Ok(ctext_v) = ctext {
/* create MIME-structure that will contain the encrypted text */
let mut encrypted_part: *mut Mailmime = new_data_part(
ptr::null_mut(),
0 as libc::size_t,
"multipart/encrypted",
MAILMIME_MECHANISM_BASE64,
)?;
let content: *mut mailmime_content = (*encrypted_part).mm_content_type;
wrapmime::append_ct_param(content, "protocol", "application/pgp-encrypted")?;
let version_mime: *mut Mailmime = new_data_part(
VERSION_CONTENT.as_mut_ptr() as *mut libc::c_void,
strlen(VERSION_CONTENT.as_mut_ptr()),
"application/pgp-encrypted",
MAILMIME_MECHANISM_7BIT,
)?;
mailmime_smart_add_part(encrypted_part, version_mime);
let ctext_v = ctext?;
// we assume that ctext_v is not dropped until the end
// of this if-scope
let ctext_part: *mut Mailmime = new_data_part(
ctext_v.as_ptr() as *mut libc::c_void,
ctext_v.len(),
"application/octet-stream",
MAILMIME_MECHANISM_7BIT,
)?;
mailmime_smart_add_part(encrypted_part, ctext_part);
(*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part;
(*encrypted_part).mm_parent = in_out_message;
let gossiped = !&gossip_headers.is_empty();
factory.finalize_mime_message(in_out_message, true, gossiped)?;
Ok(true)
} else {
bail!("encryption failed")
}
// create MIME-structure that will contain the encrypted text
let mut encrypted_part = new_data_part(
ptr::null_mut(),
0 as libc::size_t,
"multipart/encrypted",
MAILMIME_MECHANISM_BASE64,
)?;
let content = (*encrypted_part).mm_content_type;
wrapmime::append_ct_param(content, "protocol", "application/pgp-encrypted")?;
let version_mime = new_data_part(
VERSION_CONTENT.as_mut_ptr() as *mut libc::c_void,
strlen(VERSION_CONTENT.as_mut_ptr()),
"application/pgp-encrypted",
MAILMIME_MECHANISM_7BIT,
)?;
mailmime_smart_add_part(encrypted_part, version_mime);
// we assume that ctext_v is not dropped until the end
// of this if-scope
let ctext_part = new_data_part(
ctext_v.as_ptr() as *mut libc::c_void,
ctext_v.len(),
"application/octet-stream",
MAILMIME_MECHANISM_7BIT,
)?;
mailmime_smart_add_part(encrypted_part, ctext_part);
(*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part;
(*encrypted_part).mm_parent = in_out_message;
let gossiped = !&gossip_headers.is_empty();
factory.finalize_mime_message(in_out_message, true, gossiped)?;
Ok(true)
}
}
}
#[derive(Debug, Default)]
pub struct E2eeHelper {
// for decrypting only
pub encrypted: bool,
pub signatures: HashSet<String>,
pub gossipped_addr: HashSet<String>,
}
pub fn try_decrypt(
context: &Context,
in_out_message: *mut Mailmime,
) -> Result<(bool, HashSet<String>, HashSet<String>)> {
let mut encrypted = false;
let mut signatures = HashSet::default();
let mut gossipped_addr = HashSet::default();
impl E2eeHelper {
pub unsafe fn try_decrypt(
&mut self,
context: &Context,
in_out_message: *mut Mailmime,
) -> Result<()> {
/*just a pointer into mailmime structure, must not be freed*/
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
let mut message_time = 0;
let mut from = None;
let mut private_keyring = Keyring::default();
let mut public_keyring_for_validate = Keyring::default();
let mut gossip_headers: *mut mailimf_fields = ptr::null_mut();
// 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();
// 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);
// XXX do wrapmime:: helper for the next block
if !(in_out_message.is_null() || imffields.is_null()) {
if let Some(field) = mailimf_find_from_field(imffields) {
let mb_list = unsafe { (*field).frm_mb_list };
from = mailimf_find_first_addr(mb_list);
}
if !field.is_null() && !(*field).fld_data.fld_from.is_null() {
from = mailimf_find_first_addr((*(*field).fld_data.fld_from).frm_mb_list)
}
field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int);
if !field.is_null() && !(*field).fld_data.fld_orig_date.is_null() {
let orig_date: *mut mailimf_orig_date = (*field).fld_data.fld_orig_date;
if !orig_date.is_null() {
message_time = dc_timestamp_from_date((*orig_date).dt_date_time);
if message_time != 0 && message_time > time() {
message_time = time()
}
if let Some(orig_date) = mailimf_find_orig_date_field(imffields) {
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()
}
}
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);
}
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);
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(
}
/* 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,
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);
}
}
match decrypt_if_autocrypt_message(
context,
in_out_message,
&private_keyring,
&public_keyring_for_validate,
&mut self.signatures,
&mut gossip_headers,
) {
Ok(res) => {
self.encrypted = res;
}
Err(err) => {
bail!("failed to decrypt: {}", err);
}
}
if !gossip_headers.is_null() {
self.gossipped_addr = update_gossip_peerstates(
context,
message_time,
imffields,
gossip_headers,
)
}
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() {
mailimf_fields_free(gossip_headers);
}
Ok(())
}
if !gossip_headers.is_null() {
unsafe { mailimf_fields_free(gossip_headers) };
}
Ok((encrypted, signatures, gossipped_addr))
}
fn new_data_part(
@@ -414,31 +365,34 @@ fn new_data_part(
default_encoding: u32,
) -> Result<*mut Mailmime> {
let content = new_content_type(&content_type)?;
unsafe {
let mut encoding: *mut mailmime_mechanism = ptr::null_mut();
if wrapmime::content_type_needs_encoding(content) {
encoding = mailmime_mechanism_new(default_encoding as i32, ptr::null_mut());
ensure!(!encoding.is_null(), "failed to create encoding");
}
let mime_fields = mailmime_fields_new_with_data(
encoding,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
);
ensure!(!mime_fields.is_null(), "internal mime error");
let mime = mailmime_new_empty(content, mime_fields);
ensure!(!mime.is_null(), "internal mime error");
if (*mime).mm_type == MAILMIME_SINGLE as libc::c_int {
if !data.is_null() && data_bytes > 0 {
mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes);
}
}
return Ok(mime);
let mut encoding = ptr::null_mut();
if wrapmime::content_type_needs_encoding(content) {
encoding = unsafe { mailmime_mechanism_new(default_encoding as i32, ptr::null_mut()) };
ensure!(!encoding.is_null(), "failed to create encoding");
}
let mime_fields = {
unsafe {
mailmime_fields_new_with_data(
encoding,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
)
}
};
ensure!(!mime_fields.is_null(), "internal mime error");
let mime = unsafe { mailmime_new_empty(content, mime_fields) };
ensure!(!mime.is_null(), "internal mime error");
if unsafe { (*mime).mm_type } == MAILMIME_SINGLE as libc::c_int {
if !data.is_null() && data_bytes > 0 {
unsafe { mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes) };
}
}
Ok(mime)
}
/// Load public key from database or generate a new one.
@@ -470,7 +424,7 @@ fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str
&public_key,
&private_key,
&self_addr,
1,
true,
&context.sql,
) {
true => {
@@ -488,31 +442,27 @@ fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str
}
}
unsafe fn update_gossip_peerstates(
fn update_gossip_peerstates(
context: &Context,
message_time: i64,
imffields: *mut mailimf_fields,
gossip_headers: *const mailimf_fields,
) -> HashSet<String> {
) -> Result<HashSet<String>> {
// XXX split the parsing from the modification part
let mut recipients: Option<HashSet<String>> = None;
let mut gossipped_addr: HashSet<String> = Default::default();
for cur_data in (*(*gossip_headers).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 = (*field).fld_data.fld_optional_field;
if !optional_field.is_null()
&& !(*optional_field).fld_name.is_null()
&& strcasecmp(
(*optional_field).fld_name,
b"Autocrypt-Gossip\x00" as *const u8 as *const libc::c_char,
) == 0i32
{
let value = CStr::from_ptr((*optional_field).fld_value)
.to_str()
.unwrap();
let gossip_header = Aheader::from_str(value);
for field in unsafe { &(*gossip_headers).0 } {
if let mailimf_field::OptionalField(optional_field) = *field {
if optional_field.is_null() {
continue;
}
let optional_field = unsafe { &*optional_field };
if !optional_field.name.is_null() && as_str(optional_field.name) == "Autocrypt-Gossip" {
let value = to_string_lossy(optional_field.value);
let gossip_header = Aheader::from_str(&value);
if let Ok(ref header) = gossip_header {
if recipients.is_none() {
recipients = Some(mailimf_get_recipients(imffields));
@@ -522,15 +472,15 @@ unsafe fn update_gossip_peerstates(
Peerstate::from_addr(context, &context.sql, &header.addr);
if let Some(ref mut peerstate) = peerstate {
peerstate.apply_gossip(header, message_time);
peerstate.save_to_db(&context.sql, false).unwrap();
peerstate.save_to_db(&context.sql, false)?;
} else {
let p = Peerstate::from_gossip(context, header, message_time);
p.save_to_db(&context.sql, true).unwrap();
p.save_to_db(&context.sql, true)?;
peerstate = Some(p);
}
if let Some(peerstate) = peerstate {
if peerstate.degrade_event.is_some() {
handle_degrade_event(context, &peerstate);
handle_degrade_event(context, &peerstate)?;
}
}
@@ -547,7 +497,7 @@ unsafe fn update_gossip_peerstates(
}
}
gossipped_addr
Ok(gossipped_addr)
}
fn decrypt_if_autocrypt_message(
@@ -582,16 +532,15 @@ fn decrypt_if_autocrypt_message(
public_keyring_for_validate,
ret_valid_signatures,
)?;
/* decrypted_mime is a dangling pointer which we now put into
mailmime's Ownership */
// decrypted_mime is a dangling pointer which we now put into mailmime's Ownership
unsafe {
mailmime_substitute(mime, decrypted_mime);
mailmime_free(mime);
}
/* finally, let's also return gossip headers
XXX better return parsed headers so that upstream
does not need to dive into mmime-stuff again. */
// finally, let's also return gossip headers
// XXX better return parsed headers so that upstream
// does not need to dive into mmime-stuff again.
unsafe {
if (*ret_gossip_headers).is_null() && ret_valid_signatures.len() > 0 {
let mut dummy: libc::size_t = 0;
@@ -604,11 +553,12 @@ fn decrypt_if_autocrypt_message(
) == MAILIMF_NO_ERROR as libc::c_int
&& !test.is_null()
{
*ret_gossip_headers = test
*ret_gossip_headers = test;
}
}
}
return Ok(true);
Ok(true)
}
fn decrypt_part(
@@ -634,74 +584,75 @@ fn decrypt_part(
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,
after encryption has been attempted.
*/
// 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();
unsafe {
if has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int) {
/* we should only have one decryption happening */
ensure!(ret_valid_signatures.is_empty(), "corrupt signatures");
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) {
// we should only have one decryption happening
ensure!(ret_valid_signatures.is_empty(), "corrupt signatures");
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) => {
ensure!(!ret_valid_signatures.is_empty(), "no valid signatures");
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 plain = match dc_pgp_pk_decrypt(
data,
&private_keyring,
&public_keyring_for_validate,
Some(ret_valid_signatures),
) {
Ok(plain) => {
ensure!(!ret_valid_signatures.is_empty(), "no valid signatures");
plain
}
Err(err) => {
unsafe { 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(
let mut index = 0;
let mut decrypted_mime = ptr::null_mut();
if unsafe {
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;
)
} != MAIL_NO_ERROR as libc::c_int
|| decrypted_mime.is_null()
{
if !decrypted_mime.is_null() {
unsafe { mailmime_free(decrypted_mime) };
}
} else {
// decrypted_mime points into `plain`.
// FIXME(@dignifiedquire): this still leaks memory I believe, as mailmime_free
// does not free the underlying buffer. But for now we have to live with it
std::mem::forget(plain);
ret_decrypted_mime = decrypted_mime;
}
mmap_string_unref(decoded_data);
}
unsafe { mmap_string_unref(decoded_data) };
Ok(ret_decrypted_mime)
}
unsafe fn has_decrypted_pgp_armor(str__: *const libc::c_char, mut str_bytes: libc::c_int) -> bool {
let str_end: *const libc::c_uchar = (str__ as *const libc::c_uchar).offset(str_bytes as isize);
let mut p: *const libc::c_uchar = str__ as *const libc::c_uchar;
while p < str_end {
if *p as libc::c_int > ' ' as i32 {
break;
fn has_decrypted_pgp_armor(input: &[u8]) -> bool {
if let Some(index) = input.iter().position(|b| *b > b' ') {
if input.len() - index > 26 {
let start = index;
let end = start + 27;
return &input[start..end] == b"-----BEGIN PGP MESSAGE-----";
}
p = p.offset(1isize);
str_bytes -= 1
}
str_bytes > 27i32
&& strncmp(
p as *const libc::c_char,
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
27,
) == 0
false
}
/// Check if a MIME structure contains a multipart/report part.
@@ -712,29 +663,31 @@ unsafe fn has_decrypted_pgp_armor(str__: *const libc::c_char, mut str_bytes: lib
/// However, Delta Chat itself has no problem with encrypted multipart/report
/// parts and MUAs should be encouraged to encrpyt multipart/reports as well so
/// that we could use the normal Autocrypt processing.
unsafe fn contains_report(mime: *mut Mailmime) -> bool {
if (*mime).mm_type == MAILMIME_MULTIPLE as libc::c_int {
if (*(*(*mime).mm_content_type).ct_type).tp_type
== MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int
&& (*(*(*(*mime).mm_content_type).ct_type)
.tp_data
.tp_composite_type)
.ct_type
== MAILMIME_COMPOSITE_TYPE_MULTIPART as libc::c_int
&& strcmp(
(*(*mime).mm_content_type).ct_subtype,
b"report\x00" as *const u8 as *const libc::c_char,
) == 0i32
fn contains_report(mime: *mut Mailmime) -> bool {
assert!(!mime.is_null());
let mime = unsafe { *mime };
if mime.mm_type == MAILMIME_MULTIPLE as libc::c_int {
let tp_type = unsafe { (*(*mime.mm_content_type).ct_type).tp_type };
let ct_type =
unsafe { (*(*(*mime.mm_content_type).ct_type).tp_data.tp_composite_type).ct_type };
if tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int
&& ct_type == MAILMIME_COMPOSITE_TYPE_MULTIPART as libc::c_int
&& as_str(unsafe { (*mime.mm_content_type).ct_subtype }) == "report"
{
return true;
}
for cur_data in (*(*(*mime).mm_mime_fields).fld_list).into_iter() {
for cur_data in unsafe { (*(*mime.mm_mime_fields).fld_list).into_iter() } {
if contains_report(cur_data as *mut Mailmime) {
return true;
}
}
} else if (*mime).mm_type == MAILMIME_MESSAGE as libc::c_int {
if contains_report((*mime).mm_data.mm_message.mm_msg_mime) {
} else if mime.mm_type == MAILMIME_MESSAGE as libc::c_int {
let m = unsafe { mime.mm_data.mm_message.mm_msg_mime };
if contains_report(m) {
return true;
}
}
@@ -869,4 +822,22 @@ Sent with my Delta Chat Messenger: https://delta.chat";
assert_eq!(res0.unwrap(), res1.unwrap());
}
}
#[test]
fn test_has_decrypted_pgp_armor() {
let data = b" -----BEGIN PGP MESSAGE-----";
assert_eq!(has_decrypted_pgp_armor(data), true);
let data = b" \n-----BEGIN PGP MESSAGE-----";
assert_eq!(has_decrypted_pgp_armor(data), true);
let data = b" -----BEGIN PGP MESSAGE---";
assert_eq!(has_decrypted_pgp_armor(data), false);
let data = b" -----BEGIN PGP MESSAGE-----";
assert_eq!(has_decrypted_pgp_armor(data), true);
let data = b"blas";
assert_eq!(has_decrypted_pgp_armor(data), false);
}
}

View File

@@ -26,6 +26,10 @@ pub enum Error {
CStringError(crate::dc_tools::CStringError),
#[fail(display = "PGP: {:?}", _0)]
Pgp(pgp::errors::Error),
#[fail(display = "Base64Decode: {:?}", _0)]
Base64Decode(base64::DecodeError),
#[fail(display = "{:?}", _0)]
FromUtf8(std::string::FromUtf8Error),
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -36,6 +40,12 @@ impl From<rusqlite::Error> for Error {
}
}
impl From<base64::DecodeError> for Error {
fn from(err: base64::DecodeError) -> Error {
Error::Base64Decode(err)
}
}
impl From<failure::Error> for Error {
fn from(err: failure::Error) -> Error {
Error::Failure(err)
@@ -60,6 +70,12 @@ impl From<std::str::Utf8Error> for Error {
}
}
impl From<std::string::FromUtf8Error> for Error {
fn from(err: std::string::FromUtf8Error) -> Error {
Error::FromUtf8(err)
}
}
impl From<image_meta::ImageError> for Error {
fn from(err: image_meta::ImageError) -> Error {
Error::Image(err)

View File

@@ -167,7 +167,7 @@ pub enum Event {
#[strum(props(id = "2041"))]
ConfigureProgress(usize),
/// Inform about the import/export progress started by dc_imex().
/// Inform about the import/export progress started by imex().
///
/// @param data1 (usize) 0=error, 1-999=progress in permille, 1000=success and done
/// @param data2 0
@@ -175,8 +175,8 @@ pub enum Event {
#[strum(props(id = "2051"))]
ImexProgress(usize),
/// A file has been exported. A file has been written by dc_imex().
/// This event may be sent multiple times by a single call to dc_imex().
/// A file has been exported. A file has been written by imex().
/// This event may be sent multiple times by a single call to imex().
///
/// A typical purpose for a handler of this event may be to make the file public to some system
/// services.

View File

@@ -2,10 +2,7 @@ use std::ffi::CString;
use std::path::Path;
use std::ptr;
use libc::{free, strlen};
use mmime::mailmime::content::*;
use mmime::mmapstring::*;
use mmime::other::*;
use num_traits::FromPrimitive;
use rand::{thread_rng, Rng};
use crate::chat;
@@ -25,12 +22,48 @@ use crate::pgp::*;
use crate::sql::{self, Sql};
use crate::stock::StockMessage;
// import/export and tools
// param1 is a directory where the keys are written to
// param1 is a directory where the keys are searched in and read from
// param1 is a directory where the backup is written to
// param1 is the file with the backup to import
pub fn dc_imex(context: &Context, what: libc::c_int, param1: Option<impl AsRef<Path>>) {
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
#[repr(i32)]
pub enum ImexMode {
/// Export all private keys and all public keys of the user to the
/// directory given as `param1`. The default key is written to the files `public-key-default.asc`
/// and `private-key-default.asc`, if there are more keys, they are written to files as
/// `public-key-<id>.asc` and `private-key-<id>.asc`
ExportSelfKeys = 1,
/// Import private keys found in the directory given as `param1`.
/// The last imported key is made the default keys unless its name contains the string `legacy`.
/// Public keys are not imported.
ImportSelfKeys = 2,
/// Export a backup to the directory given as `param1`.
/// The backup contains all contacts, chats, images and other data and device independent settings.
/// The backup does not contain device dependent settings as ringtones or LED notification settings.
/// The name of the backup is typically `delta-chat.<day>.bak`, if more than one backup is create on a day,
/// the format is `delta-chat.<day>-<number>.bak`
ExportBackup = 11,
/// `param1` is the file (not: directory) to import. The file is normally
/// created by DC_IMEX_EXPORT_BACKUP and detected by dc_imex_has_backup(). Importing a backup
/// is only possible as long as the context is not configured or used in another way.
ImportBackup = 12,
}
/// Import/export things.
/// For this purpose, the function creates a job that is executed in the IMAP-thread then;
/// this requires to call dc_perform_imap_jobs() regularly.
///
/// What to do is defined by the _what_ parameter.
///
/// While dc_imex() returns immediately, the started job may take a while,
/// you can stop it using dc_stop_ongoing_process(). During execution of the job,
/// some events are sent out:
///
/// - A number of #DC_EVENT_IMEX_PROGRESS events are sent and may be used to create
/// a progress bar or stuff like that. Moreover, you'll be informed when the imex-job is done.
///
/// - For each file written on export, the function sends #DC_EVENT_IMEX_FILE_WRITTEN
///
/// Only one import-/export-progress can run at the same time.
/// To cancel an import-/export-progress, use dc_stop_ongoing_process().
pub fn imex(context: &Context, what: ImexMode, param1: Option<impl AsRef<Path>>) {
let mut param = Params::new();
param.set_int(Param::Cmd, what as i32);
if let Some(param1) = param1 {
@@ -42,7 +75,7 @@ pub fn dc_imex(context: &Context, what: libc::c_int, param1: Option<impl AsRef<P
}
/// Returns the filename of the backup if found, nullptr otherwise.
pub fn dc_imex_has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<String> {
pub fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<String> {
let dir_name = dir_name.as_ref();
let dir_iter = std::fs::read_dir(dir_name)?;
let mut newest_backup_time = 0;
@@ -75,10 +108,10 @@ pub fn dc_imex_has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Resu
}
}
pub fn dc_initiate_key_transfer(context: &Context) -> Result<String> {
pub fn initiate_key_transfer(context: &Context) -> Result<String> {
let mut msg: Message;
ensure!(dc_alloc_ongoing(context), "could not allocate ongoing");
let setup_code = dc_create_setup_code(context);
let setup_code = create_setup_code(context);
/* this may require a keypair to be created. this may take a second ... */
if !context
.running_state
@@ -87,7 +120,7 @@ pub fn dc_initiate_key_transfer(context: &Context) -> Result<String> {
.unwrap()
.shall_stop_ongoing
{
if let Ok(ref setup_file_content) = dc_render_setup_file(context, &setup_code) {
if let Ok(ref setup_file_content) = render_setup_file(context, &setup_code) {
/* encrypting may also take a while ... */
if !context
.running_state
@@ -153,7 +186,7 @@ pub fn dc_initiate_key_transfer(context: &Context) -> Result<String> {
/// Renders HTML body of a setup file message.
///
/// The `passphrase` must be at least 2 characters long.
pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result<String> {
pub fn render_setup_file(context: &Context, passphrase: &str) -> Result<String> {
ensure!(
passphrase.len() >= 2,
"Passphrase must be at least 2 chars long."
@@ -203,7 +236,7 @@ pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result<Strin
))
}
pub fn dc_create_setup_code(_context: &Context) -> String {
pub fn create_setup_code(_context: &Context) -> String {
let mut random_val: u16;
let mut rng = thread_rng();
let mut ret = String::new();
@@ -211,22 +244,22 @@ pub fn dc_create_setup_code(_context: &Context) -> String {
for i in 0..9 {
loop {
random_val = rng.gen();
if !(random_val as libc::c_int > 60000) {
if !(random_val as usize > 60000) {
break;
}
}
random_val = (random_val as libc::c_int % 10000) as u16;
random_val = (random_val as usize % 10000) as u16;
ret += &format!(
"{}{:04}",
if 0 != i { "-" } else { "" },
random_val as libc::c_int,
random_val as usize
);
}
ret
}
pub fn dc_continue_key_transfer(context: &Context, msg_id: u32, setup_code: &str) -> Result<()> {
pub fn continue_key_transfer(context: &Context, msg_id: u32, setup_code: &str) -> Result<()> {
ensure!(msg_id > DC_MSG_ID_LAST_SPECIAL, "wrong id");
let msg = Message::load_from_db(context, msg_id);
@@ -240,17 +273,14 @@ pub fn dc_continue_key_transfer(context: &Context, msg_id: u32, setup_code: &str
);
if let Some(filename) = msg.get_file(context) {
if let Ok(buf) = dc_read_file(context, filename) {
let norm_sc = CString::yolo(dc_normalize_setup_code(setup_code));
unsafe {
if let Ok(armored_key) =
dc_decrypt_setup_file(context, norm_sc.as_ptr(), buf.as_ptr().cast())
{
set_self_key(context, &armored_key, true, true)?;
} else {
bail!("Bad setup code.")
}
if let Ok(ref mut buf) = dc_read_file(context, filename) {
let sc = normalize_setup_code(setup_code);
if let Ok(armored_key) = decrypt_setup_file(context, sc, buf) {
set_self_key(context, &armored_key, true, true)?;
} else {
bail!("Bad setup code.")
}
Ok(())
} else {
bail!("Cannot read Autocrypt Setup Message file.");
@@ -320,7 +350,7 @@ fn set_self_key(
&public_key,
&private_key,
self_addr.unwrap(),
set_default as libc::c_int,
set_default,
&context.sql,
) {
bail!("Cannot save keypair, internal key-state possibly corrupted now!");
@@ -328,65 +358,56 @@ fn set_self_key(
Ok(())
}
pub unsafe fn dc_decrypt_setup_file(
context: &Context,
passphrase: *const libc::c_char,
filecontent: *const libc::c_char,
fn decrypt_setup_file(
_context: &Context,
passphrase: impl AsRef<str>,
filecontent: &mut [u8],
) -> Result<String> {
let fc_buf: *mut libc::c_char;
let mut fc_headerline = String::default();
let mut fc_base64: *const libc::c_char = ptr::null();
let mut binary: *mut libc::c_char = ptr::null_mut();
let mut binary_bytes: libc::size_t = 0;
let mut indx: libc::size_t = 0;
let mut payload: Result<String> = Err(format_err!("Failed to decrypt"));
let split_result = unsafe {
dc_split_armored_data(
filecontent.as_mut_ptr().cast(),
&mut fc_headerline,
ptr::null_mut(),
ptr::null_mut(),
&mut fc_base64,
)
};
fc_buf = dc_strdup(filecontent);
if dc_split_armored_data(
fc_buf,
&mut fc_headerline,
ptr::null_mut(),
ptr::null_mut(),
&mut fc_base64,
) && fc_headerline == "-----BEGIN PGP MESSAGE-----"
&& !fc_base64.is_null()
{
/* convert base64 to binary */
/*must be freed using mmap_string_unref()*/
if !(mailmime_base64_body_parse(
fc_base64,
strlen(fc_base64),
&mut indx,
&mut binary,
&mut binary_bytes,
) != MAILIMF_NO_ERROR as libc::c_int
|| binary.is_null()
|| binary_bytes == 0)
{
/* decrypt symmetrically */
match dc_pgp_symm_decrypt(
as_str(passphrase),
std::slice::from_raw_parts(binary as *const u8, binary_bytes),
) {
Ok(plain) => payload = Ok(String::from_utf8(plain).unwrap()),
Err(err) => {
error!(context, "Failed to decrypt message: {:?}", err);
payload = Err(err);
}
}
}
if !split_result || fc_headerline != "-----BEGIN PGP MESSAGE-----" || fc_base64.is_null() {
bail!("Invalid armored data");
}
free(fc_buf as *mut libc::c_void);
if !binary.is_null() {
mmap_string_unref(binary);
}
// convert base64 to binary
let base64_encoded =
unsafe { std::slice::from_raw_parts(fc_base64 as *const u8, libc::strlen(fc_base64)) };
payload
let data = base64_decode(&base64_encoded)?;
// decrypt symmetrically
let payload = dc_pgp_symm_decrypt(passphrase.as_ref(), &data)?;
let payload_str = String::from_utf8(payload)?;
Ok(payload_str)
}
pub fn dc_normalize_setup_code(s: &str) -> String {
/// Decode the base64 encoded slice. Handles line breaks.
fn base64_decode(input: &[u8]) -> Result<Vec<u8>> {
use std::io::Read;
let c = std::io::Cursor::new(input);
let lr = pgp::line_reader::LineReader::new(c);
let br = pgp::base64_reader::Base64Reader::new(lr);
let mut reader = pgp::base64_decoder::Base64Decoder::new(br);
let mut data = Vec::new();
reader.read_to_end(&mut data)?;
Ok(data)
}
pub fn normalize_setup_code(s: &str) -> String {
let mut out = String::new();
for c in s.chars() {
if c >= '0' && c <= '9' {
@@ -400,9 +421,9 @@ pub fn dc_normalize_setup_code(s: &str) -> String {
}
#[allow(non_snake_case)]
pub fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
pub fn job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
ensure!(dc_alloc_ongoing(context), "could not allocate ongoing");
let what = job.param.get_int(Param::Cmd).unwrap_or_default();
let what: Option<ImexMode> = job.param.get_int(Param::Cmd).and_then(ImexMode::from_i32);
let param = job.param.get(Param::Arg).unwrap_or_default();
ensure!(!param.is_empty(), "No Import/export dir/file given.");
@@ -410,8 +431,8 @@ pub fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
context.call_cb(Event::ImexProgress(10));
ensure!(context.sql.is_open(), "Database not opened.");
if what == DC_IMEX_EXPORT_BACKUP || what == DC_IMEX_EXPORT_SELF_KEYS {
/* before we export anything, make sure the private key exists */
if what == Some(ImexMode::ExportBackup) || what == Some(ImexMode::ExportSelfKeys) {
// before we export anything, make sure the private key exists
if e2ee::ensure_secret_key_exists(context).is_err() {
dc_free_ongoing(context);
bail!("Cannot create private key or private key not available.");
@@ -421,12 +442,12 @@ pub fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
}
let path = Path::new(param);
let success = match what {
DC_IMEX_EXPORT_SELF_KEYS => export_self_keys(context, path),
DC_IMEX_IMPORT_SELF_KEYS => import_self_keys(context, path),
DC_IMEX_EXPORT_BACKUP => unsafe { export_backup(context, path) },
DC_IMEX_IMPORT_BACKUP => import_backup(context, path),
_ => {
bail!("unknown IMEX type: {}", what);
Some(ImexMode::ExportSelfKeys) => export_self_keys(context, path),
Some(ImexMode::ImportSelfKeys) => import_self_keys(context, path),
Some(ImexMode::ExportBackup) => export_backup(context, path),
Some(ImexMode::ImportBackup) => import_backup(context, path),
None => {
bail!("unknown IMEX type");
}
};
dc_free_ongoing(context);
@@ -443,11 +464,7 @@ pub fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
}
}
/*******************************************************************************
* Import backup
******************************************************************************/
#[allow(non_snake_case)]
/// Import Backup
fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) -> Result<()> {
info!(
context,
@@ -523,13 +540,13 @@ fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) -> Resul
continue;
}
let pathNfilename = context.get_blobdir().join(file_name);
if dc_write_file(context, &pathNfilename, &file_blob) {
let path_filename = context.get_blobdir().join(file_name);
if dc_write_file(context, &path_filename, &file_blob) {
continue;
}
bail!(
"Storage full? Cannot write file {} with {} bytes.",
pathNfilename.display(),
path_filename.display(),
file_blob.len(),
);
}
@@ -550,8 +567,7 @@ fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) -> Resul
******************************************************************************/
/* the FILE_PROGRESS macro calls the callback with the permille of files processed.
The macro avoids weird values of 0% or 100% while still working. */
#[allow(non_snake_case)]
unsafe fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
let mut ok_to_continue = true;
let mut success = false;
@@ -650,9 +666,9 @@ unsafe fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()>
continue;
} else {
info!(context, "EXPORTing filename={}", name);
let curr_pathNfilename = context.get_blobdir().join(entry.file_name());
let curr_path_filename = context.get_blobdir().join(entry.file_name());
if let Ok(buf) =
dc_read_file(context, &curr_pathNfilename)
dc_read_file(context, &curr_path_filename)
{
if buf.is_empty() {
continue;
@@ -661,7 +677,7 @@ unsafe fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()>
error!(
context,
"Disk full? Cannot add file \"{}\" to backup.",
curr_pathNfilename.display(),
curr_path_filename.display(),
);
/* this is not recoverable! writing to the sqlite database should work! */
ok_to_continue = false;
@@ -773,7 +789,7 @@ fn import_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
ptr::null_mut(),
ptr::null_mut(),
);
free(buf2 as *mut libc::c_void);
libc::free(buf2 as *mut libc::c_void);
}
if split_res
&& buf2_headerline.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----")
@@ -884,7 +900,7 @@ mod tests {
let t = test_context(Some(Box::new(logging_cb)));
configure_alice_keypair(&t.ctx);
let msg = dc_render_setup_file(&t.ctx, "hello").unwrap();
let msg = render_setup_file(&t.ctx, "hello").unwrap();
println!("{}", &msg);
// Check some substrings, indicating things got substituted.
// In particular note the mixing of `\r\n` and `\n` depending
@@ -910,10 +926,10 @@ mod tests {
}
#[test]
fn test_render_setup_file_newline_replace() {
fn otest_render_setup_file_newline_replace() {
let t = test_context(Some(Box::new(ac_setup_msg_cb)));
configure_alice_keypair(&t.ctx);
let msg = dc_render_setup_file(&t.ctx, "pw").unwrap();
let msg = render_setup_file(&t.ctx, "pw").unwrap();
println!("{}", &msg);
assert!(msg.contains("<p>hello<br>there</p>"));
}
@@ -921,7 +937,7 @@ mod tests {
#[test]
fn test_create_setup_code() {
let t = dummy_context();
let setupcode = dc_create_setup_code(&t.ctx);
let setupcode = create_setup_code(&t.ctx);
assert_eq!(setupcode.len(), 44);
assert_eq!(setupcode.chars().nth(4).unwrap(), '-');
assert_eq!(setupcode.chars().nth(9).unwrap(), '-');
@@ -949,12 +965,65 @@ mod tests {
#[test]
fn test_normalize_setup_code() {
let norm = dc_normalize_setup_code("123422343234423452346234723482349234");
let norm = normalize_setup_code("123422343234423452346234723482349234");
assert_eq!(norm, "1234-2234-3234-4234-5234-6234-7234-8234-9234");
let norm = dc_normalize_setup_code(
"\t1 2 3422343234- foo bar-- 423-45 2 34 6234723482349234 ",
);
let norm =
normalize_setup_code("\t1 2 3422343234- foo bar-- 423-45 2 34 6234723482349234 ");
assert_eq!(norm, "1234-2234-3234-4234-5234-6234-7234-8234-9234");
}
/* S_EM_SETUPFILE is a AES-256 symm. encrypted setup message created by Enigmail
with an "encrypted session key", see RFC 4880. The code is in S_EM_SETUPCODE */
const S_EM_SETUPCODE: &str = "1742-0185-6197-1303-7016-8412-3581-4441-0597";
const S_EM_SETUPFILE: &str = include_str!("../test-data/message/stress.txt");
#[test]
fn test_split_and_decrypt() {
let ctx = dummy_context();
let context = &ctx.ctx;
let mut headerline = String::default();
let mut setupcodebegin = ptr::null();
let mut preferencrypt = ptr::null();
let mut buf_1 = S_EM_SETUPFILE.to_string();
unsafe {
assert!(dc_split_armored_data(
buf_1.as_mut_ptr().cast(),
&mut headerline,
&mut setupcodebegin,
&mut preferencrypt,
ptr::null_mut(),
));
}
assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----");
assert!(!setupcodebegin.is_null());
// TODO: verify that this is the right check
assert!(S_EM_SETUPCODE.starts_with(as_str(setupcodebegin)));
assert!(preferencrypt.is_null());
let mut setup_file = S_EM_SETUPFILE.to_string();
let mut decrypted = unsafe {
decrypt_setup_file(context, S_EM_SETUPCODE, setup_file.as_bytes_mut()).unwrap()
};
unsafe {
assert!(dc_split_armored_data(
decrypted.as_mut_ptr().cast(),
&mut headerline,
&mut setupcodebegin,
&mut preferencrypt,
ptr::null_mut(),
));
}
assert_eq!(headerline, "-----BEGIN PGP PRIVATE KEY BLOCK-----");
assert!(setupcodebegin.is_null());
assert!(!preferencrypt.is_null());
assert_eq!(as_str(preferencrypt), "mutual",);
}
}

View File

@@ -7,10 +7,10 @@ use crate::chat;
use crate::configure::*;
use crate::constants::*;
use crate::context::Context;
use crate::dc_imex::*;
use crate::dc_tools::*;
use crate::events::Event;
use crate::imap::*;
use crate::imex::*;
use crate::location;
use crate::login_param::LoginParam;
use crate::message::{self, Message, MessageState};
@@ -824,7 +824,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
Action::MoveMsg => job.do_DC_JOB_MOVE_MSG(context),
Action::SendMdn => job.do_DC_JOB_SEND(context),
Action::ConfigureImap => unsafe { dc_job_do_DC_JOB_CONFIGURE_IMAP(context) },
Action::ImexImap => match dc_job_do_DC_JOB_IMEX_IMAP(context, &job) {
Action::ImexImap => match job_do_DC_JOB_IMEX_IMAP(context, &job) {
Ok(()) => {}
Err(err) => {
error!(context, "{}", err);

View File

@@ -2,7 +2,6 @@ use std::collections::BTreeMap;
use std::io::Cursor;
use std::path::Path;
use libc;
use pgp::composed::{Deserializable, SignedPublicKey, SignedSecretKey};
use pgp::ser::Serialize;
use pgp::types::{KeyTrait, SecretKeyTrait};
@@ -254,14 +253,14 @@ pub fn dc_key_save_self_keypair(
public_key: &Key,
private_key: &Key,
addr: impl AsRef<str>,
is_default: libc::c_int,
is_default: bool,
sql: &Sql,
) -> bool {
sql::execute(
context,
sql,
"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);",
params![addr.as_ref(), is_default, public_key.to_bytes(), private_key.to_bytes(), time()],
params![addr.as_ref(), is_default as i32, public_key.to_bytes(), private_key.to_bytes(), time()],
).is_ok()
}

View File

@@ -39,36 +39,36 @@ pub mod contact;
pub mod context;
mod e2ee;
mod imap;
pub mod imex;
pub mod job;
mod job_thread;
pub mod key;
pub mod keyring;
pub mod location;
mod login_param;
pub mod lot;
pub mod message;
mod mimefactory;
pub mod oauth2;
mod param;
pub mod peerstate;
pub mod pgp;
pub mod qr;
pub mod securejoin;
mod smtp;
pub mod sql;
mod stock;
mod token;
#[macro_use]
mod wrapmime;
pub mod dc_array;
mod dc_dehtml;
pub mod dc_imex;
pub mod dc_mimeparser;
pub mod dc_receive_imf;
mod dc_simplify;
mod dc_strencode;
pub mod dc_tools;
mod login_param;
mod mimefactory;
pub mod securejoin;
mod token;
#[macro_use]
mod wrapmime;
#[cfg(test)]
mod test_utils;

View File

@@ -153,7 +153,7 @@ impl<'a> MimeFactory<'a> {
/* create basic mail
*************************************************************************/
let from: *mut mailimf_mailbox_list = mailimf_mailbox_list_new_empty();
let from = mailimf_mailbox_list_new_empty();
mailimf_mailbox_list_add(
from,
mailimf_mailbox_new(
@@ -165,7 +165,7 @@ impl<'a> MimeFactory<'a> {
self.from_addr.strdup(),
),
);
let mut to: *mut mailimf_address_list = ptr::null_mut();
let mut to = ptr::null_mut();
if !self.recipients_names.is_empty() && !self.recipients_addr.is_empty() {
to = mailimf_address_list_new_empty();
let name_iter = self.recipients_names.iter();
@@ -173,31 +173,21 @@ impl<'a> MimeFactory<'a> {
for (name, addr) in name_iter.zip(addr_iter) {
mailimf_address_list_add(
to,
mailimf_address_new(
MAILIMF_ADDRESS_MAILBOX as libc::c_int,
mailimf_mailbox_new(
if !name.is_empty() {
dc_encode_header_words(&name).strdup()
} else {
ptr::null_mut()
},
addr.strdup(),
),
ptr::null_mut(),
),
mailimf_address_new_mailbox(mailimf_mailbox_new(
if !name.is_empty() {
dc_encode_header_words(&name).strdup()
} else {
ptr::null_mut()
},
addr.strdup(),
)),
);
}
}
let references_list = if !self.references.is_empty() {
dc_str_to_clist(&self.references, " ")
} else {
ptr::null_mut()
};
let in_reply_to_list = if !self.in_reply_to.is_empty() {
dc_str_to_clist(&self.in_reply_to, " ")
} else {
ptr::null_mut()
};
let references_list = dc_str_to_vec(&self.references, " ");
let in_reply_to_list = dc_str_to_vec(&self.in_reply_to, " ");
let imf_fields = mailimf_fields_new_with_data_all(
mailimf_get_date(self.timestamp as i64),
from,
@@ -617,31 +607,9 @@ impl<'a> MimeFactory<'a> {
mailimf_fields_add(
imf_fields,
mailimf_field_new(
MAILIMF_FIELD_SUBJECT as libc::c_int,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
mailimf_subject_new(dc_encode_header_words(subject_str).strdup()),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
),
mailimf_field::Subject(mailimf_subject_new(
dc_encode_header_words(subject_str).strdup(),
)),
);
/*just a pointer into mailmime structure, must not be freed*/

View File

@@ -413,7 +413,7 @@ pub fn handle_securejoin_handshake(
could_not_establish_secure_connection(
context,
contact_chat_id,
if mimeparser.e2ee_helper.encrypted {
if mimeparser.encrypted {
"No valid signature."
} else {
"Not encrypted."
@@ -693,17 +693,16 @@ fn mark_peer_as_verified(context: &Context, fingerprint: impl AsRef<str>) -> Res
******************************************************************************/
fn encrypted_and_signed(mimeparser: &MimeParser, expected_fingerprint: impl AsRef<str>) -> bool {
if !mimeparser.e2ee_helper.encrypted {
if !mimeparser.encrypted {
warn!(mimeparser.context, "Message not encrypted.",);
false
} else if mimeparser.e2ee_helper.signatures.len() <= 0 {
} else if mimeparser.signatures.len() <= 0 {
warn!(mimeparser.context, "Message not signed.",);
false
} else if expected_fingerprint.as_ref().is_empty() {
warn!(mimeparser.context, "Fingerprint for comparison missing.",);
false
} else if !mimeparser
.e2ee_helper
.signatures
.contains(expected_fingerprint.as_ref())
{
@@ -718,21 +717,24 @@ fn encrypted_and_signed(mimeparser: &MimeParser, expected_fingerprint: impl AsRe
}
}
pub fn handle_degrade_event(context: &Context, peerstate: &Peerstate) {
pub fn handle_degrade_event(context: &Context, peerstate: &Peerstate) -> Result<(), Error> {
// - we do not issue an warning for DC_DE_ENCRYPTION_PAUSED as this is quite normal
// - currently, we do not issue an extra warning for DC_DE_VERIFICATION_LOST - this always comes
// together with DC_DE_FINGERPRINT_CHANGED which is logged, the idea is not to bother
// with things they cannot fix, so the user is just kicked from the verified group
// (and he will know this and can fix this)
if Some(DegradeEvent::FingerprintChanged) == peerstate.degrade_event {
let contact_id: i32 = context
.sql
.query_get_value(
context,
"SELECT id FROM contacts WHERE addr=?;",
params![&peerstate.addr],
)
.unwrap_or_default();
let contact_id: i32 = match context.sql.query_get_value(
context,
"SELECT id FROM contacts WHERE addr=?;",
params![&peerstate.addr],
) {
None => bail!(
"contact with peerstate.addr {:?} not found",
&peerstate.addr
),
Some(contact_id) => contact_id,
};
if contact_id > 0 {
let (contact_chat_id, _) =
chat::create_or_lookup_by_contact_id(context, contact_id as u32, Blocked::Deaddrop)
@@ -748,4 +750,5 @@ pub fn handle_degrade_event(context: &Context, peerstate: &Peerstate) {
emit_event!(context, Event::ChatModified(contact_chat_id));
}
}
Ok(())
}

View File

@@ -76,7 +76,7 @@ pub fn configure_alice_keypair(ctx: &Context) -> String {
KeyType::Private,
)
.unwrap();
let saved = key::dc_key_save_self_keypair(&ctx, &public, &private, &addr, 1, &ctx.sql);
let saved = key::dc_key_save_self_keypair(&ctx, &public, &private, &addr, true, &ctx.sql);
assert_eq!(saved, true, "Failed to save Alice's key");
addr
}

View File

@@ -36,7 +36,6 @@ pub fn get_ct_subtype(mime: *mut Mailmime) -> Option<String> {
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
@@ -48,10 +47,12 @@ pub fn get_autocrypt_mime(
mime_undetermined: *mut Mailmime,
) -> Result<(*mut Mailmime, *mut Mailmime), Error> {
/* return Result with two mime pointers:
First mime pointer is to the multipart-mime message
(which is replaced with a decrypted version later)
Second one is to the encrypted payload.
For non-autocrypt message an Error is returned.
First mime pointer is to the multipart-mime message
(which is replaced with a decrypted version later)
Second one is to the encrypted payload.
For non-autocrypt message an Error is returned.
*/
unsafe {
ensure!(
@@ -179,11 +180,7 @@ pub fn add_filename_part(
pub fn new_custom_field(fields: *mut mailimf_fields, name: &str, value: &str) {
unsafe {
let field = mailimf_field_new_custom(name.strdup(), value.strdup());
let res = mailimf_fields_add(fields, field);
assert!(
res as u32 == MAILIMF_NO_ERROR,
"could not create mailimf field"
);
mailimf_fields_add(fields, field);
}
}

View File

@@ -0,0 +1,125 @@
-----BEGIN PGP MESSAGE-----
Passphrase-Format: numeric9x4
Passphrase-Begin: 17
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
mngm1QCMMw2v/j8=
=9sJE
-----END PGP MESSAGE-----

File diff suppressed because one or more lines are too long