diff --git a/src/chat.rs b/src/chat.rs index 69cfd0d95e..a5e2e5de26 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -4305,6 +4305,14 @@ pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId) msg.viewtype = Viewtype::Text; } + if msg.download_state != DownloadState::Done { + // we don't use Message.get_text() here, + // because it may change in future, + // when UI shows this info itself, + // then the additional_text will not be added in get_text anymore. + msg.text += &msg.additional_text; + } + msg.param.remove(Param::GuaranteeE2ee); msg.param.remove(Param::ForcePlaintext); msg.param.remove(Param::Cmd); @@ -4316,6 +4324,8 @@ pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId) msg.param.remove(Param::IsEdited); msg.param.remove(Param::WebrtcRoom); msg.param.remove(Param::WebrtcAccepted); + msg.param.remove(Param::PostMessageFileBytes); + msg.param.remove(Param::PostMessageViewtype); msg.in_reply_to = None; // do not leak data as group names; a default subject is generated by mimefactory @@ -4382,12 +4392,22 @@ pub(crate) async fn save_copy_in_self_talk( msg.param.remove(Param::WebxdcDocumentTimestamp); msg.param.remove(Param::WebxdcSummary); msg.param.remove(Param::WebxdcSummaryTimestamp); + msg.param.remove(Param::PostMessageFileBytes); + msg.param.remove(Param::PostMessageViewtype); + + if msg.download_state != DownloadState::Done { + // we don't use Message.get_text() here, + // because it may change in future, + // when UI shows this info itself, + // then the additional_text will not be added in get_text anymore. + msg.text += &msg.additional_text; + } if !msg.original_msg_id.is_unset() { bail!("message already saved."); } - let copy_fields = "from_id, to_id, timestamp_rcvd, type, txt, + let copy_fields = "from_id, to_id, timestamp_rcvd, type, mime_modified, mime_headers, mime_compressed, mime_in_reply_to, subject, msgrmsg"; let row_id = context .sql @@ -4395,7 +4415,7 @@ pub(crate) async fn save_copy_in_self_talk( &format!( "INSERT INTO msgs ({copy_fields}, timestamp_sent, - chat_id, rfc724_mid, state, timestamp, param, starred) + txt, chat_id, rfc724_mid, state, timestamp, param, starred) SELECT {copy_fields}, -- Outgoing messages on originating device -- have timestamp_sent == 0. @@ -4403,10 +4423,11 @@ pub(crate) async fn save_copy_in_self_talk( -- so UIs display the same timestamp -- for saved and original message. IIF(timestamp_sent == 0, timestamp, timestamp_sent), - ?, ?, ?, ?, ?, ? + ?, ?, ?, ?, ?, ?, ? FROM msgs WHERE id=?;" ), ( + msg.text, dest_chat_id, dest_rfc724_mid, if msg.from_id == ContactId::SELF { diff --git a/src/download.rs b/src/download.rs index 8a709183f7..38a2f3622e 100644 --- a/src/download.rs +++ b/src/download.rs @@ -289,7 +289,11 @@ pub(crate) async fn download_msgs(context: &Context, session: &mut Session) -> R ); remove_from_download_table(context, rfc724_mid).await?; } else if available_post_msgs_contains_rfc724_mid(context, rfc724_mid).await? { - // set the message to DownloadState::Failure - probably it was deleted on the server in the meantime + warn!( + context, + "{rfc724_mid} is in available_post_msgs table but we failed to fetch it, + so set the message to DownloadState::Failure - probably it was deleted on the server in the meantime" + ); set_msg_state_to_failed(context, rfc724_mid).await?; remove_from_download_table(context, rfc724_mid).await?; remove_from_available_post_msgs_table(context, rfc724_mid).await?; diff --git a/src/imap.rs b/src/imap.rs index 3c0153beb6..8622e1932b 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -716,6 +716,7 @@ impl Imap { .get_header_value(HeaderDef::ChatIsPostMessage) .is_some() { + info!(context, "{} is a post message", message_id.clone()); // This is a Post-Message available_post_msgs.push(message_id.clone()); @@ -731,6 +732,7 @@ impl Imap { false } } else { + info!(context, "{} is not a post message", message_id.clone()); // This is not a Post-Message if is_background_fetch { if size < MAX_FETCH_MSG_SIZE { @@ -824,6 +826,12 @@ impl Imap { // TODO: is there correct place for this? if fetch_res.is_ok() { + info!( + context, + "available_post_msgs: {}, download_when_normal_starts: {}", + available_post_msgs.len(), + download_when_normal_starts.len() + ); for rfc724_mid in available_post_msgs { context .sql diff --git a/src/scheduler.rs b/src/scheduler.rs index c019c0691f..1234b96444 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -664,6 +664,7 @@ async fn fetch_idle( Ok(session) } +/// The simplified IMAP IDLE loop to watch non primary folders (non-inbox folders) async fn simple_imap_loop( ctx: Context, started: oneshot::Sender<()>, diff --git a/src/tests/pre_messages/forward_and_save.rs b/src/tests/pre_messages/forward_and_save.rs new file mode 100644 index 0000000000..a3ca16ed8a --- /dev/null +++ b/src/tests/pre_messages/forward_and_save.rs @@ -0,0 +1,122 @@ +//! Tests about forwarding and saving Pre-Messages +use anyhow::Result; +use pretty_assertions::assert_eq; + +use crate::chat::{self}; +use crate::chat::{forward_msgs, save_msgs}; +use crate::chatlist::get_last_message_for_chat; +use crate::download::{DownloadState, PRE_MSG_ATTACHMENT_SIZE_THRESHOLD}; +use crate::message::{Message, Viewtype}; +use crate::test_utils::TestContextManager; + +/// Test that forwarding Pre-Message should forward additional text to not be empty +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_forwarding_pre_message_empty_text() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + let bob = &tcm.bob().await; + let alice_group_id = alice.create_group_with_members("test group", &[bob]).await; + + let pre_message = { + let mut msg = Message::new(Viewtype::File); + msg.set_file_from_bytes(alice, "test.bin", &vec![0u8; 1_000_000], None)?; + assert!(msg.get_filebytes(alice).await?.unwrap() > PRE_MSG_ATTACHMENT_SIZE_THRESHOLD); + let msg_id = chat::send_msg(alice, alice_group_id, &mut msg).await?; + let smtp_rows = alice.get_smtp_rows_for_msg(msg_id).await; + assert_eq!(smtp_rows.len(), 2); + smtp_rows.first().expect("Pre-Message exists").to_owned() + }; + + let bob_msg = bob.recv_msg(&pre_message).await; + assert_eq!(bob_msg.download_state, DownloadState::Available); + bob_msg.chat_id.accept(bob).await?; + tcm.section("forward pre message and check it on bobs side"); + forward_msgs(bob, &[bob_msg.id], bob_msg.chat_id).await?; + let forwarded_msg_id = get_last_message_for_chat(bob, bob_msg.chat_id) + .await? + .unwrap(); + let forwarded_msg = Message::load_from_db(bob, forwarded_msg_id).await?; + assert_eq!(forwarded_msg.is_forwarded(), true); + assert_eq!(forwarded_msg.download_state(), DownloadState::Done); + assert_eq!( + forwarded_msg + .param + .exists(crate::param::Param::PostMessageFileBytes), + false, + "PostMessageFileBytes not set" + ); + assert_eq!( + forwarded_msg + .param + .exists(crate::param::Param::PostMessageViewtype), + false, + "PostMessageViewtype not set" + ); + assert_eq!( + forwarded_msg.get_text(), + " [test.bin - 976.56 KiB]".to_owned() + ); + assert_eq!(forwarded_msg.get_viewtype(), Viewtype::Text); + assert!(forwarded_msg.additional_text.is_empty()); + tcm.section("check it on alices side"); + let sent_forward_msg = bob.pop_sent_msg().await; + let alice_forwarded_msg = alice.recv_msg(&sent_forward_msg).await; + assert!(alice_forwarded_msg.additional_text.is_empty()); + assert_eq!(alice_forwarded_msg.is_forwarded(), true); + assert_eq!(alice_forwarded_msg.download_state(), DownloadState::Done); + assert_eq!( + alice_forwarded_msg + .param + .exists(crate::param::Param::PostMessageFileBytes), + false, + "PostMessageFileBytes not set" + ); + assert_eq!( + alice_forwarded_msg + .param + .exists(crate::param::Param::PostMessageViewtype), + false, + "PostMessageViewtype not set" + ); + assert_eq!( + alice_forwarded_msg.get_text(), + " [test.bin - 976.56 KiB]".to_owned() + ); + + Ok(()) +} + +/// Test that forwarding Pre-Message should forward additional text to not be empty +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_saving_pre_message_empty_text() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + let bob = &tcm.bob().await; + let alice_group_id = alice.create_group_with_members("test group", &[bob]).await; + + let pre_message = { + let mut msg = Message::new(Viewtype::File); + msg.set_file_from_bytes(alice, "test.bin", &vec![0u8; 1_000_000], None)?; + assert!(msg.get_filebytes(alice).await?.unwrap() > PRE_MSG_ATTACHMENT_SIZE_THRESHOLD); + let msg_id = chat::send_msg(alice, alice_group_id, &mut msg).await?; + let smtp_rows = alice.get_smtp_rows_for_msg(msg_id).await; + assert_eq!(smtp_rows.len(), 2); + smtp_rows.first().expect("Pre-Message exists").to_owned() + }; + + let bob_msg = bob.recv_msg(&pre_message).await; + assert_eq!(bob_msg.download_state, DownloadState::Available); + bob_msg.chat_id.accept(bob).await?; + tcm.section("save pre message and check it"); + save_msgs(bob, &[bob_msg.id]).await?; + let saved_msg_id = get_last_message_for_chat(bob, bob.get_self_chat().await.id) + .await? + .unwrap(); + let saved_msg = Message::load_from_db(bob, saved_msg_id).await?; + assert!(saved_msg.additional_text.is_empty()); + assert!(saved_msg.get_original_msg_id(bob).await?.is_some()); + assert_eq!(saved_msg.download_state(), DownloadState::Done); + assert_eq!(saved_msg.get_text(), " [test.bin - 976.56 KiB]".to_owned()); + + Ok(()) +} diff --git a/src/tests/pre_messages/mod.rs b/src/tests/pre_messages/mod.rs index f9f3543452..a0387ddee4 100644 --- a/src/tests/pre_messages/mod.rs +++ b/src/tests/pre_messages/mod.rs @@ -1,4 +1,5 @@ mod additional_text; +mod forward_and_save; mod legacy; mod receiving; mod sending;