Skip to content

Commit

Permalink
Channel command : major refacto join, invite, part, kick, list, names…
Browse files Browse the repository at this point in the history
…, server

* feat(part): reply for users on channel to do

* feat(invite): in progress

* feat(invite, kick): error cases handled

* fix(join): fix segfault with channel creation

* add binary to git ignore

* delete binary

* feat(invite, kick, part): add protection if channel list is empty + kick error cases

* fix(join, part, invite, kick): reply system changed

* feat(kick, join, part): fix segfault on part + kick done + join message sent

* fix(server): get ip address from client

* fix(join): joining message not displayed

* fix(join): message displayed

* fix(server): command in upper case

* working?

* fix(server): commands are case insensitive

* fix(join): rpl name in progress

* fix(join): rpl name fixed

* feat(topics): topics to be tested

* feat(topic): topic command ok

* feat(list): list command

* feat(names): command names

* fix(part): send to channel before removing user

Co-authored-by: Lea LESCURE <[email protected]>
Co-authored-by: Lea LESCURE <[email protected]>
Co-authored-by: llescure <[email protected]>
  • Loading branch information
4 people authored Aug 1, 2022
1 parent 4bf1b4b commit 1bbb3b2
Show file tree
Hide file tree
Showing 18 changed files with 446 additions and 119 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ SRCS = srcs/main.cpp \
srcs/channel/join.cpp \
srcs/channel/part.cpp \
srcs/channel/invite.cpp \
srcs/channel/kick.cpp \
srcs/channel/topic.cpp \
srcs/channel/list.cpp \
srcs/channel/names.cpp \
srcs/user/User.cpp \
srcs/commands/kill.cpp \
srcs/commands/nick.cpp \
Expand Down
5 changes: 3 additions & 2 deletions includes/User.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# include <iostream>
# include <stdint.h>
# include <vector>
# include <deque>
# include <ctime>

