From 25ac5a23630d0c88a75f4f31372d283a28939306 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Mon, 27 Apr 2026 15:30:23 -0300 Subject: [PATCH] fix: Fail receive_imf to not tombstone reaction if the referenced message isn't found A reaction may arrive earler than the referenced message in case of multi-transport. By not creating a tombstone we still can receive it later on another transport. --- deltachat-rpc-client/tests/test_something.py | 2 +- src/imap.rs | 16 +++--- src/reaction.rs | 55 ++++++++++++++++++-- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index fe329b4bf..d742a90b6 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -348,7 +348,7 @@ def test_receive_imf_failure(acfactory) -> None: snapshot.text == "❌ Failed to receive a message:" " Condition failed: `!context.get_config_bool(Config::SimulateReceiveImfError).await?`." f" Core version {version}." - " Please report this bug to delta@merlinux.eu or https://support.delta.chat/." + " Please report this bug to delta@merlinux.eu or https://support.delta.chat/" ) # The failed message doesn't break the IMAP loop. diff --git a/src/imap.rs b/src/imap.rs index 892253bc2..17439321c 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -1383,13 +1383,15 @@ impl Session { let res = receive_imf_inner(context, rfc724_mid, body, is_seen).await; let received_msg = match res { Err(err) => { - warn!(context, "receive_imf error: {err:#}."); - - let text = format!( - "❌ Failed to receive a message: {err:#}. Core version v{DC_VERSION_STR}. Please report this bug to delta@merlinux.eu or https://support.delta.chat/.", - ); - let mut msg = Message::new_text(text); - add_device_msg(context, None, Some(&mut msg)).await?; + let err = format!("{err:#}"); + warn!(context, "receive_imf error: {err}."); + if !err.contains("(SKIP_DEVICE_MSG)") { + let text = format!( + "❌ Failed to receive a message: {err}. Core version v{DC_VERSION_STR}. Please report this bug to delta@merlinux.eu or https://support.delta.chat/", + ); + let mut msg = Message::new_text(text); + add_device_msg(context, None, Some(&mut msg)).await?; + } None } Ok(msg) => msg, diff --git a/src/reaction.rs b/src/reaction.rs index b459a132e..3d2f3d2c1 100644 --- a/src/reaction.rs +++ b/src/reaction.rs @@ -18,7 +18,7 @@ use std::cmp::Ordering; use std::collections::BTreeMap; use std::fmt; -use anyhow::Result; +use anyhow::{Result, bail}; use serde::{Deserialize, Serialize}; use crate::chat::{Chat, ChatId, send_msg}; @@ -259,9 +259,8 @@ pub(crate) async fn set_msg_reaction( }); } } else { - info!( - context, - "Can't assign reaction to unknown message with Message-ID {}", in_reply_to + bail!( + "Can't assign reaction to unknown message with Message-ID {in_reply_to} (SKIP_DEVICE_MSG)" ); } Ok(()) @@ -519,6 +518,54 @@ Content-Disposition: reaction\n\ Ok(()) } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_reaction_and_multitransport() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + let device_chat_id = ChatId::get_for_contact(alice, ContactId::DEVICE).await?; + let n_device_msgs = get_chat_msgs(alice, device_chat_id).await?.len(); + + let reaction_bytes = "To: alice@example.org, claire@example.org\n\ +From: bob@example.net\n\ +Date: Today, 29 February 2021 00:00:10 -800\n\ +Message-ID: 56789@example.net\n\ +In-Reply-To: 12345@example.org\n\ +Content-Type: text/plain; charset=utf-8\n\ +Content-Disposition: reaction\n\ +\n\ +\u{1F44D}" + .as_bytes(); + // Alice receives a reaction to Claire's message from Bob earler than the message itself + // because Bob knows about Alice's new transport. + assert!(receive_imf(alice, reaction_bytes, false).await.is_err()); + + let msg_id = receive_imf( + alice, + "To: alice@example.org, bob@example.net\n\ +From: claire@example.org\n\ +Date: Today, 29 February 2021 00:00:00 -800\n\ +Message-ID: 12345@example.org\n\ +\n\ +Can we chat at 1pm pacific, today?" + .as_bytes(), + false, + ) + .await? + .unwrap() + .msg_ids[0]; + + // Finally the reaction arrives on Alice's older transport. + receive_imf(alice, reaction_bytes, false).await?; + let reactions = get_msg_reactions(alice, msg_id).await?; + assert_eq!(reactions.to_string(), "👍1"); + + assert_eq!( + get_chat_msgs(alice, device_chat_id).await?.len(), + n_device_msgs + ); + Ok(()) + } + async fn expect_reactions_changed_event( t: &TestContext, expected_chat_id: ChatId,