From ab50e2dbc0db3974f2ba3b60c2203cff54313103 Mon Sep 17 00:00:00 2001 From: Markus Laaksonen Date: Fri, 22 Mar 2024 13:49:53 +0200 Subject: [PATCH 1/6] fix(mode): handle k mode properly --- src/channel/Channel.cpp | 21 ++++++++++++++------- src/command/actionMode.cpp | 12 +++++++++--- src/common/magicNumber.h | 3 ++- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/channel/Channel.cpp b/src/channel/Channel.cpp index c737141..4379ef6 100644 --- a/src/channel/Channel.cpp +++ b/src/channel/Channel.cpp @@ -346,20 +346,27 @@ int Channel::handleModeChange(Client& allowedClient, modestruct& modeStruct) { return FAILURE; } setKey(modeStruct.param); - sendMessageToMembers( - COM_MESSAGE(allowedClient.getNickname(), allowedClient.getUserName(), allowedClient.getHost(), "MODE", name_ + " +k")); + sendMessageToMembers(COM_MESSAGE(allowedClient.getNickname(), allowedClient.getUserName(), allowedClient.getHost(), "MODE", + name_ + " +k " + modeStruct.param)); return SUCCESS; } if (modeStruct.modifier == '-') { if (modeStruct.param.empty()) { - LOG_DEBUG("Channel::handleModeChange: k: -k with a parameter, not setting"); - allowedClient.appendToSendBuffer(RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, allowedClient.getNickname(), "MODE")); + LOG_DEBUG("Channel::handleModeChange: k: -k without a parameter, not setting, not returning anything"); + return FAILURE; + } + if (getKey().empty() == true) { + LOG_DEBUG( + "Channel::handleModeChange: k: -k with a parameter, but key is already unset, not setting, not returning anything"); + return FAILURE; + } + if (modeStruct.param != getKey()) { + LOG_DEBUG("Channel::handleModeChange: k: -k with a parameter that doesn't match the key, not returning anything"); return FAILURE; } - // key mode is being unset even if it's already unset setKey(""); - sendMessageToMembers( - COM_MESSAGE(allowedClient.getNickname(), allowedClient.getUserName(), allowedClient.getHost(), "MODE", name_ + " -k")); + sendMessageToMembers(COM_MESSAGE(allowedClient.getNickname(), allowedClient.getUserName(), allowedClient.getHost(), "MODE", + name_ + " -k " + modeStruct.param)); return SUCCESS; } return FAILURE; diff --git a/src/command/actionMode.cpp b/src/command/actionMode.cpp index e06677e..4ce80a8 100644 --- a/src/command/actionMode.cpp +++ b/src/command/actionMode.cpp @@ -4,8 +4,14 @@ static bool isModeSupported(char mode) { return std::string(SUPPORTED_CHANNEL_MODES).find(mode) != std::string::npos; } -static bool isModeWithParam(char mode) { - return std::string(SUPPORTED_CHANNEL_MODES_WITH_PARAM).find(mode) != std::string::npos; +static bool isModeWithParam(irc::Channel::modestruct mode) { + if (mode.modifier == '+') { + return std::string(SUPPORTED_CHANNEL_MODES_PLUS_WITH_PARAM).find(mode.mode) != std::string::npos; + } + if (mode.modifier == '-') { + return std::string(SUPPORTED_CHANNEL_MODES_MINUS_WITH_PARAM).find(mode.mode) != std::string::npos; + } + return false; } static bool isNextParamExist(unsigned int currentParamIndex, unsigned long numberOfParams) { @@ -122,7 +128,7 @@ void Command::actionMode(Client& client) { modeRequests.push_back(currentMode); } - if (isNextParamExist(currentParamIndex, numberOfParams) && isModeWithParam(modeRequests.back().mode)) { + if (isNextParamExist(currentParamIndex, numberOfParams) && isModeWithParam(modeRequests.back())) { modeChangesWithParam++; currentParamIndex++; modeRequests.back().param = param_.at(currentParamIndex); diff --git a/src/common/magicNumber.h b/src/common/magicNumber.h index 9584990..9f0ae13 100644 --- a/src/common/magicNumber.h +++ b/src/common/magicNumber.h @@ -4,7 +4,8 @@ #define IRC_SERVER_VERSION "ft_irc-v1.0" #define SUPPORTED_USER_MODES "io" #define SUPPORTED_CHANNEL_MODES "oitkl" -#define SUPPORTED_CHANNEL_MODES_WITH_PARAM "kol" +#define SUPPORTED_CHANNEL_MODES_PLUS_WITH_PARAM "okl" +#define SUPPORTED_CHANNEL_MODES_MINUS_WITH_PARAM "ok" #define CHANNEL_PREFIXES "#&" #define CHANNEL_SYMBOL_PUBLIC "=" #define CHANNEL_OPERATOR_SYMBOL "@" From 099084c066cc7221e7673e06f665e9dd7aa22286 Mon Sep 17 00:00:00 2001 From: Markus Laaksonen Date: Fri, 22 Mar 2024 14:14:18 +0200 Subject: [PATCH 2/6] fix(mode): incorrect MODE replies mode parameters must show in replies to channel members, hide otherwise --- src/command/actionMode.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/command/actionMode.cpp b/src/command/actionMode.cpp index 4ce80a8..a8d6230 100644 --- a/src/command/actionMode.cpp +++ b/src/command/actionMode.cpp @@ -62,22 +62,38 @@ void Command::actionMode(Client& client) { // We know that the channel exists Channel& channel = allChannels_.at(param_.at(0)); + // Save info about if the client is a member of the channel + std::vector clientChannels = client.getMyChannels(); + bool isMember = false; + for (std::string clientChannel : clientChannels) { + if (clientChannel == param_.at(0)) { + isMember = true; + break; + } + } + // Get the modes and return if the channel is the only parameter - std::string enabledModes; + std::string enabledModesString; + std::string enabledParamsString; if (numberOfParams == 1) { if (channel.isInviteOnly() == true) { - enabledModes += "i"; + enabledModesString += "i"; } if (channel.isTopicProtected() == true) { - enabledModes += "t"; + enabledModesString += "t"; } if (channel.getKey().empty() == false) { - enabledModes += "k"; + enabledModesString += "k"; + enabledParamsString += " " + channel.getKey(); } if (channel.getUserLimit() != CHANNEL_USER_LIMIT_DISABLED) { - enabledModes += "l"; + enabledModesString += "l"; + enabledParamsString += " " + std::to_string(channel.getUserLimit()); + } + if (isMember == true) { + enabledModesString += enabledParamsString; } - client.appendToSendBuffer(RPL_CHANNELMODEIS_324(serverHostname_g, client.getNickname(), channel.getName(), enabledModes)); + client.appendToSendBuffer(RPL_CHANNELMODEIS_324(serverHostname_g, client.getNickname(), channel.getName(), enabledModesString)); return; } From a1b7094771721566bdbb7519895a577308f7bd34 Mon Sep 17 00:00:00 2001 From: Markus Laaksonen Date: Fri, 22 Mar 2024 14:16:39 +0200 Subject: [PATCH 3/6] fix(part): uninvite warning check if invited before uninviting --- src/channel/Channel.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/channel/Channel.cpp b/src/channel/Channel.cpp index 4379ef6..60a05a6 100644 --- a/src/channel/Channel.cpp +++ b/src/channel/Channel.cpp @@ -112,7 +112,9 @@ int Channel::partMember(Client& client) { LOG_DEBUG("Channel::partMember: client " << client.getNickname() << " was an operator, removing"); setOperatorStatus(client, false); } - uninvite(client); + if (isInvited(client)) { + uninvite(client); + } members_.erase(it); if (operators_.empty()) { LOG_DEBUG("Channel::partMember: no operators left, a new operator should be assigned: " << name_); From 7c3b9c5bf2ad5ee440f5e2e07dbd2737dba2bd28 Mon Sep 17 00:00:00 2001 From: Markus Laaksonen Date: Fri, 22 Mar 2024 14:32:37 +0200 Subject: [PATCH 4/6] feat(mode): verbose debug logs --- src/command/actionMode.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/command/actionMode.cpp b/src/command/actionMode.cpp index a8d6230..f28adf9 100644 --- a/src/command/actionMode.cpp +++ b/src/command/actionMode.cpp @@ -36,6 +36,7 @@ void Command::actionMode(Client& client) { unsigned long numberOfParams = param_.size(); if (numberOfParams == 0) { + LOG_DEBUG("Command::actionMode: numberOfParams == 0 not allowed"); client.appendToSendBuffer(RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); return; } @@ -45,6 +46,7 @@ void Command::actionMode(Client& client) { // Handle actionMode for a user if (std::string(CHANNEL_PREFIXES).find(param_.at(0).front()) == std::string::npos) { // We know that the first parameter is not a channel + LOG_DEBUG("Command::actionMode: first param does not have a channel prefix, so it must be a user, not implemented"); client.appendToSendBuffer(RPL_ERR_UMODEUNKNOWNFLAG_501(serverHostname_g, client.getNickname())); // TODO: placeholder // TODO: implement user mode changes return; @@ -55,6 +57,7 @@ void Command::actionMode(Client& client) { Channel& channel = allChannels_.at(param_.at(0)); (void)channel; // suppress unused variable warning } catch (const std::out_of_range& e) { + LOG_DEBUG("Command::actionMode: channel does not exist"); client.appendToSendBuffer(RPL_ERR_NOSUCHCHANNEL_403(serverHostname_g, param_.at(0))); return; } @@ -101,6 +104,7 @@ void Command::actionMode(Client& client) { // Check if the client is a channel operator, otherwise return if (channel.isOperator(client) == false) { + LOG_DEBUG("Command::actionMode: client is not a channel operator"); client.appendToSendBuffer(RPL_ERR_CHANOPRIVSNEEDED_482(serverHostname_g, client.getNickname(), channel.getName())); return; } @@ -129,13 +133,15 @@ void Command::actionMode(Client& client) { std::string& currentParamString = param_.at(currentParamIndex); char currentModifier = currentParamString[0]; if (currentModifier != '+' && currentModifier != '-') { + LOG_DEBUG("Command::actionMode: currentModifier != '+' && currentModifier != '-' not allowed"); client.appendToSendBuffer( - RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); // TODO: figure out correct reply + RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); return; } currentParamString = currentParamString.substr(1); for (char mode : currentParamString) { if (isModeSupported(mode) == false) { + LOG_DEBUG("Command::actionMode: mode not supported: " + mode); client.appendToSendBuffer(RPL_ERR_UNKNOWNMODE_472(serverHostname_g, client.getNickname(), mode, channel.getName())); return; } @@ -152,8 +158,9 @@ void Command::actionMode(Client& client) { currentParamIndex++; } if (modeChangesWithParam > 3) { + LOG_DEBUG("Command::actionMode: modeChangesWithParam > 3 not allowed"); client.appendToSendBuffer( - RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); // TODO: figure out correct reply + RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); return; } From b84bac908b355a5de959b91a08907ae99927cd78 Mon Sep 17 00:00:00 2001 From: Markus Laaksonen Date: Fri, 22 Mar 2024 15:16:25 +0200 Subject: [PATCH 5/6] fix(mode): improper log debug not compiling --- src/command/actionMode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/actionMode.cpp b/src/command/actionMode.cpp index f28adf9..fd0ede9 100644 --- a/src/command/actionMode.cpp +++ b/src/command/actionMode.cpp @@ -141,7 +141,7 @@ void Command::actionMode(Client& client) { currentParamString = currentParamString.substr(1); for (char mode : currentParamString) { if (isModeSupported(mode) == false) { - LOG_DEBUG("Command::actionMode: mode not supported: " + mode); + LOG_DEBUG("Command::actionMode: mode not supported: " << mode); client.appendToSendBuffer(RPL_ERR_UNKNOWNMODE_472(serverHostname_g, client.getNickname(), mode, channel.getName())); return; } From 3ea0005c199a3b2673750fea4771e0983bbb70a6 Mon Sep 17 00:00:00 2001 From: Markus Laaksonen Date: Fri, 22 Mar 2024 15:17:27 +0200 Subject: [PATCH 6/6] feat(mode): accept alternative MODE syntax --- src/command/actionMode.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/command/actionMode.cpp b/src/command/actionMode.cpp index fd0ede9..077fe77 100644 --- a/src/command/actionMode.cpp +++ b/src/command/actionMode.cpp @@ -118,7 +118,8 @@ void Command::actionMode(Client& client) { // o: operator (parameter: nickname) // l: user-limit (parameter: limit) - // We will get something like: MODE #mychannel +ik key +tl 10 + // We will get something like: MODE #mychannel +ik key +tl 10 + // We can also get something like: MODE #mychannel +ktl key 10 +i // We will parse it into a vector of modestructs like this: // vector[0]: {modifier: '+', mode: 'i', param: ""} // vector[1]: {modifier: '+', mode: 'k', param: "key"} @@ -126,6 +127,7 @@ void Command::actionMode(Client& client) { // vector[3]: {modifier: '+', mode: 'l', param: "10"} std::vector modeRequests; + unsigned long oldModeRequestsSize = modeRequests.size(); int modeChangesWithParam = 0; // max is 3 unsigned int currentParamIndex = 1; // max is numberOfParams - 1 while (currentParamIndex < numberOfParams) { @@ -134,8 +136,7 @@ void Command::actionMode(Client& client) { char currentModifier = currentParamString[0]; if (currentModifier != '+' && currentModifier != '-') { LOG_DEBUG("Command::actionMode: currentModifier != '+' && currentModifier != '-' not allowed"); - client.appendToSendBuffer( - RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); + client.appendToSendBuffer(RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); return; } currentParamString = currentParamString.substr(1); @@ -150,17 +151,26 @@ void Command::actionMode(Client& client) { modeRequests.push_back(currentMode); } - if (isNextParamExist(currentParamIndex, numberOfParams) && isModeWithParam(modeRequests.back())) { - modeChangesWithParam++; - currentParamIndex++; - modeRequests.back().param = param_.at(currentParamIndex); + for (unsigned long i = oldModeRequestsSize; i < modeRequests.size(); i++) { + if (isModeWithParam(modeRequests.at(i))) { + if (isNextParamExist(currentParamIndex, numberOfParams)) { + modeChangesWithParam++; + currentParamIndex++; + modeRequests.at(i).param = param_.at(currentParamIndex); + } else { + LOG_DEBUG("Command::actionMode: mode with param but no param provided"); + client.appendToSendBuffer(RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); + return; + } + } } + + oldModeRequestsSize = modeRequests.size(); currentParamIndex++; } if (modeChangesWithParam > 3) { LOG_DEBUG("Command::actionMode: modeChangesWithParam > 3 not allowed"); - client.appendToSendBuffer( - RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); + client.appendToSendBuffer(RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); return; }