# define ST_ALIVE 1
Expand Down Expand Up @@ -41,7 +42,7 @@ class User {
uint8_t _mode;
bool _password;
bool _authenticated;
std::vector<std::string> _channelsJoined;
std::deque<std::string> _channelsJoined;
int _status;
time_t _lastActivityTime;
time_t _pingTime;
Expand All @@ -62,7 +63,7 @@ class User {
uint8_t getMode(void) const;
bool getPassword(void) const;
bool getAuthenticated(void) const;
std::vector<std::string> getChannelsJoined(void) const;
std::deque<std::string> getChannelsJoined(void) const;
int getStatus(void) const;
time_t getLastActivityTime(void) const;
time_t getPingTime(void) const;
Expand Down
1 change: 1 addition & 0 deletions includes/channel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class Channel
void addMode(char mode);
void addUser(User *newUser);
void removeUser(User *userToDelete);
void removeOperator(User *userToDelete);
void addOperator(User *newOperator);
void addBannedUser(User *newBannedUser);
void addInvitee(User *newInvitee);
Expand Down
7 changes: 6 additions & 1 deletion includes/commands.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,16 @@ void version(const int &fd, const std::vector<std::string> &params, const std::s
void admin(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);
void info(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);

// Miscellaneous commands
// Channel command
void join(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);
void part(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);
void invite(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);
void kick(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);
void topic(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);
void list(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);
void names(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);

// Miscellaneous commands
void kill(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);
void ping(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);
void pong(const int &fd, const std::vector<std::string> &params, const std::string &prefix, Server *srv);
Expand Down
16 changes: 10 additions & 6 deletions includes/replies.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,25 @@
// CONNECTION REGISTRATION

// CONNECTION REGISTRATION REPLY
#define RPL_WELCOME(nick, username, clientHost) ("Welcome to the Internet Relay Network " + nick + "!" + username + "@" + clientHost + "\r\n") // 001
#define RPL_WELCOME(nick, username, clientHost) ("Welcome to the Internet Relay Network " + nick + "!" + username + "@" + clientHost + "\r\n") // 001
#define RPL_YOURHOST(serverName, version) ("Your host is " + serverName + ", running version " + version + "\r\n") // 002
#define RPL_CREATED(date) ("This server was created " + date + "\r\n") // 003
#define RPL_MYINFO(serverName, version, userModes, channelModes) (serverName + " " + version + " " + userModes + " " + channelModes + "\r\n") // 004

// CHANNELS
#define RPL_TOPIC(channelName, topic) (channelName + " :" + topic) // 332
#define RPL_NOTOPIC(channelName) (channelName + " :No topic is set") // 331
#define RPL_NAMREPLY(cMode, channelName, nMode, nickName) (cMode + " " + channelName + ":" + nMode + " " + nickName + " *(" + nMode + " " + nickName " )" + "\r\n") // 353
#define RPL_ENDOFNAMES(channelName) (channelName + " :End of NAMES list") // 366
#define RPL_TOPIC(channelName, topic) (channelName + " :" + topic + "\r\n") // 332
#define RPL_NOTOPIC(channelName) (channelName + " :No topic is set" + "\r\n") // 331
#define RPL_NAMREPLY(channelName, nickName) (channelName + " :" + nickName + "\r\n") // 353
#define RPL_ENDOFNAMES(channelName) (channelName + " :End of NAMES list" + "\r\n") // 366
#define RPL_LIST(channelName, topic) (channelName + " " + topic + "\r\n") // 322
#define RPL_LISTEND (":End of LIST\r\n") // 323



// NICK
#define ERR_NONICKNAMEGIVEN (":No nickname given\r\n") // 431
#define ERR_ERRONEUSNICKNAME(nick) (nick + " :Erroneous nickname" + "\r\n") // 432
#define ERR_NICKNAMEINUSE(nick) (nick + " :TEST Nickname is already in use" + "\r\n") // 433
#define ERR_NICKNAMEINUSE(nick) (nick + " :TEST Nickname is already in use" + "\r\n") // 433
//#define ERR_NICKCOLLISION(nick, user, clientHost) (nick + " :Nickname collision KILL from " + user + "@" + clientHost + "\r\n") // 436
#define ERR_UNAVAILRESOURCE(nickOrChannel) (nickOrChannel + " :Nick/channel is temporarily unavailable" + "\r\n") // 437
#define ERR_RESTRICTED (":Your connection is restricted!\r\n") // 484
Expand All @@ -53,6 +56,7 @@
#define ERR_NOTONCHANNEL(channel) (channel + " :You're not on that channel" + "\r\n") // 442
#define ERR_USERONCHANNEL(user, channel) (user + " " + channel + " :is already on channel" + "\r\n") // 443
#define ERR_CHANOPRIVSNEEDED(channel) (channel + " :You're not channel operator" + "\r\n") // 482
#define ERR_USERNOTINCHANNEL(nickname, channel) (nickname + " " + channel + " :They aren't on that channel" + "\r\n") // 441

// USER
// #define ERR_NEEDMOREPARAMS 461
Expand Down
5 changes: 3 additions & 2 deletions includes/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ const std::vector<Command> splitCmds(std::vector<std::string> cmd_strings);
std::string numericReply(Server *irc, const int &fd, std::string code,
std::string replyMsg);
std::string clientReply(Server *irc, const int &fd, std::string replyMsg);
std::string replyList(Server *irc, const int &fd, std::string code,
std::deque<User *> userList, std::string channelName);
std::string WelcomeChan(Server *irc, const int &fd, std::string code,
std::map<std::string, Channel *>::iterator itMap,
std::string channelName);
std::string eventChannel(Server *irc, const int &fd, std::string eventType,
std::string channelName);
int print_error(std::string message, int code, bool with_errno);
Expand Down
12 changes: 12 additions & 0 deletions srcs/channel/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

Channel::Channel(std::string name, User *currentUser): _channelName(name)
{
addOperator(currentUser);
addUser(currentUser);
}

Channel::Channel(std::string name, std::string key, User *currentUser): _channelName(name), _key(key)
{
addOperator(currentUser);
addUser(currentUser);
this->_mode.push_back('k');
}

Expand Down Expand Up @@ -98,3 +100,13 @@ void Channel::removeUser(User *userToDelete)
this->_users.erase(pos);
}
}

void Channel::removeOperator(User *userToDelete)
{
std::deque<User *>::iterator pos = std::find(this->_operators.begin(),
this->_operators.end(), userToDelete);
if (pos != this->_operators.end())
{
this->_operators.erase(pos);
}
}
47 changes: 23 additions & 24 deletions srcs/channel/invite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,81 +4,80 @@
#include "../../includes/commands.hpp"

int checkParameterInvite(std::string nickname, std::string channel,
const int &fdUser, Server *server, User *userToInvite)
const int &fdUser, Server *server, User *userToInvite)
{
// Channel list must not be empty
if (server->_channelList.empty() == true)
// Nickname and channel must not be empty
if (nickname.empty() == true || channel.empty() == true)
{
server->sendClient(fdUser, numericReply(server, fdUser,
"461", ERR_NEEDMOREPARAMS(std::string("INVITE"))));
"461", ERR_NEEDMOREPARAMS(std::string("INVITE"))));
return (-1);
}
// Nickname and channel must not be empty
if (nickname.empty() == true || channel.empty() == true)
// Channel list must not be empty
if (server->_channelList.empty() == true)
{
server->sendClient(fdUser, numericReply(server, fdUser,
"461", ERR_NEEDMOREPARAMS(std::string("INVITE"))));
"403", ERR_NOSUCHCHANNEL(channel)));
return (-1);
}
// User must exist
if (server->getUserByNickname(nickname) == NULL)
{
server->sendClient(fdUser, numericReply(server, fdUser,
"401", ERR_NOSUCHNICK(nickname)));
"401", ERR_NOSUCHNICK(nickname)));
return (-2);
}
// According to RFC "There is no requirement that the
// According to RFC "There is no requirement that the
// channel the target user is being invited to must exist or be a valid
// channel". We chose to have an existing channel as a requirement
std::map<std::string, Channel *>::iterator it = server->_channelList.find(channel);
if (it == server->_channelList.end())
{
server->sendClient(fdUser, numericReply(server, fdUser,
"403", ERR_NOSUCHCHANNEL(channel)));
"403", ERR_NOSUCHCHANNEL(channel)));
return (-3);
}
// User is already on channel
if (findUserOnChannel(it->second->_users, server->getUserByNickname(nickname)) == it->second->_users.end())
{
server->sendClient(fdUser, numericReply(server, fdUser,
"443", ERR_USERONCHANNEL(userToInvite->getFullname(), channel)));
"443", ERR_USERONCHANNEL(userToInvite->getFullname(), channel)));
return (-4);
}
// Current user must be in channel
if (findUserOnChannel(it->second->_users,
server->getUserByFd(fdUser)) == it->second->_users.end())
server->getUserByFd(fdUser)) == it->second->_users.end())
{
server->sendClient(fdUser, numericReply(server, fdUser,
"442", ERR_NOTONCHANNEL(channel)));
"442", ERR_NOTONCHANNEL(channel)));
return (-5);
}
// Current user must be an operator if channel is invite only
std::vector<char>::iterator itMode = findMode(it->second->_mode, 'i');
if (itMode != it->second->_mode.end()
&& findUserOnChannel(it->second->_operators,
server->getUserByFd(fdUser)) == it->second->_operators.end())
if (itMode != it->second->_mode.end() && findUserOnChannel(it->second->_operators,
server->getUserByFd(fdUser)) == it->second->_operators.end())
{
server->sendClient(fdUser, numericReply(server, fdUser,
"482", ERR_CHANOPRIVSNEEDED(channel)));
"482", ERR_CHANOPRIVSNEEDED(channel)));
return (-6);
}
return (0);
return (0);
}

