diff --git a/src/channel/Channel.cpp b/src/channel/Channel.cpp index c737141..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_); @@ -346,20 +348,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..077fe77 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) { @@ -30,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; } @@ -39,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; @@ -49,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; } @@ -56,22 +65,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()); } - client.appendToSendBuffer(RPL_CHANNELMODEIS_324(serverHostname_g, client.getNickname(), channel.getName(), enabledModes)); + if (isMember == true) { + enabledModesString += enabledParamsString; + } + client.appendToSendBuffer(RPL_CHANNELMODEIS_324(serverHostname_g, client.getNickname(), channel.getName(), enabledModesString)); return; } @@ -79,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; } @@ -92,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"} @@ -100,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) { @@ -107,13 +135,14 @@ void Command::actionMode(Client& client) { std::string& currentParamString = param_.at(currentParamIndex); char currentModifier = currentParamString[0]; if (currentModifier != '+' && currentModifier != '-') { - client.appendToSendBuffer( - RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); // TODO: figure out correct reply + LOG_DEBUG("Command::actionMode: currentModifier != '+' && currentModifier != '-' not allowed"); + client.appendToSendBuffer(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; } @@ -122,16 +151,26 @@ void Command::actionMode(Client& client) { modeRequests.push_back(currentMode); } - if (isNextParamExist(currentParamIndex, numberOfParams) && isModeWithParam(modeRequests.back().mode)) { - 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) { - client.appendToSendBuffer( - RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); // TODO: figure out correct reply + LOG_DEBUG("Command::actionMode: modeChangesWithParam > 3 not allowed"); + client.appendToSendBuffer(RPL_ERR_NEEDMOREPARAMS_461(serverHostname_g, client.getNickname(), "MODE")); return; } 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 "@"