Skip to content

Commit 5bf3676

Browse files
vikng-devclaude
andauthored
fix(whatsapp): treat a reply to the bot as addressing it (#1217)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 3b92dd6 commit 5bf3676

2 files changed

Lines changed: 46 additions & 3 deletions

File tree

crates/whatsapp/src/handlers.rs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -834,12 +834,21 @@ fn context_info_mentions_owner(
834834
own_lid: Option<&Jid>,
835835
) -> bool {
836836
context.is_some_and(|context| {
837-
context.mentioned_jid.iter().any(|mentioned| {
837+
let mentioned = context.mentioned_jid.iter().any(|mentioned| {
838838
mentioned
839839
.parse::<Jid>()
840840
.ok()
841841
.is_some_and(|jid| is_owner_user(&jid, own_pn, own_lid))
842-
})
842+
});
843+
// A reply is the other way to address someone in a group. It sets
844+
// `participant` to the quoted message's author and leaves
845+
// `mentioned_jid` empty, so checking mentions alone drops every reply.
846+
let replied_to = context
847+
.participant
848+
.as_deref()
849+
.and_then(|participant| participant.parse::<Jid>().ok())
850+
.is_some_and(|jid| is_owner_user(&jid, own_pn, own_lid));
851+
mentioned || replied_to
843852
})
844853
}
845854

@@ -1168,6 +1177,40 @@ async fn handle_otp_flow(
11681177
mod tests {
11691178
use {super::*, wacore::types::message::MessageSource};
11701179

1180+
fn reply_context(participant: &str) -> wa::ContextInfo {
1181+
wa::ContextInfo {
1182+
participant: Some(participant.to_owned()),
1183+
..Default::default()
1184+
}
1185+
}
1186+
1187+
#[test]
1188+
fn reply_to_the_bot_counts_as_a_mention() {
1189+
let own_pn: Jid = "15551234567@s.whatsapp.net".parse().unwrap();
1190+
let ctx = reply_context("15551234567@s.whatsapp.net");
1191+
1192+
assert!(ctx.mentioned_jid.is_empty(), "a reply carries no mention");
1193+
assert!(context_info_mentions_owner(Some(&ctx), Some(&own_pn), None));
1194+
}
1195+
1196+
#[test]
1197+
fn reply_to_anyone_else_does_not() {
1198+
let own_pn: Jid = "15551234567@s.whatsapp.net".parse().unwrap();
1199+
let own_lid: Jid = "259557842534599@lid".parse().unwrap();
1200+
1201+
for ctx in [
1202+
reply_context("11111111111@s.whatsapp.net"),
1203+
reply_context("not a jid"),
1204+
wa::ContextInfo::default(),
1205+
] {
1206+
assert!(!context_info_mentions_owner(
1207+
Some(&ctx),
1208+
Some(&own_pn),
1209+
Some(&own_lid)
1210+
));
1211+
}
1212+
}
1213+
11711214
#[test]
11721215
fn owner_self_chat_detected_without_is_from_me_when_sender_and_chat_are_owner() {
11731216
let own_lid: Jid = "259557842534599@lid".parse().unwrap();

docs/src/whatsapp.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ WhatsApp uses the same access control model as Telegram channels.
209209
| Mode | Behavior |
210210
|------|----------|
211211
| `always` | Bot may respond to allowed group messages without an @mention |
212-
| `mention` | Bot only responds in allowed groups when the account is @mentioned |
212+
| `mention` | Bot only responds in allowed groups when the account is @mentioned, or when someone replies to one of its messages |
213213
| `none` | Bot never responds in groups |
214214

215215
### OTP Self-Approval

0 commit comments

Comments
 (0)