diff --git a/src/config.rs b/src/config.rs index 305e8765c..3875e83cc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -466,6 +466,10 @@ pub enum Config { /// storing the same token multiple times on the server. EncryptedDeviceToken, + /// Make `TestContext::pop_sent_msg_opt()` and related functions pop messages from the `smtp` + /// head, i.e. make it a queue. For historical reasons the default is a stack. + PopSentMsgFromHead, + /// Enables running test hooks, e.g. see `InnerContext::pre_encrypt_mime_hook`. /// This way is better than conditional compilation, i.e. `#[cfg(test)]`, because tests not /// using this still run unmodified code. diff --git a/src/context.rs b/src/context.rs index 801dfbce8..91453de05 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1044,6 +1044,13 @@ impl Context { .await? .to_string(), ); + res.insert( + "pop_sent_msg_from_head", + self.sql + .get_raw_config("pop_sent_msg_from_head") + .await? + .unwrap_or_default(), + ); res.insert( "test_hooks", self.sql diff --git a/src/message.rs b/src/message.rs index 3d664b81f..2cb92d340 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1901,9 +1901,10 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec) -> Result<()> // // We also don't send read receipts for contact requests. // Read receipts will not be sent even after accepting the chat. + let wants_mdn = curr_param.get_bool(Param::WantsMdn).unwrap_or_default(); let to_id = if curr_blocked == Blocked::Not && !curr_hidden - && curr_param.get_bool(Param::WantsMdn).unwrap_or_default() + && wants_mdn && curr_param.get_cmd() == SystemMessage::Unknown && context.should_send_mdns().await? { @@ -1925,6 +1926,11 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec) -> Result<()> None }; if let Some(to_id) = to_id { + info!( + context, + "Queuing MDN to {to_id} for {id} from {curr_from_id}, wants_mdn={wants_mdn}, cmd={}.", + curr_param.get_cmd() + ); context .sql .execute( diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 04e618a85..62b7cb7d4 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -2492,6 +2492,8 @@ async fn handle_mdn( let Some((msg_id, chat_id, has_mdns, is_dup)) = context .sql .query_row_optional( + // MDN on a pre-message references the post-message, see `receive_imf`. So we can't tell + // which one was seen, but this is on purpose. "SELECT m.id AS msg_id, c.id AS chat_id, diff --git a/src/test_utils.rs b/src/test_utils.rs index 5f5ad18c3..8ecf01712 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -624,7 +624,10 @@ impl TestContext { } pub async fn pop_sent_msg_opt(&self, timeout: Duration) -> Option> { - let rev_order = true; + let rev_order = !self + .get_config_bool(Config::PopSentMsgFromHead) + .await + .unwrap(); self.pop_sent_msg_ex(rev_order, timeout).await } diff --git a/src/tests/pre_messages/receiving.rs b/src/tests/pre_messages/receiving.rs index 170c19052..83f8779d5 100644 --- a/src/tests/pre_messages/receiving.rs +++ b/src/tests/pre_messages/receiving.rs @@ -6,7 +6,6 @@ use pretty_assertions::assert_eq; use crate::EventType; use crate::chat; -use crate::chat::send_msg; use crate::config::Config; use crate::contact; use crate::download::{DownloadState, PRE_MSG_ATTACHMENT_SIZE_THRESHOLD, PostMsgMetadata}; @@ -265,6 +264,64 @@ async fn test_lost_pre_msg() -> Result<()> { Ok(()) } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_pre_msg_mdn_before_sending_full() -> Result<()> { + pre_msg_mdn_before_sending_full("").await +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_pre_msg_mdn_before_sending_full_with_text() -> Result<()> { + pre_msg_mdn_before_sending_full("text").await +} + +async fn pre_msg_mdn_before_sending_full(text: &str) -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + alice + .set_config_bool(Config::PopSentMsgFromHead, true) + .await?; + let bob = &tcm.bob().await; + let alice_chat_id = alice.create_group_with_members("", &[bob]).await; + + let file_bytes = include_bytes!("../../../test-data/image/screenshot.gif"); + let mut msg = Message::new(Viewtype::Image); + msg.set_file_from_bytes(alice, "a.jpg", file_bytes, None)?; + msg.set_text(text.to_string()); + let pre_msg = alice.send_msg(alice_chat_id, &mut msg).await; + let alice_msg_id = msg.id; + + let msg = bob.recv_msg(&pre_msg).await; + assert_eq!(msg.download_state, DownloadState::Available); + assert_eq!(msg.id.get_state(bob).await?, MessageState::InFresh); + assert_eq!(msg.text, text); + assert!(msg.param.get_bool(Param::WantsMdn).unwrap_or_default()); + msg.chat_id.accept(bob).await?; + markseen_msgs(bob, vec![msg.id]).await?; + assert_eq!(msg.id.get_state(bob).await?, MessageState::InSeen); + assert_eq!( + bob.sql + .count( + "SELECT COUNT(*) FROM smtp_mdns WHERE from_id=?", + (msg.from_id,) + ) + .await?, + 1 + ); + smtp::queue_mdn(bob).await?; + alice.recv_msg_trash(&bob.pop_sent_msg().await).await; + assert_eq!( + alice_msg_id.get_state(alice).await?, + MessageState::OutPending + ); + + let _full_msg = alice.pop_sent_msg().await; + assert_eq!( + alice_msg_id.get_state(alice).await?, + MessageState::OutMdnRcvd + ); + Ok(()) +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_post_msg_bad_sender() -> Result<()> { let mut tcm = TestContextManager::new(); @@ -550,7 +607,7 @@ async fn test_webxdc_updates_in_post_message_after_pre_message() -> Result<()> { .send_webxdc_status_update(alice_instance.id, r#"{"payload":42, "info":"i"}"#) .await?; - send_msg(alice, alice_chat_id, &mut alice_instance).await?; + chat::send_msg(alice, alice_chat_id, &mut alice_instance).await?; let post_message = alice.pop_sent_msg().await; let pre_message = alice.pop_sent_msg().await; @@ -591,7 +648,7 @@ async fn test_webxdc_updates_in_post_message_without_pre_message() -> Result<()> .send_webxdc_status_update(alice_instance.id, r#"{"payload":42, "info":"i"}"#) .await?; - send_msg(alice, alice_chat_id, &mut alice_instance).await?; + chat::send_msg(alice, alice_chat_id, &mut alice_instance).await?; let post_message = alice.pop_sent_msg().await; let pre_message = alice.pop_sent_msg().await; @@ -644,7 +701,10 @@ async fn test_markseen_pre_msg() -> Result<()> { assert_eq!( alice .sql - .count("SELECT COUNT(*) FROM smtp_mdns", ()) + .count( + "SELECT COUNT(*) FROM smtp_mdns WHERE from_id=?", + (msg.from_id,) + ) .await?, 1 );