mirror of
https://github.com/chatmail/core.git
synced 2026-05-17 05:46:30 +03:00
Merge fixes for chat assignment when forwarding messages
GitHub PR #2843
This commit is contained in:
93
src/chat.rs
93
src/chat.rs
@@ -2846,6 +2846,7 @@ pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId)
|
|||||||
msg.param.remove(Param::ForcePlaintext);
|
msg.param.remove(Param::ForcePlaintext);
|
||||||
msg.param.remove(Param::Cmd);
|
msg.param.remove(Param::Cmd);
|
||||||
msg.param.remove(Param::OverrideSenderDisplayname);
|
msg.param.remove(Param::OverrideSenderDisplayname);
|
||||||
|
msg.in_reply_to = None;
|
||||||
|
|
||||||
// do not leak data as group names; a default subject is generated by mimfactory
|
// do not leak data as group names; a default subject is generated by mimfactory
|
||||||
msg.subject = "".to_string();
|
msg.subject = "".to_string();
|
||||||
@@ -4291,6 +4292,98 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_forward_quote() -> Result<()> {
|
||||||
|
let alice = TestContext::new_alice().await;
|
||||||
|
let bob = TestContext::new_bob().await;
|
||||||
|
let alice_chat = alice.create_chat(&bob).await;
|
||||||
|
let bob_chat = bob.create_chat(&alice).await;
|
||||||
|
|
||||||
|
// Alice sends a message to Bob.
|
||||||
|
let sent_msg = alice.send_text(alice_chat.id, "Hi Bob").await;
|
||||||
|
bob.recv_msg(&sent_msg).await;
|
||||||
|
let received_msg = bob.get_last_msg().await;
|
||||||
|
|
||||||
|
// Bob quotes received message and sends a reply to Alice.
|
||||||
|
let mut reply = Message::new(Viewtype::Text);
|
||||||
|
reply.set_text(Some("Reply".to_owned()));
|
||||||
|
reply.set_quote(&bob, &received_msg).await?;
|
||||||
|
let sent_reply = bob.send_msg(bob_chat.id, &mut reply).await;
|
||||||
|
alice.recv_msg(&sent_reply).await;
|
||||||
|
let received_reply = alice.get_last_msg().await;
|
||||||
|
|
||||||
|
// Alice forwards a reply.
|
||||||
|
forward_msgs(&alice, &[received_reply.id], alice_chat.get_id()).await?;
|
||||||
|
let forwarded_msg = alice.pop_sent_msg().await;
|
||||||
|
bob.recv_msg(&forwarded_msg).await;
|
||||||
|
|
||||||
|
let alice_forwarded_msg = alice.get_last_msg().await;
|
||||||
|
assert!(alice_forwarded_msg.quoted_message(&alice).await?.is_none());
|
||||||
|
assert_eq!(
|
||||||
|
alice_forwarded_msg.quoted_text(),
|
||||||
|
Some("Hi Bob".to_string())
|
||||||
|
);
|
||||||
|
|
||||||
|
let bob_forwarded_msg = bob.get_last_msg().await;
|
||||||
|
assert!(bob_forwarded_msg.quoted_message(&bob).await?.is_none());
|
||||||
|
assert_eq!(bob_forwarded_msg.quoted_text(), Some("Hi Bob".to_string()));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_forward_group() -> Result<()> {
|
||||||
|
let alice = TestContext::new_alice().await;
|
||||||
|
let bob = TestContext::new_bob().await;
|
||||||
|
|
||||||
|
let alice_chat = alice.create_chat(&bob).await;
|
||||||
|
let bob_chat = bob.create_chat(&alice).await;
|
||||||
|
|
||||||
|
// Alice creates a group with Bob.
|
||||||
|
let alice_group_chat_id =
|
||||||
|
create_group_chat(&alice, ProtectionStatus::Unprotected, "Group").await?;
|
||||||
|
let bob_id = Contact::create(&alice, "Bob", "bob@example.net").await?;
|
||||||
|
let claire_id = Contact::create(&alice, "Claire", "claire@example.net").await?;
|
||||||
|
add_contact_to_chat(&alice, alice_group_chat_id, bob_id).await?;
|
||||||
|
add_contact_to_chat(&alice, alice_group_chat_id, claire_id).await?;
|
||||||
|
let sent_group_msg = alice
|
||||||
|
.send_text(alice_group_chat_id, "Hi Bob and Claire")
|
||||||
|
.await;
|
||||||
|
bob.recv_msg(&sent_group_msg).await;
|
||||||
|
let bob_group_chat_id = bob.get_last_msg().await.chat_id;
|
||||||
|
|
||||||
|
// Alice deletes a message on her device.
|
||||||
|
// This is needed to make assignment of further messages received in this group
|
||||||
|
// based on `References:` header harder.
|
||||||
|
// Previously this exposed a bug, so this is a regression test.
|
||||||
|
message::delete_msgs(&alice, &[sent_group_msg.sender_msg_id]).await?;
|
||||||
|
|
||||||
|
// Alice sends a message to Bob.
|
||||||
|
let sent_msg = alice.send_text(alice_chat.id, "Hi Bob").await;
|
||||||
|
bob.recv_msg(&sent_msg).await;
|
||||||
|
let received_msg = bob.get_last_msg().await;
|
||||||
|
assert_eq!(received_msg.get_text(), Some("Hi Bob".to_string()));
|
||||||
|
assert_eq!(received_msg.chat_id, bob_chat.id);
|
||||||
|
|
||||||
|
// Alice sends another message to Bob, this has first message as a parent.
|
||||||
|
let sent_msg = alice.send_text(alice_chat.id, "Hello Bob").await;
|
||||||
|
bob.recv_msg(&sent_msg).await;
|
||||||
|
let received_msg = bob.get_last_msg().await;
|
||||||
|
assert_eq!(received_msg.get_text(), Some("Hello Bob".to_string()));
|
||||||
|
assert_eq!(received_msg.chat_id, bob_chat.id);
|
||||||
|
|
||||||
|
// Bob forwards message to a group chat with Alice.
|
||||||
|
forward_msgs(&bob, &[received_msg.id], bob_group_chat_id).await?;
|
||||||
|
let forwarded_msg = bob.pop_sent_msg().await;
|
||||||
|
alice.recv_msg(&forwarded_msg).await;
|
||||||
|
|
||||||
|
let received_forwarded_msg = alice.get_last_msg_in(alice_group_chat_id).await;
|
||||||
|
assert!(received_forwarded_msg.is_forwarded());
|
||||||
|
assert_eq!(received_forwarded_msg.chat_id, alice_group_chat_id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn test_only_minimal_data_are_forwarded() -> Result<()> {
|
async fn test_only_minimal_data_are_forwarded() -> Result<()> {
|
||||||
// send a message from Alice to a group with Bob
|
// send a message from Alice to a group with Bob
|
||||||
|
|||||||
@@ -2113,6 +2113,8 @@ fn set_better_msg(mime_parser: &mut MimeMessage, better_msg: impl AsRef<str>) {
|
|||||||
/// Returns the last message referenced from `References` header if it is in the database.
|
/// Returns the last message referenced from `References` header if it is in the database.
|
||||||
///
|
///
|
||||||
/// For Delta Chat messages it is the last message in the chat of the sender.
|
/// For Delta Chat messages it is the last message in the chat of the sender.
|
||||||
|
///
|
||||||
|
/// Note that the returned message may be trashed.
|
||||||
async fn get_previous_message(
|
async fn get_previous_message(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
mime_parser: &MimeMessage,
|
mime_parser: &MimeMessage,
|
||||||
@@ -2128,6 +2130,8 @@ async fn get_previous_message(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Given a list of Message-IDs, returns the latest message found in the database.
|
/// Given a list of Message-IDs, returns the latest message found in the database.
|
||||||
|
///
|
||||||
|
/// Only messages that are not in the trash chat are considered.
|
||||||
async fn get_rfc724_mid_in_list(context: &Context, mid_list: &str) -> Result<Option<Message>> {
|
async fn get_rfc724_mid_in_list(context: &Context, mid_list: &str) -> Result<Option<Message>> {
|
||||||
if mid_list.is_empty() {
|
if mid_list.is_empty() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
@@ -2135,7 +2139,10 @@ async fn get_rfc724_mid_in_list(context: &Context, mid_list: &str) -> Result<Opt
|
|||||||
|
|
||||||
for id in parse_message_ids(mid_list).iter().rev() {
|
for id in parse_message_ids(mid_list).iter().rev() {
|
||||||
if let Some((_, _, msg_id)) = rfc724_mid_exists(context, id).await? {
|
if let Some((_, _, msg_id)) = rfc724_mid_exists(context, id).await? {
|
||||||
return Ok(Some(Message::load_from_db(context, msg_id).await?));
|
let msg = Message::load_from_db(context, msg_id).await?;
|
||||||
|
if msg.chat_id != DC_CHAT_ID_TRASH {
|
||||||
|
return Ok(Some(msg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4741,4 +4748,66 @@ Second thread."#;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_get_parent_message() -> Result<()> {
|
||||||
|
let t = TestContext::new_alice().await;
|
||||||
|
t.set_config(Config::ShowEmails, Some("2")).await?;
|
||||||
|
|
||||||
|
let mime = br#"Subject: First
|
||||||
|
Message-ID: first@example.net
|
||||||
|
To: Alice <alice@example.com>
|
||||||
|
From: Bob <bob@example.net>
|
||||||
|
Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no
|
||||||
|
|
||||||
|
First."#;
|
||||||
|
dc_receive_imf(&t, mime, "INBOX", 1, false).await?;
|
||||||
|
let first = t.get_last_msg().await;
|
||||||
|
let mime = br#"Subject: Second
|
||||||
|
Message-ID: second@example.net
|
||||||
|
To: Alice <alice@example.com>
|
||||||
|
From: Bob <bob@example.net>
|
||||||
|
Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no
|
||||||
|
|
||||||
|
First."#;
|
||||||
|
dc_receive_imf(&t, mime, "INBOX", 2, false).await?;
|
||||||
|
let second = t.get_last_msg().await;
|
||||||
|
let mime = br#"Subject: Third
|
||||||
|
Message-ID: third@example.net
|
||||||
|
To: Alice <alice@example.com>
|
||||||
|
From: Bob <bob@example.net>
|
||||||
|
Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no
|
||||||
|
|
||||||
|
First."#;
|
||||||
|
dc_receive_imf(&t, mime, "INBOX", 3, false).await?;
|
||||||
|
let third = t.get_last_msg().await;
|
||||||
|
|
||||||
|
let mime = br#"Subject: Message with references.
|
||||||
|
Message-ID: second@example.net
|
||||||
|
To: Alice <alice@example.com>
|
||||||
|
From: Bob <bob@example.net>
|
||||||
|
In-Reply-To: <third@example.net>
|
||||||
|
References: <second@example.net> <nonexistent@example.net> <first@example.net>
|
||||||
|
Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no
|
||||||
|
|
||||||
|
Message with references."#;
|
||||||
|
let mime_parser = MimeMessage::from_bytes(&t, &mime[..]).await?;
|
||||||
|
|
||||||
|
let parent = get_parent_message(&t, &mime_parser).await?.unwrap();
|
||||||
|
assert_eq!(parent.id, first.id);
|
||||||
|
|
||||||
|
message::delete_msgs(&t, &[first.id]).await?;
|
||||||
|
let parent = get_parent_message(&t, &mime_parser).await?.unwrap();
|
||||||
|
assert_eq!(parent.id, second.id);
|
||||||
|
|
||||||
|
message::delete_msgs(&t, &[second.id]).await?;
|
||||||
|
let parent = get_parent_message(&t, &mime_parser).await?.unwrap();
|
||||||
|
assert_eq!(parent.id, third.id);
|
||||||
|
|
||||||
|
message::delete_msgs(&t, &[third.id]).await?;
|
||||||
|
let parent = get_parent_message(&t, &mime_parser).await?;
|
||||||
|
assert!(parent.is_none());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -877,7 +877,7 @@ impl Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn quoted_message(&self, context: &Context) -> Result<Option<Message>> {
|
pub async fn quoted_message(&self, context: &Context) -> Result<Option<Message>> {
|
||||||
if self.param.get(Param::Quote).is_some() {
|
if self.param.get(Param::Quote).is_some() && !self.is_forwarded() {
|
||||||
if let Some(in_reply_to) = &self.in_reply_to {
|
if let Some(in_reply_to) = &self.in_reply_to {
|
||||||
if let Some((_, _, msg_id)) = rfc724_mid_exists(context, in_reply_to).await? {
|
if let Some((_, _, msg_id)) = rfc724_mid_exists(context, in_reply_to).await? {
|
||||||
let msg = Message::load_from_db(context, msg_id).await?;
|
let msg = Message::load_from_db(context, msg_id).await?;
|
||||||
|
|||||||
Reference in New Issue
Block a user