From 85756a6a8fd501482cde14bc263d338a05b16dd1 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Tue, 30 Jan 2024 20:27:34 +0000 Subject: [PATCH] Implement SAQUIT --- src/client.rs | 42 +++++++++++++++++++++++++++++++++++------- src/messages.rs | 8 ++++++++ src/server.rs | 20 +++++++++++++++++--- src/server/response.rs | 18 ++++++++++++++++++ 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/client.rs b/src/client.rs index 9de2125..7afc711 100644 --- a/src/client.rs +++ b/src/client.rs @@ -24,9 +24,9 @@ use crate::{ Broadcast, ChannelFetchTopic, ChannelFetchWhoList, ChannelInvite, ChannelJoin, ChannelKickUser, ChannelList, ChannelMemberList, ChannelMessage, ChannelPart, ChannelSetMode, ChannelUpdateTopic, ClientAway, ConnectedChannels, FetchClientDetails, - FetchUserPermission, FetchWhoList, FetchWhois, KillUser, MessageKind, PrivateMessage, - ServerAdminInfo, ServerDisconnect, ServerFetchMotd, ServerListUsers, UserKickedFromChannel, - UserNickChange, UserNickChangeInternal, Wallops, + FetchUserPermission, FetchWhoList, FetchWhois, ForceDisconnect, KillUser, MessageKind, + PrivateMessage, ServerAdminInfo, ServerDisconnect, ServerFetchMotd, ServerListUsers, + UserKickedFromChannel, UserNickChange, UserNickChangeInternal, Wallops, }, persistence::{ events::{ @@ -35,7 +35,10 @@ use crate::{ }, Persistence, }, - server::{response::WhoList, Server}, + server::{ + response::{NoSuchNick, WhoList}, + Server, + }, SERVER_NAME, }; @@ -296,6 +299,15 @@ impl Handler for Client { } } +impl Handler for Client { + type Result = MessageResult; + + fn handle(&mut self, _msg: ForceDisconnect, ctx: &mut Self::Context) -> Self::Result { + ctx.stop(); + MessageResult(true) + } +} + /// Retrieves the entire WHO list for the user. impl Handler for Client { type Result = ResponseFuture<::Result>; @@ -380,7 +392,7 @@ impl Handler for Client { impl Handler for Client { type Result = (); - #[instrument(parent = & msg.span, skip_all)] + #[instrument(parent = &msg.span, skip_all)] fn handle(&mut self, msg: KillUser, ctx: &mut Self::Context) -> Self::Result { self.server_leave_reason = Some(format!("Killed ({} ({}))", msg.killer, msg.comment)); ctx.stop(); @@ -900,7 +912,6 @@ impl StreamHandler> for Client { Command::REHASH => {} Command::DIE => {} Command::RESTART => {} - Command::USERS(_) => {} Command::WALLOPS(message) if self.connection.mode.contains(UserMode::OPER) => { self.server.do_send(Wallops { span: Span::current(), @@ -919,7 +930,24 @@ impl StreamHandler> for Client { }); } Command::SAPART(_, _) => {} - Command::SAQUIT(_, _) => {} + Command::SAQUIT(user, comment) if self.connection.mode.contains(UserMode::OPER) => { + let span = Span::current(); + self.server_send_map_write( + ctx, + ForceDisconnect { + span, + user: user.to_string(), + comment, + }, + move |res, this| { + if res { + vec![] + } else { + NoSuchNick { nick: user }.into_messages(&this.connection.nick) + } + }, + ); + } Command::AUTHENTICATE(_) => { self.writer.write( SaslAlreadyAuthenticated(self.connection.nick.to_string()).into_message(), diff --git a/src/messages.rs b/src/messages.rs index 8265e2e..ab1aec6 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -37,6 +37,14 @@ pub struct KillUser { pub killed: String, } +#[derive(Message, Clone)] +#[rtype(result = "bool")] +pub struct ForceDisconnect { + pub span: Span, + pub user: String, + pub comment: String, +} + /// Internal event to update a user's nick. #[derive(Message, Clone)] #[rtype(result = "()")] diff --git a/src/server.rs b/src/server.rs index 7b78b19..c3c386d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -26,9 +26,9 @@ use crate::{ messages::{ Broadcast, ChannelFetchTopic, ChannelFetchWhoList, ChannelJoin, ChannelList, ChannelMemberList, ClientAway, ConnectedChannels, FetchClientByNick, FetchWhoList, - FetchWhois, KillUser, MessageKind, PrivateMessage, ServerAdminInfo, ServerDisconnect, - ServerFetchMotd, ServerListUsers, UserConnected, UserNickChange, UserNickChangeInternal, - Wallops, + FetchWhois, ForceDisconnect, KillUser, MessageKind, PrivateMessage, ServerAdminInfo, + ServerDisconnect, ServerFetchMotd, ServerListUsers, UserConnected, UserNickChange, + UserNickChangeInternal, Wallops, }, persistence::Persistence, server::response::{AdminInfo, ListUsers, Motd, WhoList, Whois}, @@ -306,6 +306,20 @@ impl Handler for Server { } } +impl Handler for Server { + type Result = MessageResult; + + #[instrument(parent = &msg.span, skip_all)] + fn handle(&mut self, msg: ForceDisconnect, _ctx: &mut Self::Context) -> Self::Result { + if let Some((handle, _)) = self.clients.iter().find(|(_, v)| v.nick == msg.user) { + handle.do_send(msg); + MessageResult(true) + } else { + MessageResult(false) + } + } +} + impl Handler for Server { type Result = ResponseFuture<::Result>; diff --git a/src/server/response.rs b/src/server/response.rs index 94c5fec..3f75c04 100644 --- a/src/server/response.rs +++ b/src/server/response.rs @@ -84,6 +84,24 @@ impl Whois { } } +pub struct NoSuchNick { + pub nick: String, +} + +impl NoSuchNick { + #[must_use] + pub fn into_messages(self, for_user: &str) -> Vec { + vec![Message { + tags: None, + prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())), + command: Command::Response( + Response::ERR_NOSUCHNICK, + vec![for_user.to_string(), self.nick, "No such nick".to_string()], + ), + }] + } +} + #[derive(Default)] pub struct WhoList { pub list: Vec,