Skip to content

Commit cc54a3f

Browse files
committed
fix: do not try to process calls from partial messages
Any control information from the message should only be downloaded when the message is fully downloaded to avoid processing it twice. Besides, "partial" messages may actually be full messages with an error that are only processed as partial to add a message bubble allowing to download the message later.
1 parent 94984f3 commit cc54a3f

File tree

2 files changed

+70
-6
lines changed

2 files changed

+70
-6
lines changed

src/calls/calls_tests.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::*;
22
use crate::chat::forward_msgs;
33
use crate::config::Config;
44
use crate::constants::DC_CHAT_ID_TRASH;
5-
use crate::receive_imf::receive_imf;
5+
use crate::receive_imf::{receive_imf, receive_imf_from_inbox};
66
use crate::test_utils::{TestContext, TestContextManager};
77

88
struct CallSetup {
@@ -604,3 +604,65 @@ async fn test_end_text_call() -> Result<()> {
604604

605605
Ok(())
606606
}
607+
608+
/// Tests that partially downloaded "call ended"
609+
/// messages are not processed.
610+
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
611+
async fn test_no_partial_calls() -> Result<()> {
612+
let mut tcm = TestContextManager::new();
613+
let alice = &tcm.alice().await;
614+
615+
let seen = false;
616+
617+
// The messages in the test
618+
// have no `Date` on purpose,
619+
// so they are treated as new.
620+
let received_call = receive_imf(
621+
alice,
622+
b"From: bob@example.net\n\
623+
To: alice@example.org\n\
624+
Message-ID: <first@example.net>\n\
625+
Chat-Version: 1.0\n\
626+
Chat-Content: call\n\
627+
Chat-Webrtc-Room: YWFhYWFhYWFhCg==\n\
628+
\n\
629+
Hello, this is a call\n",
630+
seen,
631+
)
632+
.await?
633+
.unwrap();
634+
assert_eq!(received_call.msg_ids.len(), 1);
635+
let call_msg = Message::load_from_db(alice, received_call.msg_ids[0])
636+
.await
637+
.unwrap();
638+
assert_eq!(call_msg.viewtype, Viewtype::Call);
639+
assert_eq!(call_state(alice, call_msg.id).await?, CallState::Alerting);
640+
641+
let imf_raw = b"From: bob@example.net\n\
642+
To: alice@example.org\n\
643+
Message-ID: <second@example.net>\n\
644+
In-Reply-To: <first@example.net>\n\
645+
Chat-Version: 1.0\n\
646+
Chat-Content: call-ended\n\
647+
\n\
648+
Call ended\n";
649+
receive_imf_from_inbox(
650+
alice,
651+
"second@example.net",
652+
imf_raw,
653+
seen,
654+
Some(imf_raw.len().try_into().unwrap()),
655+
)
656+
.await?;
657+
658+
// The call is still not ended.
659+
assert_eq!(call_state(alice, call_msg.id).await?, CallState::Alerting);
660+
661+
// Fully downloading the message ends the call.
662+
receive_imf_from_inbox(alice, "second@example.net", imf_raw, seen, None)
663+
.await
664+
.context("Failed to fully download end call message")?;
665+
assert_eq!(call_state(alice, call_msg.id).await?, CallState::Missed);
666+
667+
Ok(())
668+
}

src/receive_imf.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ pub(crate) async fn receive_imf_inner(
999999
}
10001000
}
10011001

1002-
if mime_parser.is_call() {
1002+
if is_partial_download.is_none() && mime_parser.is_call() {
10031003
context
10041004
.handle_call_msg(insert_msg_id, &mime_parser, from_id)
10051005
.await?;
@@ -1157,8 +1157,9 @@ async fn decide_chat_assignment(
11571157
{
11581158
info!(context, "Chat edit/delete/iroh/sync message (TRASH).");
11591159
true
1160-
} else if mime_parser.is_system_message == SystemMessage::CallAccepted
1161-
|| mime_parser.is_system_message == SystemMessage::CallEnded
1160+
} else if is_partial_download.is_none()
1161+
&& (mime_parser.is_system_message == SystemMessage::CallAccepted
1162+
|| mime_parser.is_system_message == SystemMessage::CallEnded)
11621163
{
11631164
info!(context, "Call state changed (TRASH).");
11641165
true
@@ -1986,8 +1987,9 @@ async fn add_parts(
19861987

19871988
handle_edit_delete(context, mime_parser, from_id).await?;
19881989

1989-
if mime_parser.is_system_message == SystemMessage::CallAccepted
1990-
|| mime_parser.is_system_message == SystemMessage::CallEnded
1990+
if is_partial_download.is_none()
1991+
&& (mime_parser.is_system_message == SystemMessage::CallAccepted
1992+
|| mime_parser.is_system_message == SystemMessage::CallEnded)
19911993
{
19921994
if let Some(field) = mime_parser.get_header(HeaderDef::InReplyTo) {
19931995
if let Some(call) =

0 commit comments

Comments
 (0)