void invite(const int &fdUser, const std::vector<std::string> &parameter, Server *server)
void invite(const int &fdUser, const std::vector<std::string> &parameter, const std::string &, Server *server)
{
std::string nickname = parameter[0];
std::string channel = parameter[1];
User *userToInvite = server->getUserByNickname(nickname);

if (checkParameterInvite(nickname, channel, fdUser, server, userToInvite) < 0)
return ;
return;
// Add user to the list of invitee and return reply
std::map<std::string, Channel *>::iterator channelPos = server->_channelList.find(channel);
channelPos->second->addUser(server->getUserByNickname(nickname));
server->sendClient(fdUser, clientReply(server, fdUser, nickname + " has been invited to " +
channel + "by " + server->getUserByFd(fdUser)->getNickname()));
server->sendClient(fdUser, clientReply(server, fdUser, "INVITE " +
server->getUserByNickname(nickname)->getNickname()) + " " + channel);
server->sendClient(server->getUserByNickname(nickname)->getFd(),
clientReply(server, fdUser, nickname + " has been invited to " +
channel + "by " + server->getUserByFd(fdUser)->getNickname()));
clientReply(server, fdUser, "INVITE " +
server->getUserByNickname(nickname)->getNickname()) + " " + channel);
}
58 changes: 39 additions & 19 deletions srcs/channel/join.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@
#include "../../includes/utils.hpp"
#include "../../includes/commands.hpp"

