Skip to content

Commit f2a82d8

Browse files
committed
fix: Don't emit CallMissed for those who aren't allowed to call us (#7840)
The previous commit replaces `CallEnded` and `IncomingMsg` events with `CallMissed` for missed calls, but as the latter is supposed to trigger notifications, it shalln't be emitted for calls from those who aren't allowed to call us.
1 parent 315fc00 commit f2a82d8

2 files changed

Lines changed: 108 additions & 70 deletions

File tree

src/calls.rs

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ impl Context {
224224
context,
225225
wait.try_into()?,
226226
call.id,
227+
true, // Doesn't matter for outgoing calls
227228
));
228229

229230
Ok(call.id)
@@ -317,6 +318,7 @@ impl Context {
317318
context: WeakContext,
318319
wait: u64,
319320
call_id: MsgId,
321+
can_call_me: bool,
320322
) -> Result<()> {
321323
sleep(Duration::from_secs(wait)).await;
322324
let context = context.upgrade()?;
@@ -333,7 +335,9 @@ impl Context {
333335
call.mark_as_canceled(&context).await?;
334336
let missed_call_str = stock_str::missed_call(&context).await;
335337
call.update_text(&context, &missed_call_str).await?;
336-
context.emit_event(EventType::CallMissed { msg_id, chat_id });
338+
if can_call_me {
339+
context.emit_event(EventType::CallMissed { msg_id, chat_id });
340+
}
337341
} else {
338342
call.mark_as_ended(&context).await?;
339343
let canceled_call_str = stock_str::canceled_call(&context).await;
@@ -345,6 +349,30 @@ impl Context {
345349
Ok(())
346350
}
347351

352+
async fn can_call_me(&self, from_id: ContactId) -> Result<bool> {
353+
Ok(match who_can_call_me(self).await? {
354+
WhoCanCallMe::Contacts => ChatIdBlocked::lookup_by_contact(self, from_id)
355+
.await?
356+
.is_some_and(|chat_id_blocked| {
357+
match chat_id_blocked.blocked {
358+
Blocked::Not => true,
359+
Blocked::Yes | Blocked::Request => {
360+
// Do not notify about incoming calls
361+
// from contact requests and blocked contacts.
362+
//
363+
// User can still access the call and accept it
364+
// via the chat in case of contact requests.
365+
false
366+
}
367+
}
368+
}),
369+
WhoCanCallMe::Everybody => ChatIdBlocked::lookup_by_contact(self, from_id)
370+
.await?
371+
.is_none_or(|chat_id_blocked| chat_id_blocked.blocked != Blocked::Yes),
372+
WhoCanCallMe::Nobody => false,
373+
})
374+
}
375+
348376
pub(crate) async fn handle_call_msg(
349377
&self,
350378
call_id: MsgId,
@@ -358,53 +386,33 @@ impl Context {
358386
};
359387

360388
if call.is_incoming() {
361-
if call.is_stale() {
362-
let missed_call_str = stock_str::missed_call(self).await;
363-
call.update_text(self, &missed_call_str).await?;
364-
// TODO: Don't notify for blocked contacts
365-
let (msg_id, chat_id) = (call_id, call.msg.chat_id);
389+
let call_str = match call.is_stale() {
390+
true => stock_str::missed_call(self).await,
391+
false => stock_str::incoming_call(self, call.has_video_initially()).await,
392+
};
393+
call.update_text(self, &call_str).await?;
394+
let (msg_id, chat_id) = (call_id, call.msg.chat_id);
395+
let can_call_me = self.can_call_me(from_id).await?;
396+
if !can_call_me {
397+
} else if call.is_stale() {
366398
self.emit_event(EventType::CallMissed { msg_id, chat_id });
367-
self.emit_msgs_changed(chat_id, msg_id);
368399
} else {
369-
let incoming_call_str =
370-
stock_str::incoming_call(self, call.has_video_initially()).await;
371-
call.update_text(self, &incoming_call_str).await?;
372-
self.emit_msgs_changed(call.msg.chat_id, call_id); // ringing calls are not additionally notified
373-
let can_call_me = match who_can_call_me(self).await? {
374-
WhoCanCallMe::Contacts => ChatIdBlocked::lookup_by_contact(self, from_id)
375-
.await?
376-
.is_some_and(|chat_id_blocked| {
377-
match chat_id_blocked.blocked {
378-
Blocked::Not => true,
379-
Blocked::Yes | Blocked::Request => {
380-
// Do not notify about incoming calls
381-
// from contact requests and blocked contacts.
382-
//
383-
// User can still access the call and accept it
384-
// via the chat in case of contact requests.
385-
false
386-
}
387-
}
388-
}),
389-
WhoCanCallMe::Everybody => ChatIdBlocked::lookup_by_contact(self, from_id)
390-
.await?
391-
.is_none_or(|chat_id_blocked| chat_id_blocked.blocked != Blocked::Yes),
392-
WhoCanCallMe::Nobody => false,
393-
};
394-
if can_call_me {
395-
self.emit_event(EventType::IncomingCall {
396-
msg_id: call.msg.id,
397-
chat_id: call.msg.chat_id,
398-
place_call_info: call.place_call_info.to_string(),
399-
has_video: call.has_video_initially(),
400-
});
401-
}
400+
self.emit_event(EventType::IncomingCall {
401+
msg_id,
402+
chat_id,
403+
place_call_info: call.place_call_info.to_string(),
404+
has_video: call.has_video_initially(),
405+
});
406+
}
407+
self.emit_msgs_changed(chat_id, msg_id);
408+
if !call.is_stale() {
402409
let wait = call.remaining_ring_seconds();
403410
let context = self.get_weak_context();
404411
task::spawn(Context::emit_end_call_if_unaccepted(
405412
context,
406413
wait.try_into()?,
407414
call.msg.id,
415+
can_call_me,
408416
));
409417
}
410418
} else {
@@ -468,7 +476,9 @@ impl Context {
468476
call.mark_as_canceled(self).await?;
469477
let missed_call_str = stock_str::missed_call(self).await;
470478
call.update_text(self, &missed_call_str).await?;
471-
self.emit_event(EventType::CallMissed { msg_id, chat_id });
479+
if self.can_call_me(from_id).await? {
480+
self.emit_event(EventType::CallMissed { msg_id, chat_id });
481+
}
472482
}
473483
} else {
474484
// outgoing

src/calls/calls_tests.rs

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -436,36 +436,64 @@ async fn test_caller_cancels_call() -> Result<()> {
436436
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
437437
async fn test_stale_call() -> Result<()> {
438438
let mut tcm = TestContextManager::new();
439-
let alice = &tcm.alice().await;
440-
let bob = &tcm.bob().await;
441-
442-
let alice_chat = alice.create_chat(bob).await;
443-
alice
444-
.place_outgoing_call(alice_chat.id, PLACE_INFO.to_string(), true)
445-
.await?;
446-
let sent1 = alice.pop_sent_msg().await;
447-
448-
SystemTime::shift(Duration::from_secs(3600));
449-
let bob_call = bob.recv_msg(&sent1).await;
450-
bob.evtracker
451-
.get_matching(|evt| matches!(evt, EventType::CallMissed { .. }))
452-
.await;
453-
let EventType::MsgsChanged { msg_id, chat_id } = bob
454-
.evtracker
455-
.get_matching(|evt| matches!(evt, EventType::MsgsChanged { .. }))
456-
.await
457-
else {
458-
unreachable!();
459-
};
460-
assert_eq!(msg_id, bob_call.id);
461-
assert_eq!(chat_id, bob_call.chat_id);
462-
assert_text(bob, bob_call.id, "Missed call").await?;
463-
assert_eq!(call_state(bob, bob_call.id).await?, CallState::Missed);
439+
for accepted in [false, true] {
440+
let alice = &tcm.alice().await;
441+
let bob = &tcm.bob().await;
464442

465-
// Test that message summary says it is a missed call.
466-
let bob_call_msg = Message::load_from_db(bob, bob_call.id).await?;
467-
let summary = bob_call_msg.get_summary(bob, None).await?;
468-
assert_eq!(summary.text, "🎥 Missed call");
443+
info!(bob, "Alice is accepted: {accepted}.");
444+
if accepted {
445+
bob.create_chat(alice).await;
446+
}
447+
let alice_chat = alice.create_chat(bob).await;
448+
alice
449+
.place_outgoing_call(alice_chat.id, PLACE_INFO.to_string(), true)
450+
.await?;
451+
let sent1 = alice.pop_sent_msg().await;
452+
453+
SystemTime::shift(Duration::from_secs(3600));
454+
let bob_call = bob.recv_msg(&sent1).await;
455+
let EventType::MsgsChanged { msg_id, chat_id } = bob
456+
.evtracker
457+
.get_matching(|evt| {
458+
matches!(
459+
evt,
460+
EventType::MsgsChanged { .. } | EventType::CallMissed { .. }
461+
)
462+
})
463+
.await
464+
else {
465+
unreachable!();
466+
};
467+
assert_eq!(chat_id, bob_call.chat_id);
468+
let msg = Message::load_from_db(bob, msg_id).await?;
469+
assert_eq!(msg.text, stock_str::messages_e2e_encrypted(bob).await);
470+
if accepted {
471+
bob.evtracker
472+
.get_matching(|evt| matches!(evt, EventType::CallMissed { .. }))
473+
.await;
474+
}
475+
let EventType::MsgsChanged { msg_id, chat_id } = bob
476+
.evtracker
477+
.get_matching(|evt| {
478+
matches!(
479+
evt,
480+
EventType::MsgsChanged { .. } | EventType::CallMissed { .. }
481+
)
482+
})
483+
.await
484+
else {
485+
unreachable!();
486+
};
487+
assert_eq!(msg_id, bob_call.id);
488+
assert_eq!(chat_id, bob_call.chat_id);
489+
assert_text(bob, bob_call.id, "Missed call").await?;
490+
assert_eq!(call_state(bob, bob_call.id).await?, CallState::Missed);
491+
492+
// Test that message summary says it is a missed call.
493+
let bob_call_msg = Message::load_from_db(bob, bob_call.id).await?;
494+
let summary = bob_call_msg.get_summary(bob, None).await?;
495+
assert_eq!(summary.text, "🎥 Missed call");
496+
}
469497
Ok(())
470498
}
471499

0 commit comments

Comments
 (0)