From bdd2421072bf3334f1bc05c03f1c5ec1ceac46f6 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sun, 8 Jan 2023 00:00:11 +0000 Subject: [PATCH] Implement SANICK command --- src/client.rs | 58 +++++++++++++++++++++++++++++++++++++++------------------- src/messages.rs | 9 +++++++++ src/server.rs | 20 +++++++++++++++++++- 3 files changed, 67 insertions(+), 20 deletions(-) diff --git a/src/client.rs b/src/client.rs index 7fc1927..722718b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -17,6 +17,7 @@ use crate::{ Broadcast, ChannelFetchTopic, ChannelInvite, ChannelJoin, ChannelKickUser, ChannelList, ChannelMemberList, ChannelMessage, ChannelPart, ChannelUpdateTopic, FetchClientDetails, ServerDisconnect, ServerFetchMotd, UserKickedFromChannel, UserNickChange, + UserNickChangeInternal, }, server::Server, SERVER_NAME, @@ -221,6 +222,34 @@ impl Handler for Client { } } +impl Handler for Client { + type Result = (); + + #[instrument(parent = &msg.span, skip_all)] + fn handle(&mut self, msg: UserNickChangeInternal, ctx: &mut Self::Context) -> Self::Result { + // alert the server to the nick change (we'll receive this event back so the user + // gets the notification too) + self.server.do_send(UserNickChange { + client: ctx.address(), + connection: self.connection.clone(), + new_nick: msg.new_nick.clone(), + span: Span::current(), + }); + + for channel in self.channels.values() { + channel.do_send(UserNickChange { + client: ctx.address(), + connection: self.connection.clone(), + new_nick: msg.new_nick.clone(), + span: Span::current(), + }); + } + + // updates our nick locally + self.connection.nick = msg.new_nick; + } +} + /// A message received from the root server to indicate that another known user has changed their /// nick impl Handler for Client { @@ -280,26 +309,11 @@ impl StreamHandler> for Client { // these were already handled by `negotiate_client_connection` } Command::NICK(new_nick) => { - // alert the server to the nick change (we'll receive this event back so the user - // gets the notification too) - self.server.do_send(UserNickChange { - client: ctx.address(), - connection: self.connection.clone(), - new_nick: new_nick.clone(), + ctx.notify(UserNickChangeInternal { + old_nick: self.connection.nick.to_string(), + new_nick, span: Span::current(), }); - - for channel in self.channels.values() { - channel.do_send(UserNickChange { - client: ctx.address(), - connection: self.connection.clone(), - new_nick: new_nick.clone(), - span: Span::current(), - }); - } - - // updates our nick locally - self.connection.nick = new_nick; } Command::OPER(_, _) => {} Command::UserMODE(_, _) => {} @@ -499,7 +513,13 @@ impl StreamHandler> for Client { Command::ISON(_) => {} Command::SAJOIN(_, _) => {} Command::SAMODE(_, _, _) => {} - Command::SANICK(_, _) => {} + Command::SANICK(old_nick, new_nick) => { + self.server.do_send(UserNickChangeInternal { + old_nick, + new_nick, + span: Span::current(), + }); + } Command::SAPART(_, _) => {} Command::SAQUIT(_, _) => {} Command::NICKSERV(_) => {} diff --git a/src/messages.rs b/src/messages.rs index 94344cc..4b54dba 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -23,6 +23,15 @@ pub struct ServerDisconnect { pub span: Span, } +/// Internal event to update a user's nick. +#[derive(Message, Clone)] +#[rtype(result = "()")] +pub struct UserNickChangeInternal { + pub old_nick: String, + pub new_nick: String, + pub span: Span, +} + /// Sent when the user changes their nick. #[derive(Message, Clone)] #[rtype(result = "()")] diff --git a/src/server.rs b/src/server.rs index 8346421..5fa8adc 100644 --- a/src/server.rs +++ b/src/server.rs @@ -6,7 +6,7 @@ use actix::{Actor, Addr, AsyncContext, Context, Handler, MessageResult, Response use futures::{stream::FuturesOrdered, TryFutureExt}; use irc_proto::{Command, Message, Prefix, Response}; use tokio_stream::StreamExt; -use tracing::{instrument, Span}; +use tracing::{debug, instrument, warn, Span}; use crate::{ channel::Channel, @@ -16,6 +16,7 @@ use crate::{ messages::{ Broadcast, ChannelFetchTopic, ChannelJoin, ChannelList, ChannelMemberList, FetchClientByNick, ServerDisconnect, ServerFetchMotd, UserConnected, UserNickChange, + UserNickChangeInternal, }, server::response::Motd, SERVER_NAME, @@ -28,6 +29,23 @@ pub struct Server { pub config: Config, } +/// Received when an admin SANICKs another user. +impl Handler for Server { + type Result = (); + + fn handle(&mut self, msg: UserNickChangeInternal, _ctx: &mut Self::Context) -> Self::Result { + let client = self.clients.iter().find(|(_k, v)| v.nick == msg.old_nick); + let Some((client, _)) = client else { + warn!(%msg.old_nick, %msg.new_nick, "User attempted to update nick for unknown user"); + return; + }; + + debug!(%msg.old_nick, %msg.new_nick, "User is updating nick for another user"); + + client.do_send(msg); + } +} + /// Received when a user connects to the server, and sends them the server preamble impl Handler for Server { type Result = (); -- libgit2 1.7.2