From 1a8fbe56090990fd0ae1a204dc2ada2744a1c32e Mon Sep 17 00:00:00 2001 From: Val Lorentz Date: Sat, 2 Sep 2023 19:36:19 +0200 Subject: [PATCH] Implement IRCv3 away-notify --- sable_ircd/src/capability/mod.rs | 1 + sable_ircd/src/messages/message.rs | 2 ++ sable_ircd/src/messages/send_history.rs | 18 +++++++++++++++++- sable_network/src/node/update_receiver.rs | 17 ++++++++++++++++- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/sable_ircd/src/capability/mod.rs b/sable_ircd/src/capability/mod.rs index fd923091..88dae55b 100644 --- a/sable_ircd/src/capability/mod.rs +++ b/sable_ircd/src/capability/mod.rs @@ -70,6 +70,7 @@ define_capabilities! ( Batch: 0x10 => ("batch", true), LabeledResponse: 0x20 => ("labeled-response", true), UserhostInNames: 0x40 => ("userhost-in-names", true), + AwayNotify: 0x80 => ("away-notify", true), ChatHistory: 0x100 => ("draft/chathistory", true), PersistentSession: 0x200 => ("sable.libera.chat/persistent-session", true), diff --git a/sable_ircd/src/messages/message.rs b/sable_ircd/src/messages/message.rs index 2bb94d18..4bd8265a 100644 --- a/sable_ircd/src/messages/message.rs +++ b/sable_ircd/src/messages/message.rs @@ -4,6 +4,8 @@ use super::*; use sable_macros::define_messages; define_messages! { + Away => { (source, reason: &str) => ":{source} AWAY :{reason}" }, + Unaway => { (source) => ":{source} AWAY" }, Cap => { (source, target, subcmd: &str, text: &str) => ":{source} CAP {target} {subcmd} :{text}" }, Nick => { (source, newnick: &Nickname) => ":{source} NICK {newnick}" }, Join => { (source, chan: &ChannelName) => ":{source} JOIN {chan}" }, diff --git a/sable_ircd/src/messages/send_history.rs b/sable_ircd/src/messages/send_history.rs index 7ec8b773..995bf331 100644 --- a/sable_ircd/src/messages/send_history.rs +++ b/sable_ircd/src/messages/send_history.rs @@ -50,13 +50,22 @@ impl SendHistoryItem for update::NewUser { } impl SendHistoryItem for update::UserAwayChange { - fn send_to(&self, conn: impl MessageSink, _from_entry: &HistoryLogEntry) -> HandleResult { + fn send_to(&self, conn: impl MessageSink, from_entry: &HistoryLogEntry) -> HandleResult { if Some(self.user.user.id) == conn.user_id() { + // Echo back to the user let message = match self.new_reason { None => numeric::Unaway::new(), Some(_) => numeric::NowAway::new(), }; conn.send(message.format_for(&self.user, &self.user)); + } else { + // Tell other users sharing a channel if they enabled away-notify + let message = match self.new_reason { + None => message::Unaway::new(&self.user), + Some(reason) => message::Away::new(&self.user, reason.value()), + }; + let message = message.with_tags_from(from_entry); + conn.send(message.with_required_capabilities(ClientCapability::AwayNotify)); } Ok(()) @@ -193,6 +202,13 @@ impl SendHistoryItem for update::ChannelJoin { conn.send(msg); } + if let Some(away_reason) = self.user.user.away_reason { + let message = + message::Away::new(&self.user, &away_reason.value()).with_tags_from(from_entry); + + conn.send(message.with_required_capabilities(ClientCapability::AwayNotify)); + } + Ok(()) } } diff --git a/sable_network/src/node/update_receiver.rs b/sable_network/src/node/update_receiver.rs index 85d0f3bf..cddd6bb9 100644 --- a/sable_network/src/node/update_receiver.rs +++ b/sable_network/src/node/update_receiver.rs @@ -26,7 +26,22 @@ impl NetworkNode { entry: &HistoryLogEntry, detail: &update::UserAwayChange, ) -> HandleResult { - self.notify_user(detail.user.user.id, entry.id); + let net = self.network(); + let source = net.user(detail.user.user.id)?; + + let mut notified = HashSet::new(); + + // Notify the source user themselves, even if they are not in any channel + notified.insert(detail.user.user.id); + + for m1 in source.channels() { + let chan = m1.channel()?; + for m2 in chan.members() { + notified.insert(m2.user_id()); + } + } + + self.notify_users(notified, entry.id); Ok(()) }