void channelReply(Server *server, const int &fdUser, std::string channelName)
{
// Reply if the user successfully joined the channel
// Use send for all the user of a channel (vector of fd)
std::string event = clientReply(server, fdUser, "JOIN " + channelName);
std::string userList = WelcomeChan(server, fdUser, "353",
server->_channelList.find(channelName),
channelName);
std::string endOfNames = numericReply(server, fdUser, "366", RPL_ENDOFNAMES(channelName));
std::vector<std::string> parameterTopic;

parameterTopic.push_back(channelName);
server->sendChannel(channelName, event);
topic(fdUser, parameterTopic, channelName, server);
server->sendClient(fdUser, userList + endOfNames);
}

void createChannel(std::string channelName, int pos, std::vector<std::string> key,
User *currentUser, Server *server)
{
Expand All @@ -27,11 +44,15 @@ int checkKey(size_t pos, std::vector<std::string> key,
std::map<std::string, Channel *>::iterator itMap, Server *server,
const int &fdUser)
{
std::string keySetInChannel;
std::vector<std::string>::iterator it;
std::string keyToCheck;

if (key.empty() == true)
return (0);
std::string keySetInChannel = itMap->second->getKey();
std::vector<std::string>::iterator it = key.begin() + pos;
std::string keyToCheck = *it;
keySetInChannel = itMap->second->getKey();
it = key.begin() + pos;
keyToCheck = *it;

if (keyToCheck.compare(keySetInChannel) != 0)
{
Expand Down Expand Up @@ -87,12 +108,15 @@ void join(const int &fdUser, const std::vector<std::string> &parameter, const st
// Get parameters of join
std::vector<std::string> channel;
std::vector<std::string> key;
std::vector<std::string>::iterator itChan;
std::map<std::string, Channel *>::iterator itMap;
std::vector<char>::iterator itMode;

channel = splitByComma(parameter[0]);
if (parameter.size() > 1)
key = splitByComma(parameter[1]);

std::vector<std::string>::iterator itChan = channel.begin();
itChan = channel.begin();
itChan = channel.begin();
for (; itChan != channel.end(); itChan++)
{
Expand All @@ -102,38 +126,34 @@ void join(const int &fdUser, const std::vector<std::string> &parameter, const st
// Case where channel already exists
if (server->_channelList.empty() == false)
{
std::map<std::string, Channel *>::iterator itMap = server->_channelList.find(*itChan);
itMap = server->_channelList.find(*itChan);
if (itMap != server->_channelList.end())
{
if (checkKey(itChan - channel.begin(), key, itMap, server, fdUser) < 0)
return;
std::vector<char>::iterator itMode = findMode(itMap->second->_mode, 'i');
if (itMap->second->_mode.empty() == false && itMode != itMap->second->_mode.end() && checkInviteBan(itMap->second->_invitees, server->getUserByFd(fdUser)) < 0)
itMode = findMode(itMap->second->_mode, 'i');
if (itMap->second->_mode.empty() == false
&& itMode != itMap->second->_mode.end()
&& checkInviteBan(itMap->second->_invitees, server->getUserByFd(fdUser)) < 0)
return (server->sendClient(fdUser, numericReply(server, fdUser,
"473", ERR_INVITEONLYCHAN(*itChan))));
if (itMap->second->_bannedUsers.empty() == false && checkInviteBan(itMap->second->_bannedUsers, server->getUserByFd(fdUser)) < 0)
"473", ERR_INVITEONLYCHAN(*itChan))));
if (itMap->second->_bannedUsers.empty() == false
&& checkInviteBan(itMap->second->_bannedUsers, server->getUserByFd(fdUser)) < 0)
return (server->sendClient(fdUser, numericReply(server, fdUser,
"474", ERR_BANNEDFROMCHAN(*itChan))));
"474", ERR_BANNEDFROMCHAN(*itChan))));
addUserToChannel(itMap, server->getUserByFd(fdUser));
}
else
createChannel(*itChan, itChan - channel.begin(), key,
server->getUserByFd(fdUser), server);
channelReply(server, fdUser, *itChan);
}
// Case where channel doesn't exist
else
{
createChannel(*itChan, itChan - channel.begin(), key,
server->getUserByFd(fdUser), server);
channelReply(server, fdUser, *itChan);
}
// Reply if the user successfully joined the channel
// Use send for all the user of a channel (vector of fd)
std::string event = clientReply(server, fdUser, "has joined " + *itChan);
std::string userList = replyList(server, fdUser, "353",
server->_channelList.find(*itChan)->second->_users,
*itChan);
std::string endOfNames = numericReply(server, fdUser, "366", RPL_ENDOFNAMES(*itChan));
server->sendChannel(*itChan, event);
server->sendClient(fdUser, userList + "\r\n" + endOfNames);
}
}
Loading

0 comments on commit 1bbb3b2

Please sign in to comment.