mirror of
https://github.com/chatmail/core.git
synced 2026-04-05 23:22:11 +03:00
Compare commits
5 Commits
1.0.0-beta
...
local_hpk_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0be33eafb1 | ||
|
|
5d47d25c1e | ||
|
|
e4f9446e3c | ||
|
|
abbbd0cb67 | ||
|
|
ae9f52e001 |
@@ -120,6 +120,8 @@ def acfactory(pytestconfig, tmpdir, request):
|
||||
pytest.skip("specify a --liveconfig file to run tests with real accounts")
|
||||
self.live_count += 1
|
||||
configdict = self.configlist.pop(0)
|
||||
if "e2ee_enabled" not in configdict:
|
||||
configdict["e2ee_enabled"] = "1"
|
||||
tmpdb = tmpdir.join("livedb%d" % self.live_count)
|
||||
ac = Account(tmpdb.strpath, logid="ac{}".format(self.live_count))
|
||||
ac._evlogger.init_time = self.init_time
|
||||
|
||||
@@ -421,10 +421,43 @@ class TestOnlineAccount:
|
||||
lp.sec("mark message as seen on ac2, wait for changes on ac1")
|
||||
ac2.mark_seen_messages([msg_in])
|
||||
lp.step("1")
|
||||
ac1._evlogger.get_matching("DC_EVENT_MSG_READ")
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_MSG_READ")
|
||||
assert ev[1] >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert ev[2] >= const.DC_MSG_ID_LAST_SPECIAL
|
||||
lp.step("2")
|
||||
assert msg_out.is_out_mdn_received()
|
||||
|
||||
def test_send_and_receive_will_encrypt_decrypt(self, acfactory, lp):
|
||||
lp.sec("starting accounts, waiting for configuration")
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
ac2 = acfactory.get_online_configuring_account()
|
||||
c2 = ac1.create_contact(email=ac2.get_config("addr"))
|
||||
chat = ac1.create_chat_by_contact(c2)
|
||||
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
|
||||
wait_configuration_progress(ac1, 1000)
|
||||
wait_configuration_progress(ac2, 1000)
|
||||
|
||||
lp.sec("sending text message from ac1 to ac2")
|
||||
msg_out = chat.send_text("message1")
|
||||
|
||||
lp.sec("wait for ac2 to receive message")
|
||||
ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||
assert ev[2] == msg_out.id
|
||||
msg_in = ac2.get_message_by_id(msg_out.id)
|
||||
assert msg_in.text == "message1"
|
||||
|
||||
lp.sec("create new chat with contact and send back (encrypted) message")
|
||||
chat2b = ac2.create_chat_by_message(msg_in)
|
||||
chat2b.send_text("message-back")
|
||||
|
||||
lp.sec("wait for ac1 to receive message")
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
|
||||
assert ev[1] == chat.id
|
||||
assert ev[2] > msg_out.id
|
||||
msg_back = ac1.get_message_by_id(ev[2])
|
||||
assert msg_back.text == "message-back"
|
||||
|
||||
def test_saved_mime_on_received_message(self, acfactory, lp):
|
||||
lp.sec("starting accounts, waiting for configuration")
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
|
||||
@@ -11,7 +11,7 @@ lazy_static! {
|
||||
struct Dehtml {
|
||||
strbuilder: String,
|
||||
add_text: AddText,
|
||||
last_href: *mut libc::c_char,
|
||||
last_href: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -32,7 +32,7 @@ pub unsafe fn dc_dehtml(buf_terminated: *mut libc::c_char) -> *mut libc::c_char
|
||||
let mut dehtml = Dehtml {
|
||||
strbuilder: String::with_capacity(strlen(buf_terminated)),
|
||||
add_text: AddText::YesRemoveLineEnds,
|
||||
last_href: 0 as *mut libc::c_char,
|
||||
last_href: None,
|
||||
};
|
||||
let mut saxparser = dc_saxparser_t {
|
||||
starttag_cb: None,
|
||||
@@ -51,7 +51,6 @@ pub unsafe fn dc_dehtml(buf_terminated: *mut libc::c_char) -> *mut libc::c_char
|
||||
);
|
||||
dc_saxparser_set_text_handler(&mut saxparser, Some(dehtml_text_cb));
|
||||
dc_saxparser_parse(&mut saxparser, buf_terminated);
|
||||
free(dehtml.last_href as *mut libc::c_void);
|
||||
|
||||
dehtml.strbuilder.strdup()
|
||||
}
|
||||
@@ -66,7 +65,11 @@ unsafe fn dehtml_text_cb(
|
||||
if dehtml.add_text == AddText::YesPreserveLineEnds
|
||||
|| dehtml.add_text == AddText::YesRemoveLineEnds
|
||||
{
|
||||
let last_added = std::ffi::CStr::from_ptr(text).to_string_lossy();
|
||||
let last_added = std::ffi::CStr::from_ptr(text)
|
||||
.to_str()
|
||||
.expect("invalid utf8");
|
||||
// TODO: why does len does not match?
|
||||
// assert_eq!(last_added.len(), len as usize);
|
||||
|
||||
if dehtml.add_text == AddText::YesRemoveLineEnds {
|
||||
dehtml.strbuilder += LINE_RE.replace_all(last_added.as_ref(), "\r").as_ref();
|
||||
@@ -86,14 +89,10 @@ unsafe fn dehtml_endtag_cb(userdata: *mut libc::c_void, tag: *const libc::c_char
|
||||
dehtml.add_text = AddText::YesRemoveLineEnds;
|
||||
}
|
||||
"a" => {
|
||||
if !dehtml.last_href.is_null() {
|
||||
if let Some(ref last_href) = dehtml.last_href.take() {
|
||||
dehtml.strbuilder += "](";
|
||||
dehtml.strbuilder += std::ffi::CStr::from_ptr((*dehtml).last_href)
|
||||
.to_string_lossy()
|
||||
.as_ref();
|
||||
dehtml.strbuilder += last_href;
|
||||
dehtml.strbuilder += ")";
|
||||
free(dehtml.last_href as *mut libc::c_void);
|
||||
dehtml.last_href = 0 as *mut libc::c_char;
|
||||
}
|
||||
}
|
||||
"b" | "strong" => {
|
||||
@@ -131,12 +130,13 @@ unsafe fn dehtml_starttag_cb(
|
||||
dehtml.add_text = AddText::YesPreserveLineEnds;
|
||||
}
|
||||
"a" => {
|
||||
free(dehtml.last_href as *mut libc::c_void);
|
||||
dehtml.last_href = dc_strdup_keep_null(dc_attr_find(
|
||||
let text_c = std::ffi::CStr::from_ptr(dc_attr_find(
|
||||
attr,
|
||||
b"href\x00" as *const u8 as *const libc::c_char,
|
||||
));
|
||||
if !dehtml.last_href.is_null() {
|
||||
let text_r = text_c.to_str().expect("invalid utf8");
|
||||
if !text_r.is_empty() {
|
||||
dehtml.last_href = Some(text_r.to_string());
|
||||
dehtml.strbuilder += "[";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,11 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
let mut peerstates: Vec<Peerstate> = Vec::new();
|
||||
*helper = Default::default();
|
||||
|
||||
info!(
|
||||
context,
|
||||
0, "dc_e2ee_encrypt guaruanteed={}", e2ee_guaranteed
|
||||
);
|
||||
|
||||
if !(recipients_addr.is_null()
|
||||
|| in_out_message.is_null()
|
||||
|| !(*in_out_message).mm_parent.is_null()
|
||||
@@ -106,6 +111,10 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
iter1 = (*recipients_addr).first;
|
||||
while !iter1.is_null() {
|
||||
let recipient_addr = to_string((*iter1).data as *const libc::c_char);
|
||||
info!(
|
||||
context,
|
||||
0, "dc_e2ee_encrypt recipient_addr {}", recipient_addr
|
||||
);
|
||||
if recipient_addr != addr {
|
||||
let peerstate =
|
||||
Peerstate::from_addr(context, &context.sql, &recipient_addr);
|
||||
@@ -115,11 +124,22 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
|| 0 != e2ee_guaranteed)
|
||||
{
|
||||
let peerstate = peerstate.unwrap();
|
||||
info!(
|
||||
context,
|
||||
0, "dc_e2ee_encrypt {} has peerstate", recipient_addr
|
||||
);
|
||||
if let Some(key) = peerstate.peek_key(min_verified as usize) {
|
||||
keyring.add_owned(key.clone());
|
||||
peerstates.push(peerstate);
|
||||
}
|
||||
} else {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"dc_e2ee_encrypt {} HAS NO peerstate {}",
|
||||
recipient_addr,
|
||||
peerstate.is_some()
|
||||
);
|
||||
do_encrypt = 0i32;
|
||||
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
|
||||
break;
|
||||
@@ -293,7 +313,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
) {
|
||||
let ctext_bytes = ctext_v.len();
|
||||
let ctext = ctext_v.strdup();
|
||||
(*helper).cdata_to_free = ctext as *mut _;
|
||||
helper.cdata_to_free = ctext as *mut _;
|
||||
|
||||
/* create MIME-structure that will contain the encrypted text */
|
||||
let mut encrypted_part: *mut mailmime = new_data_part(
|
||||
@@ -339,7 +359,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
(*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part;
|
||||
(*encrypted_part).mm_parent = in_out_message;
|
||||
mailmime_free(message_to_encrypt);
|
||||
(*helper).encryption_successfull = 1i32;
|
||||
helper.encryption_successfull = 1i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -574,7 +594,8 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
}
|
||||
} else if let Some(ref header) = autocryptheader {
|
||||
let p = Peerstate::from_header(context, header, message_time);
|
||||
p.save_to_db(&context.sql, true);
|
||||
info!(context, 0, "setting peerstate from header for {:?}", p.addr);
|
||||
assert!(p.save_to_db(&context.sql, true));
|
||||
peerstate = Some(p);
|
||||
}
|
||||
}
|
||||
@@ -926,6 +947,7 @@ unsafe fn decrypt_part(
|
||||
*ret_decrypted_mime = decrypted_mime;
|
||||
sth_decrypted = 1i32
|
||||
}
|
||||
std::mem::forget(plain);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1055,3 +1077,69 @@ pub unsafe fn dc_ensure_secret_key_exists(context: &Context) -> libc::c_int {
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_mailmime_parse() {
|
||||
let plain = b"Chat-Disposition-Notification-To: holger@deltachat.de
|
||||
Chat-Group-ID: CovhGgau8M-
|
||||
Chat-Group-Name: Delta Chat Dev
|
||||
Subject: =?utf-8?Q?Chat=3A?= Delta Chat =?utf-8?Q?Dev=3A?= sidenote for
|
||||
=?utf-8?Q?all=3A?= rust core master ...
|
||||
Content-Type: text/plain; charset=\"utf-8\"; protected-headers=\"v1\"
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
sidenote for all: rust core master is broken currently ... so dont recomm=
|
||||
end to try to run with desktop or ios unless you are ready to hunt bugs
|
||||
|
||||
-- =20
|
||||
Sent with my Delta Chat Messenger: https://delta.chat";
|
||||
let plain_bytes = plain.len();
|
||||
let plain_buf = plain.as_ptr() as *const libc::c_char;
|
||||
|
||||
let mut index = 0;
|
||||
let mut decrypted_mime = std::ptr::null_mut();
|
||||
|
||||
let res = unsafe {
|
||||
mailmime_parse(
|
||||
plain_buf as *const _,
|
||||
plain_bytes,
|
||||
&mut index,
|
||||
&mut decrypted_mime,
|
||||
)
|
||||
};
|
||||
unsafe {
|
||||
let msg1 = (*decrypted_mime).mm_data.mm_message.mm_msg_mime;
|
||||
let mut decoded_data = 0 as *const libc::c_char;
|
||||
let mut decoded_data_bytes = 0;
|
||||
let mut transfer_decoding_buffer: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
|
||||
assert_eq!(
|
||||
mailmime_transfer_decode(
|
||||
msg1,
|
||||
&mut decoded_data,
|
||||
&mut decoded_data_bytes,
|
||||
&mut transfer_decoding_buffer,
|
||||
),
|
||||
1
|
||||
);
|
||||
println!(
|
||||
"{:?}",
|
||||
String::from_utf8_lossy(std::slice::from_raw_parts(
|
||||
decoded_data as *const u8,
|
||||
decoded_data_bytes as usize,
|
||||
))
|
||||
);
|
||||
|
||||
free(decoded_data as *mut _);
|
||||
}
|
||||
|
||||
assert_eq!(res, 0);
|
||||
assert!(!decrypted_mime.is_null());
|
||||
|
||||
unsafe { free(decrypted_mime as *mut _) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -786,7 +786,7 @@ unsafe fn dc_add_smtp_job(
|
||||
b"\x1e\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
param.set(Param::File, as_str(pathNfilename));
|
||||
param.set(Param::File, as_str(recipients));
|
||||
param.set(Param::Recipients, as_str(recipients));
|
||||
dc_job_add(
|
||||
context,
|
||||
action,
|
||||
|
||||
@@ -1041,6 +1041,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
&mut e2ee_helper,
|
||||
);
|
||||
}
|
||||
info!(
|
||||
(*factory).context,
|
||||
0, "encryption successful {}", e2ee_helper.encryption_successfull
|
||||
);
|
||||
|
||||
if 0 != e2ee_helper.encryption_successfull {
|
||||
(*factory).out_encrypted = 1;
|
||||
if 0 != do_gossip {
|
||||
|
||||
@@ -98,34 +98,34 @@ pub unsafe fn dc_mimeparser_empty(mimeparser: &mut dc_mimeparser_t) {
|
||||
dc_mimepart_unref(part);
|
||||
}
|
||||
assert!(mimeparser.parts.is_empty());
|
||||
(*mimeparser).header_root = 0 as *mut mailimf_fields;
|
||||
(*mimeparser).header.clear();
|
||||
if !(*mimeparser).header_protected.is_null() {
|
||||
mailimf_fields_free((*mimeparser).header_protected);
|
||||
(*mimeparser).header_protected = 0 as *mut mailimf_fields
|
||||
mimeparser.header_root = 0 as *mut mailimf_fields;
|
||||
mimeparser.header.clear();
|
||||
if !mimeparser.header_protected.is_null() {
|
||||
mailimf_fields_free(mimeparser.header_protected);
|
||||
mimeparser.header_protected = 0 as *mut mailimf_fields
|
||||
}
|
||||
(*mimeparser).is_send_by_messenger = 0i32;
|
||||
(*mimeparser).is_system_message = 0i32;
|
||||
free((*mimeparser).subject as *mut libc::c_void);
|
||||
(*mimeparser).subject = 0 as *mut libc::c_char;
|
||||
if !(*mimeparser).mimeroot.is_null() {
|
||||
mailmime_free((*mimeparser).mimeroot);
|
||||
(*mimeparser).mimeroot = 0 as *mut mailmime
|
||||
mimeparser.is_send_by_messenger = 0i32;
|
||||
mimeparser.is_system_message = 0i32;
|
||||
free(mimeparser.subject as *mut libc::c_void);
|
||||
mimeparser.subject = 0 as *mut libc::c_char;
|
||||
if !mimeparser.mimeroot.is_null() {
|
||||
mailmime_free(mimeparser.mimeroot);
|
||||
mimeparser.mimeroot = 0 as *mut mailmime
|
||||
}
|
||||
(*mimeparser).is_forwarded = 0i32;
|
||||
(*mimeparser).reports.clear();
|
||||
(*mimeparser).decrypting_failed = 0i32;
|
||||
dc_e2ee_thanks(&mut (*mimeparser).e2ee_helper);
|
||||
mimeparser.is_forwarded = 0i32;
|
||||
mimeparser.reports.clear();
|
||||
mimeparser.decrypting_failed = 0i32;
|
||||
dc_e2ee_thanks(&mut mimeparser.e2ee_helper);
|
||||
|
||||
if let Some(location_kml) = (*mimeparser).location_kml.as_mut() {
|
||||
if let Some(location_kml) = mimeparser.location_kml.as_mut() {
|
||||
dc_kml_unref(location_kml);
|
||||
}
|
||||
(*mimeparser).location_kml = None;
|
||||
mimeparser.location_kml = None;
|
||||
|
||||
if let Some(message_kml) = (*mimeparser).message_kml.as_mut() {
|
||||
if let Some(message_kml) = mimeparser.message_kml.as_mut() {
|
||||
dc_kml_unref(message_kml);
|
||||
}
|
||||
(*mimeparser).message_kml = None;
|
||||
mimeparser.message_kml = None;
|
||||
}
|
||||
|
||||
unsafe fn dc_mimepart_unref(mut mimepart: dc_mimepart_t) {
|
||||
@@ -148,19 +148,18 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
body_not_terminated,
|
||||
body_bytes,
|
||||
&mut index,
|
||||
&mut (*mimeparser).mimeroot,
|
||||
&mut mimeparser.mimeroot,
|
||||
);
|
||||
if !(r != MAILIMF_NO_ERROR as libc::c_int || (*mimeparser).mimeroot.is_null()) {
|
||||
if !(r != MAILIMF_NO_ERROR as libc::c_int || mimeparser.mimeroot.is_null()) {
|
||||
dc_e2ee_decrypt(
|
||||
(*mimeparser).context,
|
||||
(*mimeparser).mimeroot,
|
||||
&mut (*mimeparser).e2ee_helper,
|
||||
mimeparser.context,
|
||||
mimeparser.mimeroot,
|
||||
&mut mimeparser.e2ee_helper,
|
||||
);
|
||||
dc_mimeparser_parse_mime_recursive(mimeparser, (*mimeparser).mimeroot);
|
||||
dc_mimeparser_parse_mime_recursive(mimeparser, mimeparser.mimeroot);
|
||||
let field: *mut mailimf_field = dc_mimeparser_lookup_field(mimeparser, "Subject");
|
||||
if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
|
||||
(*mimeparser).subject =
|
||||
dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value)
|
||||
mimeparser.subject = dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value)
|
||||
}
|
||||
if !dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
@@ -168,7 +167,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
(*mimeparser).is_send_by_messenger = 1i32
|
||||
mimeparser.is_send_by_messenger = 1i32
|
||||
}
|
||||
if !dc_mimeparser_lookup_field(mimeparser, "Autocrypt-Setup-Message").is_null() {
|
||||
let mut has_setup_file: libc::c_int = 0i32;
|
||||
@@ -212,7 +211,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
b"location-streaming-enabled\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
(*mimeparser).is_system_message = 8i32
|
||||
mimeparser.is_system_message = 8i32
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,7 +228,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
}
|
||||
}
|
||||
if 0 != (*mimeparser).is_send_by_messenger
|
||||
if 0 != mimeparser.is_send_by_messenger
|
||||
&& 0 != S_GENERATE_COMPOUND_MSGS
|
||||
&& mimeparser.parts.len() == 2
|
||||
{
|
||||
@@ -248,22 +247,33 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
|
||||
if need_drop {
|
||||
free(mimeparser.parts[1].msg as *mut libc::c_void);
|
||||
let mut textpart = mimeparser.parts.swap_remove(0);
|
||||
mimeparser.parts[1].msg = textpart.msg;
|
||||
textpart.msg = 0 as *mut libc::c_char;
|
||||
dc_mimepart_unref(textpart);
|
||||
let mut filepart = mimeparser.parts.swap_remove(1);
|
||||
|
||||
// clear old one
|
||||
free(filepart.msg as *mut libc::c_void);
|
||||
|
||||
// insert new one
|
||||
filepart.msg = mimeparser.parts[0].msg;
|
||||
|
||||
// forget the one we use now
|
||||
mimeparser.parts[0].msg = std::ptr::null_mut();
|
||||
|
||||
// swap new with old
|
||||
let old = std::mem::replace(&mut mimeparser.parts[0], filepart);
|
||||
|
||||
// unref old one
|
||||
dc_mimepart_unref(old);
|
||||
}
|
||||
}
|
||||
if !(*mimeparser).subject.is_null() {
|
||||
if !mimeparser.subject.is_null() {
|
||||
let mut prepend_subject: libc::c_int = 1i32;
|
||||
if 0 == (*mimeparser).decrypting_failed {
|
||||
let p: *mut libc::c_char = strchr((*mimeparser).subject, ':' as i32);
|
||||
if p.wrapping_offset_from((*mimeparser).subject) == 2
|
||||
|| p.wrapping_offset_from((*mimeparser).subject) == 3
|
||||
|| 0 != (*mimeparser).is_send_by_messenger
|
||||
if 0 == mimeparser.decrypting_failed {
|
||||
let p: *mut libc::c_char = strchr(mimeparser.subject, ':' as i32);
|
||||
if p.wrapping_offset_from(mimeparser.subject) == 2
|
||||
|| p.wrapping_offset_from(mimeparser.subject) == 3
|
||||
|| 0 != mimeparser.is_send_by_messenger
|
||||
|| !strstr(
|
||||
(*mimeparser).subject,
|
||||
mimeparser.subject,
|
||||
b"Chat:\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
.is_null()
|
||||
@@ -272,7 +282,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
}
|
||||
if 0 != prepend_subject {
|
||||
let subj: *mut libc::c_char = dc_strdup((*mimeparser).subject);
|
||||
let subj: *mut libc::c_char = dc_strdup(mimeparser.subject);
|
||||
let p_0: *mut libc::c_char = strchr(subj, '[' as i32);
|
||||
if !p_0.is_null() {
|
||||
*p_0 = 0i32 as libc::c_char
|
||||
@@ -295,7 +305,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
free(subj as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
if 0 != (*mimeparser).is_forwarded {
|
||||
if 0 != mimeparser.is_forwarded {
|
||||
for part in mimeparser.parts.iter_mut() {
|
||||
part.param.set_int(Param::Forwarded, 1);
|
||||
}
|
||||
@@ -327,7 +337,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
}
|
||||
}
|
||||
if 0 == (*mimeparser).decrypting_failed {
|
||||
if 0 == mimeparser.decrypting_failed {
|
||||
let dn_field: *const mailimf_optional_field = dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Disposition-Notification-To\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -372,11 +382,11 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
}
|
||||
/* Cleanup - and try to create at least an empty part if there are no parts yet */
|
||||
if dc_mimeparser_get_last_nonmeta(mimeparser).is_none() && (*mimeparser).reports.is_empty() {
|
||||
if dc_mimeparser_get_last_nonmeta(mimeparser).is_none() && mimeparser.reports.is_empty() {
|
||||
let mut part_5 = dc_mimepart_new();
|
||||
part_5.type_0 = 10i32;
|
||||
if !(*mimeparser).subject.is_null() && 0 == (*mimeparser).is_send_by_messenger {
|
||||
part_5.msg = dc_strdup((*mimeparser).subject)
|
||||
if !mimeparser.subject.is_null() && 0 == mimeparser.is_send_by_messenger {
|
||||
part_5.msg = dc_strdup(mimeparser.subject)
|
||||
} else {
|
||||
part_5.msg = dc_strdup(b"\x00" as *const u8 as *const libc::c_char)
|
||||
}
|
||||
@@ -493,32 +503,32 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
|
||||
) == 0i32
|
||||
{
|
||||
info!(
|
||||
(*mimeparser).context,
|
||||
mimeparser.context,
|
||||
0, "Protected headers found in text/rfc822-headers attachment: Will be ignored.",
|
||||
);
|
||||
return 0i32;
|
||||
}
|
||||
if (*mimeparser).header_protected.is_null() {
|
||||
if mimeparser.header_protected.is_null() {
|
||||
let mut dummy: size_t = 0i32 as size_t;
|
||||
if mailimf_envelope_and_optional_fields_parse(
|
||||
(*mime).mm_mime_start,
|
||||
(*mime).mm_length,
|
||||
&mut dummy,
|
||||
&mut (*mimeparser).header_protected,
|
||||
&mut mimeparser.header_protected,
|
||||
) != MAILIMF_NO_ERROR as libc::c_int
|
||||
|| (*mimeparser).header_protected.is_null()
|
||||
|| mimeparser.header_protected.is_null()
|
||||
{
|
||||
warn!((*mimeparser).context, 0, "Protected headers parsing error.",);
|
||||
warn!(mimeparser.context, 0, "Protected headers parsing error.",);
|
||||
} else {
|
||||
hash_header(
|
||||
&mut (*mimeparser).header,
|
||||
(*mimeparser).header_protected,
|
||||
(*mimeparser).context,
|
||||
&mut mimeparser.header,
|
||||
mimeparser.header_protected,
|
||||
mimeparser.context,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
info!(
|
||||
(*mimeparser).context,
|
||||
mimeparser.context,
|
||||
0,
|
||||
"Protected headers found in MIME header: Will be ignored as we already found an outer one."
|
||||
);
|
||||
@@ -622,7 +632,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
|
||||
let mut part = dc_mimepart_new();
|
||||
part.type_0 = 10i32;
|
||||
let msg_body = CString::new(
|
||||
(*mimeparser)
|
||||
mimeparser
|
||||
.context
|
||||
.stock_str(StockMessage::CantDecryptMsgBody)
|
||||
.as_ref(),
|
||||
@@ -635,7 +645,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
|
||||
part.msg_raw = dc_strdup(part.msg);
|
||||
mimeparser.parts.push(part);
|
||||
any_part_added = 1i32;
|
||||
(*mimeparser).decrypting_failed = 1i32
|
||||
mimeparser.decrypting_failed = 1i32
|
||||
}
|
||||
46 => {
|
||||
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
|
||||
@@ -663,7 +673,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
|
||||
b"disposition-notification\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
(*mimeparser).reports.push(mime);
|
||||
mimeparser.reports.push(mime);
|
||||
} else {
|
||||
any_part_added = dc_mimeparser_parse_mime_recursive(
|
||||
mimeparser,
|
||||
@@ -713,7 +723,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
|
||||
}
|
||||
if plain_cnt == 1i32 && html_cnt == 1i32 {
|
||||
warn!(
|
||||
(*mimeparser).context,
|
||||
mimeparser.context,
|
||||
0i32,
|
||||
"HACK: multipart/mixed message found with PLAIN and HTML, we\'ll skip the HTML part as this seems to be unwanted."
|
||||
);
|
||||
@@ -742,12 +752,12 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
if (*mimeparser).header_root.is_null() {
|
||||
(*mimeparser).header_root = (*mime).mm_data.mm_message.mm_fields;
|
||||
if mimeparser.header_root.is_null() {
|
||||
mimeparser.header_root = (*mime).mm_data.mm_message.mm_fields;
|
||||
hash_header(
|
||||
&mut (*mimeparser).header,
|
||||
(*mimeparser).header_root,
|
||||
(*mimeparser).context,
|
||||
&mut mimeparser.header,
|
||||
mimeparser.header_root,
|
||||
mimeparser.context,
|
||||
);
|
||||
}
|
||||
if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() {
|
||||
@@ -1127,8 +1137,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
simplifier = Some(dc_simplify_t::new());
|
||||
}
|
||||
/* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */
|
||||
let charset: *const libc::c_char =
|
||||
mailmime_content_charset_get((*mime).mm_content_type);
|
||||
let charset = mailmime_content_charset_get((*mime).mm_content_type);
|
||||
if !charset.is_null()
|
||||
&& strcmp(charset, b"utf-8\x00" as *const u8 as *const libc::c_char)
|
||||
!= 0i32
|
||||
@@ -1144,12 +1153,16 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
);
|
||||
|
||||
let (res, _, _) = encoding.decode(data);
|
||||
info!(mimeparser.context, 0, "decoded message: '{}'", res);
|
||||
if res.is_empty() {
|
||||
/* no error - but nothing to add */
|
||||
current_block = 8795901732489102124;
|
||||
} else {
|
||||
decoded_data_bytes = res.len();
|
||||
decoded_data = res.as_ptr() as *const libc::c_char;
|
||||
let b = res.as_bytes();
|
||||
decoded_data = b.as_ptr() as *const libc::c_char;
|
||||
decoded_data_bytes = b.len();
|
||||
std::mem::forget(res);
|
||||
|
||||
current_block = 17788412896529399552;
|
||||
}
|
||||
} else {
|
||||
@@ -1169,19 +1182,19 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
8795901732489102124 => {}
|
||||
_ => {
|
||||
/* check header directly as is_send_by_messenger is not yet set up */
|
||||
let is_msgrmsg: libc::c_int = (dc_mimeparser_lookup_optional_field(
|
||||
let is_msgrmsg = (!dc_mimeparser_lookup_optional_field(
|
||||
&mimeparser,
|
||||
b"Chat-Version\x00" as *const u8 as *const libc::c_char,
|
||||
) != 0 as *mut libc::c_void
|
||||
as *mut mailimf_optional_field)
|
||||
)
|
||||
.is_null())
|
||||
as libc::c_int;
|
||||
let simplified_txt: *mut libc::c_char =
|
||||
simplifier.unwrap().simplify(
|
||||
decoded_data,
|
||||
decoded_data_bytes as libc::c_int,
|
||||
if mime_type == 70i32 { 1i32 } else { 0i32 },
|
||||
is_msgrmsg,
|
||||
);
|
||||
|
||||
let simplified_txt = simplifier.unwrap().simplify(
|
||||
decoded_data,
|
||||
decoded_data_bytes as libc::c_int,
|
||||
if mime_type == 70i32 { 1i32 } else { 0i32 },
|
||||
is_msgrmsg,
|
||||
);
|
||||
if !simplified_txt.is_null()
|
||||
&& 0 != *simplified_txt.offset(0isize) as libc::c_int
|
||||
{
|
||||
@@ -1196,7 +1209,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
free(simplified_txt as *mut libc::c_void);
|
||||
}
|
||||
if 0 != simplifier.unwrap().is_forwarded {
|
||||
(*mimeparser).is_forwarded = 1i32
|
||||
mimeparser.is_forwarded = 1i32
|
||||
}
|
||||
current_block = 10261677128829721533;
|
||||
}
|
||||
@@ -1324,8 +1337,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
4,
|
||||
) == 0i32
|
||||
{
|
||||
(*mimeparser).location_kml = Some(dc_kml_parse(
|
||||
(*mimeparser).context,
|
||||
mimeparser.location_kml = Some(dc_kml_parse(
|
||||
mimeparser.context,
|
||||
decoded_data,
|
||||
decoded_data_bytes,
|
||||
));
|
||||
@@ -1343,8 +1356,8 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
4,
|
||||
) == 0i32
|
||||
{
|
||||
(*mimeparser).message_kml = Some(dc_kml_parse(
|
||||
(*mimeparser).context,
|
||||
mimeparser.message_kml = Some(dc_kml_parse(
|
||||
mimeparser.context,
|
||||
decoded_data,
|
||||
decoded_data_bytes,
|
||||
));
|
||||
@@ -1566,7 +1579,7 @@ pub unsafe fn dc_mimeparser_sender_equals_recipient(mimeparser: &dc_mimeparser_t
|
||||
let mut fld_from: *const mailimf_from = 0 as *const mailimf_from;
|
||||
let mb: *mut mailimf_mailbox;
|
||||
|
||||
if !(*mimeparser).header_root.is_null() {
|
||||
if !mimeparser.header_root.is_null() {
|
||||
/* get From: and check there is exactly one sender */
|
||||
fld = mailimf_find_field(mimeparser.header_root, MAILIMF_FIELD_FROM as libc::c_int);
|
||||
if !(fld.is_null()
|
||||
|
||||
@@ -723,8 +723,7 @@ pub unsafe fn dc_receive_imf(
|
||||
&mut msg_id,
|
||||
) {
|
||||
rr_event_to_send
|
||||
.push((chat_id_0, 0));
|
||||
rr_event_to_send.push((msg_id, 0));
|
||||
.push((chat_id_0, msg_id));
|
||||
}
|
||||
mdn_consumed = (msg_id
|
||||
!= 0 as libc::c_uint)
|
||||
@@ -1723,7 +1722,7 @@ unsafe fn check_verified_properties(
|
||||
|
||||
unsafe fn set_better_msg<T: AsRef<str>>(mime_parser: &mut dc_mimeparser_t, better_msg: T) {
|
||||
let msg = better_msg.as_ref();
|
||||
if !(msg.len() > 0) && !mime_parser.parts.is_empty() {
|
||||
if msg.len() > 0 && !mime_parser.parts.is_empty() {
|
||||
let part = &mut mime_parser.parts[0];
|
||||
if (*part).type_0 == 10 {
|
||||
free(part.msg as *mut libc::c_void);
|
||||
|
||||
@@ -29,6 +29,10 @@ impl dc_simplify_t {
|
||||
is_html: libc::c_int,
|
||||
is_msgrmsg: libc::c_int,
|
||||
) -> *mut libc::c_char {
|
||||
if in_bytes <= 0 {
|
||||
return "".strdup();
|
||||
}
|
||||
|
||||
/* create a copy of the given buffer */
|
||||
let mut out: *mut libc::c_char;
|
||||
let mut temp: *mut libc::c_char;
|
||||
|
||||
@@ -166,7 +166,7 @@ impl<'a> Peerstate<'a> {
|
||||
|
||||
pub fn from_addr(context: &'a Context, _sql: &Sql, addr: &str) -> Option<Self> {
|
||||
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;";
|
||||
|
||||
info!(context, 0, "peerstate.from_addr {}", addr);
|
||||
Self::from_stmt(context, query, &[addr])
|
||||
}
|
||||
|
||||
@@ -188,21 +188,38 @@ impl<'a> Peerstate<'a> {
|
||||
P: IntoIterator,
|
||||
P::Item: rusqlite::ToSql,
|
||||
{
|
||||
info!(context, 0, "from_stmt query {:?}", query);
|
||||
context
|
||||
.sql
|
||||
.query_row(query, params, |row| {
|
||||
/* all the above queries start with this: SELECT
|
||||
addr, last_seen, last_seen_autocrypt, prefer_encrypted,
|
||||
public_key, gossip_timestamp, gossip_key, public_key_fingerprint,
|
||||
gossip_key_fingerprint, verified_key, verified_key_fingerprint
|
||||
*/
|
||||
let mut res = Self::new(context);
|
||||
|
||||
res.addr = Some(row.get(0)?);
|
||||
info!(context, 0, "from_stmt res.addr {:?} starting", res.addr);
|
||||
res.last_seen = row.get(1)?;
|
||||
res.last_seen_autocrypt = row.get(2)?;
|
||||
res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
|
||||
res.gossip_timestamp = row.get(5)?;
|
||||
let pkf: String = row.get(7)?;
|
||||
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
|
||||
let gkf: String = row.get(8)?;
|
||||
|
||||
let t: Result<String, rusqlite::Error> = row.get(8);
|
||||
let gkf: String = match t {
|
||||
Err(_) => String::from(""),
|
||||
Ok(res) => res,
|
||||
};
|
||||
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
|
||||
let vkf: String = row.get(10)?;
|
||||
|
||||
let t: Result<String, rusqlite::Error> = row.get(10);
|
||||
let vkf: String = match t {
|
||||
Err(_) => String::from(""),
|
||||
Ok(res) => res,
|
||||
};
|
||||
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) };
|
||||
|
||||
res.public_key = row
|
||||
@@ -217,7 +234,7 @@ impl<'a> Peerstate<'a> {
|
||||
.get(9)
|
||||
.ok()
|
||||
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
||||
res.verified_key = if vk == res.gossip_key {
|
||||
res.verified_key = if vk == res.gossip_key && res.gossip_key.is_some() {
|
||||
VerifiedKey::Gossip
|
||||
} else if vk == res.public_key {
|
||||
VerifiedKey::Public
|
||||
@@ -400,6 +417,10 @@ impl<'a> Peerstate<'a> {
|
||||
}
|
||||
|
||||
if self.to_save == Some(ToSave::All) || create {
|
||||
info!(
|
||||
self.context,
|
||||
0, "update acpeerstates with peerstate {:?}", self
|
||||
);
|
||||
success = sql::execute(
|
||||
self.context,
|
||||
sql,
|
||||
@@ -422,6 +443,7 @@ impl<'a> Peerstate<'a> {
|
||||
&self.addr,
|
||||
],
|
||||
).is_ok();
|
||||
assert_eq!(success, true);
|
||||
} else if self.to_save == Some(ToSave::Timestamps) {
|
||||
success = sql::execute(
|
||||
self.context,
|
||||
@@ -498,6 +520,40 @@ mod tests {
|
||||
assert_eq!(peerstate, peerstate_new);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_peerstate_with_empty_gossip_key_save_to_db() {
|
||||
let ctx = crate::test_utils::dummy_context();
|
||||
let addr = "hello@mail.com";
|
||||
|
||||
let pub_key = crate::key::Key::from_base64("xsBNBFztUVkBCADYaQl/UOUpRPd32nLRzx8eU0eI+jQEnG+g5anjYA+3oct1rROGl5SygjMULDKdaUy27O3o9Srsti0YjA7uxZnavIqhSopJhFidqY1M1wA9JZa/duucZdNwUGbjGIRsS/4Cjr5+3svscK24hVYub1dvDWXpwUTnj3K6xOEnJdoM+MhCqtSD5+zcJhFc9vyZm9ZTGWUxAhKh0iJTcCD8V6CQ3XZ2z9GruwzZT/FTFovWrz7m3TUI2OdSSHh0eZLRGEoxMCT/vzflAFGAr8ijCaRsEIfqP6FW8uQWnFTqkjxEUCZG6XkeFHB84aj5jqYG/1KCLjL5vEKwfl1tz/WnPhY7ABEBAAHNEDxoZWxsb0BtYWlsLmNvbT7CwIkEEAEIADMCGQEFAlztUVoCGwMECwkIBwYVCAkKCwIDFgIBFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7ijAwf+PTsuawUax9cNPn1bN90H+g9qyHZJMEwKXtUnNaXJxPW3iB7ThhpCiCzsZwP7+l7ArS8tmLeNDw2bENtcf1XCv4wovP2fdXOP3QOUUFX/GdakcTwv7DzC7CO0grB1HtaPhGw/6UX2o2cx2i9xiUf4Givq2MfCbgAW5zloH6WXGPb6yLQYJXxqDIphr4+uZDb+bMAyWHN/DUkAjHrV8nnVki7PMHqzzZpwglalxMX8RGeiGZE39ALJKL/Og87DMFah87/yoxQWGoS7Wqv0XDcCPKoTCPrpk8pOe2KEsq/lz215nefHd4aRpfUX5YCYa8HPvvfPQbGF73uvyQw5w7qjis7ATQRc7VFZAQgAt8ONdnX6KEEQ5Jw6ilJ+LBtY44SP5t0I3eK+goKepgIiKhjGDa+Mntyi4jdhH+HO6kvK5SHMh2sPp4rRO/WKHJwWFySyM1OdyiywhyH0J9R5rBY4vPHsJjf6vSKJdWLWT+ho1fNet2IIC+jVCYli91MAMbRvk6EKVj1nCc+67giOahXEkHt6xxkeCGlOvbw8hxGj1A8+AC1BLms/OR3oc4JMi9O3kq6uG0z9tlUEerac9HVwcjoO1XLe+hJhoT5H+TbnGjPuhuURP3pFiIKHpbRYgUfdSAY0dTObO7t4I5y/drPOrCTnWrBUg2wXAECUhpRKow9/ai2YemLv9KqhhwARAQABwsB2BBgBCAAgBQJc7VFaAhsMFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7jmyggAhs4QzCzIbT2OsAReBxkxtm0AI+g1HZ1KFKof5NDHfgv9C/Qu1I8mKEjlZzA4qFyPmLqntgwJ0RuFy6gLbljZBNCFO7vB478AhYtnWjuKZmA40HUPwcB1hEJ31c42akzfUbioY1TLLepngdsJg7Cm8O+rhI9+1WRA66haJDgFs793SVUDyJh8f9NX50l5zR87/bsV30CFSw0q4OSSy9VI/z+2g5khn1LnuuOrCfFnYIPYtJED1BfkXkosxGlgbzy79VvGmI9d23x4atDK7oBPCzIj+lP8sytJ0u3HOguXi9OgDitKy+Pt1r8gH8frdktMJr5Ts6DW+tIn2vR23KR8aA==", KeyType::Public).unwrap();
|
||||
|
||||
let mut peerstate = Peerstate {
|
||||
context: &ctx.ctx,
|
||||
addr: Some(addr.into()),
|
||||
last_seen: 10,
|
||||
last_seen_autocrypt: 11,
|
||||
prefer_encrypt: EncryptPreference::Mutual,
|
||||
public_key: Some(pub_key.clone()),
|
||||
public_key_fingerprint: Some(pub_key.fingerprint()),
|
||||
gossip_key: None,
|
||||
gossip_timestamp: 12,
|
||||
gossip_key_fingerprint: None,
|
||||
verified_key: VerifiedKey::None,
|
||||
verified_key_fingerprint: None,
|
||||
to_save: Some(ToSave::All),
|
||||
degrade_event: None,
|
||||
};
|
||||
|
||||
assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save");
|
||||
|
||||
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into())
|
||||
.expect("failed to load peerstate from db");
|
||||
|
||||
// clear to_save, as that is not persissted
|
||||
peerstate.to_save = None;
|
||||
assert_eq!(peerstate, peerstate_new);
|
||||
}
|
||||
|
||||
// TODO: don't copy this from stress.rs
|
||||
#[allow(dead_code)]
|
||||
struct TestContext {
|
||||
|
||||
Reference in New Issue
Block a user