Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix and improve mode #100

Merged
merged 6 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions src/channel/Channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_);
Expand Down Expand Up @@ -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;
Expand Down
73 changes: 56 additions & 17 deletions src/command/actionMode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -49,36 +57,54 @@ 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;
}

// 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<std::string> 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;
}

// Now we know that we have at least two parameters

// 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;
}
Expand All @@ -92,28 +118,31 @@ 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"}
// vector[2]: {modifier: '+', mode: 't', param: ""}
// vector[3]: {modifier: '+', mode: 'l', param: "10"}

std::vector<Channel::modestruct> modeRequests;
unsigned long oldModeRequestsSize = modeRequests.size();
int modeChangesWithParam = 0; // max is 3
unsigned int currentParamIndex = 1; // max is numberOfParams - 1
while (currentParamIndex < numberOfParams) {
Channel::modestruct currentMode;
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;
}
Expand All @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion src/common/magicNumber.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 "@"
Expand Down
Loading