From ef84846267a3498f6ed911ad1264cf2acd8f8b9e Mon Sep 17 00:00:00 2001 From: reverse Date: Sun, 16 Aug 2026 19:11:57 +0000 Subject: [PATCH] invite: route INVITE for a remote target to its server and deliver inbound INVITE --- src/coremods/core_channel.rs | 12 ++++++++++++ src/link.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/coremods/core_channel.rs b/src/coremods/core_channel.rs index 63295ce..3a08309 100644 --- a/src/coremods/core_channel.rs +++ b/src/coremods/core_channel.rs @@ -281,6 +281,18 @@ impl Command for Invite { return CmdResult::Fail; } let Some(tuid) = s.find_nick(tnick) else { + // remote target: route the invite to the server that owns it + if let Some((tuuid, _)) = s.find_remote(tnick) { + let iuuid = s.users[&uid].uuid.clone(); + s.route_invite(&iuuid, &tuuid, chan); + let rnick = s + .remote_users + .get(&tuuid) + .map(|r| r.nick.clone()) + .unwrap_or_else(|| tnick.to_string()); + s.numeric(uid, RPL_INVITING, &format!("{rnick} {chan}")); + return CmdResult::Ok; + } s.numeric( uid, ERR_NOSUCHNICK, diff --git a/src/link.rs b/src/link.rs index 9d26a7c..4ac28ec 100644 --- a/src/link.rs +++ b/src/link.rs @@ -168,6 +168,7 @@ impl Server { "QUIT" if registered => self.link_quit_recv(uid, msg), "KILL" if registered => self.link_kill_recv(uid, msg), "SAVE" if registered => self.link_save_recv(uid, msg), + "INVITE" if registered => self.link_invite_recv(uid, msg), "ADDLINE" if registered => self.link_addline_recv(uid, msg), "DELLINE" if registered => self.link_delline_recv(uid, msg), "PRIVMSG" if registered => self.link_message_recv(uid, msg, false), @@ -1141,6 +1142,37 @@ impl Server { } } + /// Route an INVITE toward the server that owns a remote `target` uuid. + pub fn route_invite(&self, inviter: &str, target: &str, chan: &str) { + if let Some(v) = self.link_toward(target) { + self.link_out(v, format!(":{inviter} INVITE {target} {chan}")); + } + } + + /// `: INVITE ` — deliver an invite to a local target (record + /// it so they bypass +i, and notify them), or forward toward a remote one. + fn link_invite_recv(&mut self, via: Uid, msg: &Message) { + let Some(src) = msg.source.clone() else { + return; + }; + let (Some(target), Some(chan)) = + (msg.params.first().cloned(), msg.params.get(1).cloned()) + else { + return; + }; + if let Some(&luid) = self.uuid_local.get(&target) { + let key = chan.to_ascii_lowercase(); + if let Some(ch) = self.channels.get_mut(&key) { + ch.invites.insert(luid); + } + let prefix = self.uuid_prefix(&src).unwrap_or_else(|| src.clone()); + let nick = self.users.get(&luid).map(|u| u.nick.clone()).unwrap_or_default(); + self.send(luid, format!(":{prefix} INVITE {nick} :{chan}")); + } else { + self.forward_to_target(&target, msg, via); + } + } + /// `: ADDLINE :` — a /// network ban set on a peer (e.g. a services akill). Apply and relay onward. fn link_addline_recv(&mut self, via: Uid, msg: &Message) {