From cdea0f994227f584828c9a081d4f54a05221d92c Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sat, 4 Feb 2023 14:19:24 +0000 Subject: [PATCH] Implement responses for more error cases --- src/channel.rs | 34 ++++++++++++++++++++++++++++------ src/channel/permissions.rs | 4 ++-- src/channel/response.rs | 36 ++++++++++++++++++++++++++++++++++++ src/client.rs | 15 +++++++++++---- src/connection.rs | 6 +++--- 5 files changed, 80 insertions(+), 15 deletions(-) diff --git a/src/channel.rs b/src/channel.rs index 9daa630..15100d9 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -9,7 +9,7 @@ use actix::{ }; use chrono::{DateTime, Utc}; use futures::future::Either; -use irc_proto::{Command, Message, Mode}; +use irc_proto::{Command, Message, Mode, Response}; use tracing::{debug, error, info, instrument, warn, Span}; use crate::{ @@ -17,6 +17,7 @@ use crate::{ permissions::Permission, response::{ ChannelInviteResult, ChannelJoinRejectionReason, ChannelNamesList, ChannelTopic, + MissingPrivileges, }, }, client::Client, @@ -137,8 +138,22 @@ impl Handler for Channel { }; if !self.get_user_permissions(sender.user_id).can_chatter() { - // TODO - error!("User cannot send message to channel"); + msg.client.do_send(Broadcast { + message: Message { + tags: None, + prefix: None, + command: Command::Response( + Response::ERR_CANNOTSENDTOCHAN, + vec![ + sender.to_nick().to_string(), + self.name.to_string(), + "Cannot send to channel".to_string(), + ], + ), + }, + span: Span::current(), + }); + return; } @@ -421,8 +436,12 @@ impl Handler for Channel { .get_user_permissions(client_info.user_id) .can_set_topic() { - // TODO - error!("User cannot set channel topic"); + error!("User attempted to set channel topic without privileges"); + msg.client.do_send(Broadcast { + message: MissingPrivileges(client_info.to_nick(), self.name.to_string()) + .into_message(), + span: Span::current(), + }); return; } @@ -455,8 +474,11 @@ impl Handler for Channel { }; if !self.get_user_permissions(kicker.user_id).can_kick() { - // TODO error!("Kicker can not kick people from the channel"); + msg.client.do_send(Broadcast { + message: MissingPrivileges(kicker.to_nick(), self.name.to_string()).into_message(), + span: Span::current(), + }); return; } diff --git a/src/channel/permissions.rs b/src/channel/permissions.rs index af63c85..6351713 100644 --- a/src/channel/permissions.rs +++ b/src/channel/permissions.rs @@ -90,8 +90,8 @@ impl Permission { /// Returns true, if the user is allowed to kick people from the channel. #[must_use] - pub fn can_kick(self) -> bool { - self == Self::Operator + pub const fn can_kick(self) -> bool { + (self as i16) >= (Self::HalfOperator as i16) } /// Returns true, if the user is allowed to set the given permission on another diff --git a/src/channel/response.rs b/src/channel/response.rs index 2bec2e8..68bc75c 100644 --- a/src/channel/response.rs +++ b/src/channel/response.rs @@ -183,3 +183,39 @@ impl ChannelInviteResult { pub enum ChannelJoinRejectionReason { Banned, } + +impl ChannelJoinRejectionReason { + #[must_use] + pub fn into_message(self) -> Message { + match self { + Self::Banned => Message { + tags: None, + prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())), + command: Command::Response( + Response::ERR_BANNEDFROMCHAN, + vec!["Cannot join channel (+b)".to_string()], + ), + }, + } + } +} + +pub struct MissingPrivileges(pub Prefix, pub String); + +impl MissingPrivileges { + #[must_use] + pub fn into_message(self) -> Message { + Message { + tags: None, + prefix: None, + command: Command::Response( + Response::ERR_CHANOPRIVSNEEDED, + vec![ + self.0.to_string(), + self.1, + "You're not channel operator".to_string(), + ], + ), + } + } +} diff --git a/src/client.rs b/src/client.rs index 6c2636d..3d38d16 100644 --- a/src/client.rs +++ b/src/client.rs @@ -15,7 +15,10 @@ use tracing::{debug, error, info, info_span, instrument, warn, Instrument, Span} use crate::{ channel::Channel, - connection::{sasl::SaslAlreadyAuthenticated, Capability, InitiatedConnection, MessageSink}, + connection::{ + sasl::SaslAlreadyAuthenticated, Capability, InitiatedConnection, MessageSink, + NickNotOwnedByUser, + }, messages::{ Broadcast, ChannelFetchTopic, ChannelInvite, ChannelJoin, ChannelKickUser, ChannelList, ChannelMemberList, ChannelMessage, ChannelPart, ChannelSetMode, ChannelUpdateTopic, @@ -263,7 +266,8 @@ impl Handler for Client { let handle = match handle { Ok(v) => v, Err(error) => { - error!(?error, "Failed to join user to channel"); + error!(?error, "User failed to join channel"); + this.writer.write(error.into_message()); continue; } }; @@ -346,7 +350,10 @@ impl Handler for Client { .into_actor(self) .map(|res, this, ctx| { if !res.unwrap() { - // TODO: send notification to user to say the nick isn't available + ctx.notify(Broadcast { + message: NickNotOwnedByUser(msg.new_nick).into_message(), + span: Span::current(), + }); return; } @@ -667,7 +674,7 @@ impl StreamHandler> for Client { self.writer.write(Message { tags: None, - prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())), + prefix: None, command: Command::Response( Response::RPL_TIME, vec![ diff --git a/src/connection.rs b/src/connection.rs index ad1bf46..84fd8ab 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -226,7 +226,7 @@ pub async fn negotiate_client_connection( Ok(Some(initiated)) } -pub struct NickNotOwnedByUser(String); +pub struct NickNotOwnedByUser(pub String); impl NickNotOwnedByUser { #[must_use] @@ -235,8 +235,8 @@ impl NickNotOwnedByUser { tags: None, prefix: None, command: Command::Response( - Response::ERR_NICKLOCKED, - vec![self.0, "You must use a nick assigned to you".to_string()], + Response::ERR_NICKNAMEINUSE, + vec![self.0, "Nickname is already in use".to_string()], ), } } -- libgit2 1.7.2