mirror of
https://github.com/chatmail/core.git
synced 2026-04-06 23:52:11 +03:00
Compare commits
7 Commits
get_core_v
...
fix_956
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
738ba9b7c4 | ||
|
|
f91474c2f8 | ||
|
|
2a081aac2b | ||
|
|
9b10f31fb3 | ||
|
|
63ad7b8d34 | ||
|
|
86baaab2e9 | ||
|
|
3e66d23367 |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,5 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.0-beta.10 (pending)
|
||||
|
||||
- fix grpid-determination from in-reply-to and references headers. @hpk42
|
||||
|
||||
- only send Autocrypt-gossip headers on encrypted messages. @dignifiedquire
|
||||
|
||||
- fix reply-to-encrypted message to also be encrypted. @hpk42
|
||||
|
||||
- remove last unsafe code from dc_receive_imf :) @hpk42
|
||||
|
||||
|
||||
## 1.0.0-beta.9
|
||||
|
||||
- historic: we now use the mailparse crate and lettre-email to generate mime
|
||||
|
||||
@@ -58,8 +58,6 @@ class Message(object):
|
||||
|
||||
def set_text(self, text):
|
||||
"""set text of this message. """
|
||||
assert self.id > 0, "message not prepared"
|
||||
assert self.is_out_preparing()
|
||||
lib.dc_msg_set_text(self._dc_msg, as_dc_charpointer(text))
|
||||
|
||||
@props.with_doc
|
||||
|
||||
@@ -430,6 +430,30 @@ class TestOnlineAccount:
|
||||
assert self_addr not in ev[2]
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_DELETED_BLOB_FILE")
|
||||
|
||||
def test_prepare_file(self, acfactory, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
chat = self.get_chat(ac1, ac2)
|
||||
|
||||
lp.sec("ac1: prepare and send attachment + text to ac2")
|
||||
blobdir = ac1.get_blobdir()
|
||||
p = os.path.join(blobdir, "somedata.txt")
|
||||
with open(p, "w") as f:
|
||||
f.write("some data")
|
||||
msg = Message.new_empty(ac1, "file")
|
||||
msg.set_text("hello world")
|
||||
msg.set_file(p)
|
||||
message = chat.prepare_message(msg)
|
||||
assert message.is_out_preparing()
|
||||
assert message.text == "hello world"
|
||||
chat.send_prepared(message)
|
||||
|
||||
lp.sec("ac2: receive message")
|
||||
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
||||
assert ev[2] > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
msg = ac2.get_message_by_id(ev[1])
|
||||
assert msg.text == "hello world"
|
||||
assert open(msg.filename).read() == "some data"
|
||||
|
||||
def test_mvbox_sentbox_threads(self, acfactory, lp):
|
||||
lp.sec("ac1: start with mvbox thread")
|
||||
ac1 = acfactory.get_online_configuring_account(mvbox=True, sentbox=True)
|
||||
@@ -475,27 +499,32 @@ class TestOnlineAccount:
|
||||
ac1._evlogger.get_matching("DC_EVENT_IMAP_MESSAGE_MOVED")
|
||||
ac1._evlogger.get_matching("DC_EVENT_IMAP_MESSAGE_MOVED")
|
||||
|
||||
def test_forward_messages(self, acfactory):
|
||||
def test_forward_messages(self, acfactory, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
chat = self.get_chat(ac1, ac2)
|
||||
|
||||
lp.sec("ac1: send message to ac2")
|
||||
msg_out = chat.send_text("message2")
|
||||
|
||||
# wait for other account to receive
|
||||
lp.sec("ac2: wait for receive")
|
||||
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
||||
assert ev[2] == msg_out.id
|
||||
msg_in = ac2.get_message_by_id(msg_out.id)
|
||||
assert msg_in.text == "message2"
|
||||
|
||||
# check the message arrived in contact-requests/deaddrop
|
||||
lp.sec("ac2: check that the message arrive in deaddrop")
|
||||
chat2 = msg_in.chat
|
||||
assert msg_in in chat2.get_messages()
|
||||
assert not msg_in.is_forwarded()
|
||||
assert chat2.is_deaddrop()
|
||||
assert chat2 == ac2.get_deaddrop_chat()
|
||||
|
||||
lp.sec("ac2: create new chat and forward message to it")
|
||||
chat3 = ac2.create_group_chat("newgroup")
|
||||
assert not chat3.is_promoted()
|
||||
ac2.forward_messages([msg_in], chat3)
|
||||
|
||||
lp.sec("ac2: check new chat has a forwarded message")
|
||||
assert chat3.is_promoted()
|
||||
messages = chat3.get_messages()
|
||||
msg = messages[-1]
|
||||
|
||||
@@ -57,13 +57,13 @@ class TestOnlineInCreation:
|
||||
|
||||
lp.sec("wait1 for original or forwarded messages to arrive")
|
||||
ev1 = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||
assert ev1[1] >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert ev1[1] > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
received_original = ac2.get_message_by_id(ev1[2])
|
||||
assert cmp(received_original.filename, path, False)
|
||||
|
||||
lp.sec("wait2 for original or forwarded messages to arrive")
|
||||
ev2 = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||
assert ev2[1] >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert ev2[1] > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert ev2[1] != ev1[1]
|
||||
received_copy = ac2.get_message_by_id(ev2[2])
|
||||
assert cmp(received_copy.filename, path, False)
|
||||
|
||||
@@ -76,7 +76,6 @@ impl Aheader {
|
||||
if let Ok(Some(value)) = headers.get_first_value("Autocrypt") {
|
||||
match Self::from_str(&value) {
|
||||
Ok(header) => {
|
||||
info!(context, "comparing {} - {}", header.addr, wanted_from);
|
||||
if addr_cmp(&header.addr, wanted_from) {
|
||||
return Some(header);
|
||||
}
|
||||
|
||||
@@ -579,6 +579,10 @@ pub fn unblock(context: &Context, chat_id: u32) {
|
||||
}
|
||||
|
||||
pub fn set_blocking(context: &Context, chat_id: u32, new_blocking: Blocked) -> bool {
|
||||
if chat_id == 0 {
|
||||
warn!(context, "ignoring setting of Block-status for chat_id=0");
|
||||
return false;
|
||||
}
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
|
||||
@@ -47,11 +47,6 @@ pub fn dc_receive_imf(
|
||||
server_uid,
|
||||
);
|
||||
|
||||
// Parse the imf to mailimf_message. normally, this is done by mailimf_message_parse(),
|
||||
// however, as we also need the MIME data,
|
||||
// we use mailmime_parse() through dc_mimeparser (both call mailimf_struct_multiple_parse()
|
||||
// somewhen, I did not found out anything that speaks against this approach yet)
|
||||
|
||||
let mime_parser = MimeParser::from_bytes(context, imf_raw);
|
||||
let mut mime_parser = if let Err(err) = mime_parser {
|
||||
warn!(context, "dc_receive_imf parse error: {}", err);
|
||||
@@ -210,7 +205,7 @@ pub fn dc_receive_imf(
|
||||
&mut created_db_entries,
|
||||
&mut create_event_to_send,
|
||||
) {
|
||||
warn!(context, "{}", err);
|
||||
warn!(context, "add_parts error: {:?}", err);
|
||||
|
||||
cleanup(
|
||||
context,
|
||||
@@ -414,18 +409,18 @@ fn add_parts(
|
||||
Blocked::Deaddrop
|
||||
};
|
||||
|
||||
create_or_lookup_group(
|
||||
let (new_chat_id, new_chat_id_blocked) = create_or_lookup_group(
|
||||
context,
|
||||
&mut mime_parser,
|
||||
allow_creation,
|
||||
create_blocked,
|
||||
*from_id,
|
||||
to_ids,
|
||||
chat_id,
|
||||
&mut chat_id_blocked,
|
||||
)?;
|
||||
if 0 != *chat_id && Blocked::Not != chat_id_blocked && create_blocked == Blocked::Not {
|
||||
chat::unblock(context, *chat_id);
|
||||
*chat_id = new_chat_id;
|
||||
chat_id_blocked = new_chat_id_blocked;
|
||||
if *chat_id != 0 && chat_id_blocked != Blocked::Not && create_blocked == Blocked::Not {
|
||||
chat::unblock(context, new_chat_id);
|
||||
chat_id_blocked = Blocked::Not;
|
||||
}
|
||||
}
|
||||
@@ -507,18 +502,19 @@ fn add_parts(
|
||||
if !to_ids.is_empty() {
|
||||
*to_id = to_ids[0];
|
||||
if *chat_id == 0 {
|
||||
create_or_lookup_group(
|
||||
let (new_chat_id, new_chat_id_blocked) = create_or_lookup_group(
|
||||
context,
|
||||
&mut mime_parser,
|
||||
allow_creation,
|
||||
Blocked::Not,
|
||||
*from_id,
|
||||
to_ids,
|
||||
chat_id,
|
||||
&mut chat_id_blocked,
|
||||
)?;
|
||||
if 0 != *chat_id && Blocked::Not != chat_id_blocked {
|
||||
chat::unblock(context, *chat_id);
|
||||
*chat_id = new_chat_id;
|
||||
chat_id_blocked = new_chat_id_blocked;
|
||||
// automatically unblock chat when the user sends a message
|
||||
if *chat_id != 0 && chat_id_blocked != Blocked::Not {
|
||||
chat::unblock(context, new_chat_id);
|
||||
chat_id_blocked = Blocked::Not;
|
||||
}
|
||||
}
|
||||
@@ -789,7 +785,7 @@ fn calc_timestamps(
|
||||
/// - is there a group with the same recipients? if so, use this (if there are multiple, use the most recent one)
|
||||
/// - create an ad-hoc group based on the recipient list
|
||||
///
|
||||
/// So when the function returns, the caller has the group id matching the current state of the group.
|
||||
/// on success the function returns the found/created (chat_id, chat_blocked) tuple .
|
||||
#[allow(non_snake_case)]
|
||||
fn create_or_lookup_group(
|
||||
context: &Context,
|
||||
@@ -797,14 +793,9 @@ fn create_or_lookup_group(
|
||||
allow_creation: i32,
|
||||
create_blocked: Blocked,
|
||||
from_id: u32,
|
||||
to_ids: &mut Vec<u32>,
|
||||
ret_chat_id: *mut u32,
|
||||
ret_chat_id_blocked: &mut Blocked,
|
||||
) -> Result<()> {
|
||||
let group_explicitly_left: bool;
|
||||
let mut chat_id = 0;
|
||||
to_ids: &[u32],
|
||||
) -> Result<(u32, Blocked)> {
|
||||
let mut chat_id_blocked = Blocked::Not;
|
||||
let mut grpid = "".to_string();
|
||||
let mut grpname = None;
|
||||
let to_ids_cnt = to_ids.len();
|
||||
let mut recreate_member_list = 0;
|
||||
@@ -815,26 +806,13 @@ fn create_or_lookup_group(
|
||||
let mut X_MrGrpImageChanged = "".to_string();
|
||||
let mut better_msg: String = From::from("");
|
||||
|
||||
let cleanup = |ret_chat_id: *mut u32,
|
||||
ret_chat_id_blocked: &mut Blocked,
|
||||
chat_id: u32,
|
||||
chat_id_blocked: Blocked| {
|
||||
if !ret_chat_id.is_null() {
|
||||
unsafe { *ret_chat_id = chat_id };
|
||||
}
|
||||
*ret_chat_id_blocked = if 0 != chat_id {
|
||||
chat_id_blocked
|
||||
} else {
|
||||
Blocked::Not
|
||||
};
|
||||
};
|
||||
|
||||
if mime_parser.is_system_message == SystemMessage::LocationStreamingEnabled {
|
||||
better_msg =
|
||||
context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", from_id as u32)
|
||||
}
|
||||
set_better_msg(mime_parser, &better_msg);
|
||||
|
||||
let mut grpid = "".to_string();
|
||||
if let Some(optional_field) = mime_parser.lookup_field("Chat-Group-ID") {
|
||||
grpid = optional_field.clone();
|
||||
}
|
||||
@@ -843,33 +821,26 @@ fn create_or_lookup_group(
|
||||
if let Some(value) = mime_parser.lookup_field("Message-ID") {
|
||||
if let Some(extracted_grpid) = dc_extract_grpid_from_rfc724_mid(&value) {
|
||||
grpid = extracted_grpid.to_string();
|
||||
} else {
|
||||
grpid = "".to_string();
|
||||
}
|
||||
}
|
||||
if grpid.is_empty() {
|
||||
if let Some(value) = mime_parser.lookup_field("In-Reply-To") {
|
||||
grpid = value.clone();
|
||||
}
|
||||
if grpid.is_empty() {
|
||||
if let Some(value) = mime_parser.lookup_field("References") {
|
||||
grpid = value.clone();
|
||||
}
|
||||
|
||||
if grpid.is_empty() {
|
||||
create_or_lookup_adhoc_group(
|
||||
context,
|
||||
mime_parser,
|
||||
allow_creation,
|
||||
create_blocked,
|
||||
from_id,
|
||||
to_ids,
|
||||
&mut chat_id,
|
||||
&mut chat_id_blocked,
|
||||
)?;
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(extracted_grpid) = get_grpid_from_list(mime_parser, "In-Reply-To") {
|
||||
grpid = extracted_grpid;
|
||||
} else if let Some(extracted_grpid) = get_grpid_from_list(mime_parser, "References") {
|
||||
grpid = extracted_grpid;
|
||||
} else {
|
||||
return create_or_lookup_adhoc_group(
|
||||
context,
|
||||
mime_parser,
|
||||
allow_creation,
|
||||
create_blocked,
|
||||
from_id,
|
||||
to_ids,
|
||||
)
|
||||
.map_err(|err| {
|
||||
info!(context, "could not create adhoc-group: {:?}", err);
|
||||
err
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -948,26 +919,29 @@ fn create_or_lookup_group(
|
||||
|
||||
// check, if we have a chat with this group ID
|
||||
let (mut chat_id, chat_id_verified, _blocked) = chat::get_chat_id_by_grpid(context, &grpid);
|
||||
if chat_id != 0 && chat_id_verified {
|
||||
if let Err(err) = check_verified_properties(context, mime_parser, from_id as u32, to_ids) {
|
||||
warn!(context, "verification problem: {}", err);
|
||||
let s = format!("{}. See 'Info' for more details", err);
|
||||
mime_parser.repl_msg_by_error(s);
|
||||
if chat_id != 0 {
|
||||
if chat_id_verified {
|
||||
if let Err(err) =
|
||||
check_verified_properties(context, mime_parser, from_id as u32, to_ids)
|
||||
{
|
||||
warn!(context, "verification problem: {}", err);
|
||||
let s = format!("{}. See 'Info' for more details", err);
|
||||
mime_parser.repl_msg_by_error(s);
|
||||
}
|
||||
}
|
||||
// check if the sender is a member of the existing group -
|
||||
// if not, we'll recreate the group list
|
||||
if !chat::is_contact_in_chat(context, chat_id, from_id as u32) {
|
||||
recreate_member_list = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// check if the sender is a member of the existing group -
|
||||
// if not, we'll recreate the group list
|
||||
if chat_id != 0 && !chat::is_contact_in_chat(context, chat_id, from_id as u32) {
|
||||
recreate_member_list = 1;
|
||||
}
|
||||
|
||||
// check if the group does not exist but should be created
|
||||
group_explicitly_left = chat::is_group_explicitly_left(context, &grpid).unwrap_or_default();
|
||||
|
||||
let group_explicitly_left = chat::is_group_explicitly_left(context, &grpid).unwrap_or_default();
|
||||
let self_addr = context
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.unwrap_or_default();
|
||||
|
||||
if chat_id == 0
|
||||
&& !mime_parser.is_mailinglist_message()
|
||||
&& !grpid.is_empty()
|
||||
@@ -978,10 +952,8 @@ fn create_or_lookup_group(
|
||||
&& (!group_explicitly_left
|
||||
|| X_MrAddToGrp.is_some() && addr_cmp(&self_addr, X_MrAddToGrp.as_ref().unwrap()))
|
||||
{
|
||||
let mut create_verified = VerifiedStatus::Unverified;
|
||||
if mime_parser.lookup_field("Chat-Verified").is_some() {
|
||||
create_verified = VerifiedStatus::Verified;
|
||||
|
||||
// group does not exist but should be created
|
||||
let create_verified = if mime_parser.lookup_field("Chat-Verified").is_some() {
|
||||
if let Err(err) =
|
||||
check_verified_properties(context, mime_parser, from_id as u32, to_ids)
|
||||
{
|
||||
@@ -989,11 +961,16 @@ fn create_or_lookup_group(
|
||||
let s = format!("{}. See 'Info' for more details", err);
|
||||
mime_parser.repl_msg_by_error(&s);
|
||||
}
|
||||
VerifiedStatus::Verified
|
||||
} else {
|
||||
VerifiedStatus::Unverified
|
||||
};
|
||||
|
||||
if allow_creation == 0 {
|
||||
info!(context, "creating group forbidden by caller");
|
||||
return Ok((0, Blocked::Not));
|
||||
}
|
||||
if 0 == allow_creation {
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
chat_id = create_group_record(
|
||||
context,
|
||||
&grpid,
|
||||
@@ -1007,9 +984,8 @@ fn create_or_lookup_group(
|
||||
|
||||
// again, check chat_id
|
||||
if chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
||||
chat_id = 0;
|
||||
if group_explicitly_left {
|
||||
chat_id = DC_CHAT_ID_TRASH;
|
||||
return if group_explicitly_left {
|
||||
Ok((DC_CHAT_ID_TRASH, chat_id_blocked))
|
||||
} else {
|
||||
create_or_lookup_adhoc_group(
|
||||
context,
|
||||
@@ -1018,12 +994,12 @@ fn create_or_lookup_group(
|
||||
create_blocked,
|
||||
from_id,
|
||||
to_ids,
|
||||
&mut chat_id,
|
||||
&mut chat_id_blocked,
|
||||
)?;
|
||||
}
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return Ok(());
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!(context, "failed to create ad-hoc group: {:?}", err);
|
||||
err
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
// execute group commands
|
||||
@@ -1128,74 +1104,78 @@ fn create_or_lookup_group(
|
||||
}
|
||||
|
||||
// check the number of receivers -
|
||||
// the only critical situation is if the user hits "Reply" instead of "Reply all" in a non-messenger-client */
|
||||
if to_ids_cnt == 1 && !mime_parser.is_send_by_messenger {
|
||||
let is_contact_cnt = chat::get_chat_contact_cnt(context, chat_id);
|
||||
if is_contact_cnt > 3 {
|
||||
// to_ids_cnt==1 may be "From: A, To: B, SELF" as SELF is not counted in to_ids_cnt.
|
||||
// So everything up to 3 is no error.
|
||||
chat_id = 0;
|
||||
create_or_lookup_adhoc_group(
|
||||
context,
|
||||
mime_parser,
|
||||
allow_creation,
|
||||
create_blocked,
|
||||
from_id,
|
||||
to_ids,
|
||||
&mut chat_id,
|
||||
&mut chat_id_blocked,
|
||||
)?;
|
||||
}
|
||||
// the only critical situation is if the user hits "Reply" instead
|
||||
// of "Reply all" in a non-messenger-client */
|
||||
if to_ids_cnt == 1
|
||||
&& !mime_parser.is_send_by_messenger
|
||||
&& chat::get_chat_contact_cnt(context, chat_id) > 3
|
||||
{
|
||||
// to_ids_cnt==1 may be "From: A, To: B, SELF" as SELF is not counted in to_ids_cnt.
|
||||
// So everything up to 3 is no error.
|
||||
create_or_lookup_adhoc_group(
|
||||
context,
|
||||
mime_parser,
|
||||
allow_creation,
|
||||
create_blocked,
|
||||
from_id,
|
||||
to_ids,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!(context, "could not create ad-hoc group: {:?}", err);
|
||||
err
|
||||
})?;
|
||||
}
|
||||
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
Ok(())
|
||||
Ok((chat_id, chat_id_blocked))
|
||||
}
|
||||
|
||||
/// Handle groups for received messages
|
||||
/// try extract a grpid from a message-id list header value
|
||||
fn get_grpid_from_list(mime_parser: &MimeParser, header_key: &str) -> Option<String> {
|
||||
if let Some(value) = mime_parser.lookup_field(header_key) {
|
||||
for part in value.split(',').map(str::trim) {
|
||||
if !part.is_empty() {
|
||||
if let Some(extracted_grpid) = dc_extract_grpid_from_rfc724_mid(part) {
|
||||
return Some(extracted_grpid.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Handle groups for received messages, return chat_id/Blocked status on success
|
||||
fn create_or_lookup_adhoc_group(
|
||||
context: &Context,
|
||||
mime_parser: &MimeParser,
|
||||
allow_creation: i32,
|
||||
create_blocked: Blocked,
|
||||
from_id: u32,
|
||||
to_ids: &mut Vec<u32>,
|
||||
ret_chat_id: *mut u32,
|
||||
ret_chat_id_blocked: &mut Blocked,
|
||||
) -> Result<()> {
|
||||
// if we're here, no grpid was found, check there is an existing ad-hoc
|
||||
// group matching the to-list or if we can create one
|
||||
let mut chat_id = 0;
|
||||
let mut chat_id_blocked = Blocked::Not;
|
||||
to_ids: &[u32],
|
||||
) -> Result<(u32, Blocked)> {
|
||||
// if we're here, no grpid was found, check if there is an existing
|
||||
// ad-hoc group matching the to-list or if we should and can create one
|
||||
// (we do not want to heuristically look at the likely mangled Subject)
|
||||
|
||||
let cleanup = |ret_chat_id: *mut u32,
|
||||
ret_chat_id_blocked: &mut Blocked,
|
||||
chat_id: u32,
|
||||
chat_id_blocked: Blocked| {
|
||||
if !ret_chat_id.is_null() {
|
||||
unsafe { *ret_chat_id = chat_id };
|
||||
}
|
||||
*ret_chat_id_blocked = chat_id_blocked;
|
||||
};
|
||||
|
||||
// build member list from the given ids
|
||||
if to_ids.is_empty() || mime_parser.is_mailinglist_message() {
|
||||
// too few contacts or a mailinglist
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return Ok(());
|
||||
if mime_parser.is_mailinglist_message() {
|
||||
// XXX we could parse List-* headers and actually create and
|
||||
// manage a mailing list group, eventually
|
||||
info!(
|
||||
context,
|
||||
"not creating ad-hoc group for mailing list message"
|
||||
);
|
||||
return Ok((0, Blocked::Not));
|
||||
}
|
||||
|
||||
let mut member_ids = to_ids.clone();
|
||||
let mut member_ids = to_ids.to_vec();
|
||||
if !member_ids.contains(&from_id) {
|
||||
member_ids.push(from_id);
|
||||
}
|
||||
if !member_ids.contains(&DC_CONTACT_ID_SELF) {
|
||||
member_ids.push(DC_CONTACT_ID_SELF);
|
||||
}
|
||||
|
||||
if member_ids.len() < 3 {
|
||||
// too few contacts given
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return Ok(());
|
||||
info!(context, "not creating ad-hoc group: too few contacts");
|
||||
return Ok((0, Blocked::Not));
|
||||
}
|
||||
|
||||
let chat_ids = search_chat_ids_by_contact_ids(context, &member_ids)?;
|
||||
@@ -1214,18 +1194,16 @@ fn create_or_lookup_adhoc_group(
|
||||
);
|
||||
|
||||
if let Ok((id, id_blocked)) = res {
|
||||
chat_id = id as u32;
|
||||
chat_id_blocked = id_blocked;
|
||||
/* success, chat found */
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return Ok(());
|
||||
return Ok((id as u32, id_blocked));
|
||||
}
|
||||
}
|
||||
|
||||
if 0 == allow_creation {
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return Ok(());
|
||||
if allow_creation == 0 {
|
||||
info!(context, "creating ad-hoc group prevented from caller");
|
||||
return Ok((0, Blocked::Not));
|
||||
}
|
||||
|
||||
// we do not check if the message is a reply to another group, this may result in
|
||||
// chats with unclear member list. instead we create a new group in the following lines ...
|
||||
|
||||
@@ -1233,10 +1211,12 @@ fn create_or_lookup_adhoc_group(
|
||||
// - there is no need to check if this group exists; otherwise we would have caught it above
|
||||
let grpid = create_adhoc_grp_id(context, &member_ids);
|
||||
if grpid.is_empty() {
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return Ok(());
|
||||
warn!(
|
||||
context,
|
||||
"failed to create ad-hoc grpid for {:?}", member_ids
|
||||
);
|
||||
return Ok((0, Blocked::Not));
|
||||
}
|
||||
|
||||
// use subject as initial chat name
|
||||
let grpname = if let Some(subject) = mime_parser.subject.as_ref().filter(|s| !s.is_empty()) {
|
||||
subject.to_string()
|
||||
@@ -1245,22 +1225,20 @@ fn create_or_lookup_adhoc_group(
|
||||
};
|
||||
|
||||
// create group record
|
||||
chat_id = create_group_record(
|
||||
let new_chat_id = create_group_record(
|
||||
context,
|
||||
&grpid,
|
||||
grpname,
|
||||
create_blocked,
|
||||
VerifiedStatus::Unverified,
|
||||
);
|
||||
chat_id_blocked = create_blocked;
|
||||
for &member_id in &member_ids {
|
||||
chat::add_to_chat_contacts_table(context, chat_id, member_id);
|
||||
chat::add_to_chat_contacts_table(context, new_chat_id, member_id);
|
||||
}
|
||||
|
||||
context.call_cb(Event::ChatModified(chat_id));
|
||||
context.call_cb(Event::ChatModified(new_chat_id));
|
||||
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
Ok(())
|
||||
Ok((new_chat_id, create_blocked))
|
||||
}
|
||||
|
||||
fn create_group_record(
|
||||
@@ -1687,6 +1665,7 @@ fn add_or_lookup_contact_by_addr(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::dummy_context;
|
||||
|
||||
#[test]
|
||||
fn test_hex_hash() {
|
||||
@@ -1695,4 +1674,34 @@ mod tests {
|
||||
let res = hex_hash(data);
|
||||
assert_eq!(res, "b94d27b9934d3e08");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_grpid_simple() {
|
||||
let context = dummy_context();
|
||||
let raw = b"From: hello\n\
|
||||
Subject: outer-subject\n\
|
||||
In-Reply-To: <lqkjwelq123@123123>\n\
|
||||
References: <Gr.HcxyMARjyJy.9-uvzWPTLtV@nauta.cu>\n\
|
||||
\n\
|
||||
hello\x00";
|
||||
let mimeparser = MimeParser::from_bytes(&context.ctx, &raw[..]).unwrap();
|
||||
assert_eq!(get_grpid_from_list(&mimeparser, "In-Reply-To"), None);
|
||||
let grpid = Some("HcxyMARjyJy".to_string());
|
||||
assert_eq!(get_grpid_from_list(&mimeparser, "References"), grpid);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_grpid_from_multiple() {
|
||||
let context = dummy_context();
|
||||
let raw = b"From: hello\n\
|
||||
Subject: outer-subject\n\
|
||||
In-Reply-To: <Gr.HcxyMARjyJy.9-qweqwe@asd.net>\n\
|
||||
References: <qweqweqwe>, <Gr.HcxyMARjyJy.9-uvzWPTLtV@nau.ca>\n\
|
||||
\n\
|
||||
hello\x00";
|
||||
let mimeparser = MimeParser::from_bytes(&context.ctx, &raw[..]).unwrap();
|
||||
let grpid = Some("HcxyMARjyJy".to_string());
|
||||
assert_eq!(get_grpid_from_list(&mimeparser, "In-Reply-To"), grpid);
|
||||
assert_eq!(get_grpid_from_list(&mimeparser, "References"), grpid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,8 +217,11 @@ pub(crate) fn dc_create_outgoing_rfc724_mid(grpid: Option<&str>, from_addr: &str
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `mid` - A string that holds the message id
|
||||
/// * `mid` - A string that holds the message id. Leading/Trailing <>
|
||||
/// characters are automatically stripped.
|
||||
pub(crate) fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> {
|
||||
let mid = mid.trim_start_matches('<').trim_end_matches('>');
|
||||
|
||||
if mid.len() < 9 || !mid.starts_with("Gr.") {
|
||||
return None;
|
||||
}
|
||||
@@ -688,6 +691,16 @@ mod tests {
|
||||
let mid = "Gr.1234567890123456.morerandom@domain.de";
|
||||
let grpid = dc_extract_grpid_from_rfc724_mid(mid);
|
||||
assert_eq!(grpid, Some("1234567890123456"));
|
||||
|
||||
// Should return extracted grpid for grpid with length of 11
|
||||
let mid = "<Gr.12345678901.morerandom@domain.de>";
|
||||
let grpid = dc_extract_grpid_from_rfc724_mid(mid);
|
||||
assert_eq!(grpid, Some("12345678901"));
|
||||
|
||||
// Should return extracted grpid for grpid with length of 11
|
||||
let mid = "<Gr.1234567890123456.morerandom@domain.de>";
|
||||
let grpid = dc_extract_grpid_from_rfc724_mid(mid);
|
||||
assert_eq!(grpid, Some("1234567890123456"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user