diff --git a/ft_irc3/includes/AdditionalCommands.hpp b/ft_irc3/includes/AdditionalCommands.hpp index 9786d3d..bd655b2 100644 --- a/ft_irc3/includes/AdditionalCommands.hpp +++ b/ft_irc3/includes/AdditionalCommands.hpp @@ -5,8 +5,8 @@ /* +:+ +:+ +:+ */ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ -/* Created: 2024/05/16 15:23:58 by fgras-ca #+# #+# */ -/* Updated: 2024/05/19 19:18:11 by fgras-ca ### ########.fr */ +/* Created: 2024/05/21 18:09:05 by fgras-ca #+# #+# */ +/* Updated: 2024/05/21 19:46:40 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -16,8 +16,11 @@ #include "Client.hpp" #include "Server.hpp" #include "Channel.hpp" +#include "CommandHandler.hpp" #include "Utils.hpp" #include "RPL.hpp" +#include "Who.hpp" + #include #include #include @@ -26,12 +29,20 @@ class Server; class Client; class Channel; +class CommandHandler; -void sendWelcomeMessages(Client *client, Server *server); -void sendMotd(Client *client, Server *server); -void broadcastChannelList(Client *client, Server *server); -void handlePartCommand(Server *server, Client *client, const std::string &command); -void handleNickCommand(Server *server, Client *client, const std::string &command); -void handlePrivmsgCommand(Server *server, Client *client, const std::string &command); +class AdditionalCommands +{ +private: + Server *_server; + CommandHandler *_commandhandler; +public: + AdditionalCommands(Server *server); + void processCommand(Client *client, const std::string &command); + void broadcastChannelList(Client *client, Server *server); + void handlePartCommand(Server *server, Client *client, const std::string &command); + void handleNickCommand(Server *server, Client *client, const std::string &command); + void handlePrivmsgCommand(Server *server, Client *client, const std::string &command); +}; #endif // ADDITIONALCOMMANDS_HPP diff --git a/ft_irc3/includes/Channel.hpp b/ft_irc3/includes/Channel.hpp index 40e1514..fb1276f 100644 --- a/ft_irc3/includes/Channel.hpp +++ b/ft_irc3/includes/Channel.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 12:41:35 by fgras-ca #+# #+# */ -/* Updated: 2024/05/19 15:14:50 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 19:26:51 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,11 +17,16 @@ #include #include #include -#include "RPL.hpp" +#include "RPL.hpp" +#include "Client.hpp" +#include "Server.hpp" + +class Server; class Client; -class Channel { +class Channel +{ public: Channel(const std::string &name); ~Channel(); @@ -33,6 +38,8 @@ public: const std::vector &getClients() const; void addOperator(Client *client); bool isOperator(Client *client) const; + bool hasClient(Client *client) const; // Ajouté + void broadcast(const std::string &message, Client *_client, Server *_server); // Ajouté private: std::string _name; @@ -40,4 +47,4 @@ private: std::vector _operators; }; -#endif +#endif // CHANNEL_HPP diff --git a/ft_irc3/includes/Client.hpp b/ft_irc3/includes/Client.hpp index 9462e8e..15d589b 100644 --- a/ft_irc3/includes/Client.hpp +++ b/ft_irc3/includes/Client.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 12:15:42 by fgras-ca #+# #+# */ -/* Updated: 2024/05/19 15:38:28 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 18:03:09 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/ft_irc3/includes/ClientManager.hpp b/ft_irc3/includes/ClientManager.hpp index 57342ad..8080bac 100644 --- a/ft_irc3/includes/ClientManager.hpp +++ b/ft_irc3/includes/ClientManager.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 18:30:07 by fgras-ca #+# #+# */ -/* Updated: 2024/05/19 18:56:44 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 18:01:47 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -19,7 +19,6 @@ #include "Channel.hpp" #include "Server.hpp" #include "CommandHandler.hpp" -#include "AdditionalCommands.hpp" #include "RPL.hpp" #include "Utils.hpp" diff --git a/ft_irc3/includes/CommandHandler.hpp b/ft_irc3/includes/CommandHandler.hpp index 6e6fd86..43ff5df 100644 --- a/ft_irc3/includes/CommandHandler.hpp +++ b/ft_irc3/includes/CommandHandler.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 18:14:12 by fgras-ca #+# #+# */ -/* Updated: 2024/05/21 13:47:12 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 20:15:58 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,39 +17,42 @@ #include "Server.hpp" #include "Client.hpp" #include "Channel.hpp" -#include "AdditionalCommands.hpp" #include "Who.hpp" -#include "CommandHandler.hpp" +#include "AdditionalCommands.hpp" #include "RPL.hpp" +#include "Join.hpp" +#include "Welcome.hpp" #include #include #include class Server; -class ModeWhoHandler; -class AdditinalCommands; +class Client; +class Channel; +class WhoHandler; +class AdditionalCommands; class CommandHandler { private: Server *_server; + AdditionalCommands *_additionalCommands; public: CommandHandler(Server *server); - bool isValidNickname(const std::string& nickname); - bool isNicknameInUse(const std::string& nickname); - void handleNick(Client* client, const std::vector& tokens); + bool isValidNickname(const std::string& nickname); + bool isNicknameInUse(const std::string& nickname); + void handleNick(Client* client, const std::vector& tokens); - void handleUser(Client* client, const std::vector& tokens); - void handlePingCommand(Client* client, const std::vector& tokens); + void handleUser(Client* client, const std::vector& tokens); + void handlePingCommand(Client* client, const std::vector& tokens); void handleCommand(Client *client, const std::string &command); - void handleCapCommand(Client* client, const std::vector& tokens); - void handlePassCommand(Client* client, const std::vector& tokens); + void handleCapCommand(Client* client, const std::vector& tokens); + void handlePassCommand(Client* client, const std::vector& tokens); + void handleQuitCommand(Client* client, const std::vector& tokens); + void handleErrorCommand(Client* client, const std::string &message); - void processCommand(Client *client, const std::string &command); - void handleJoinCommand(Client *client, const std::string &channelName); - std::string getUsersList(Channel *channel); }; -#endif +#endif // COMMANDHANDLER_HPP \ No newline at end of file diff --git a/ft_irc3/includes/Join.hpp b/ft_irc3/includes/Join.hpp new file mode 100644 index 0000000..d48ea70 --- /dev/null +++ b/ft_irc3/includes/Join.hpp @@ -0,0 +1,34 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Join.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 19:51:08 by fgras-ca #+# #+# */ +/* Updated: 2024/05/21 20:13:15 by fgras-ca ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef JOIN_HPP +#define JOIN_HPP + +#include "Server.hpp" +#include "Client.hpp" +#include "Channel.hpp" +#include "RPL.hpp" + +class Server; +class Client; +class Channel; + +class JoinHandler +{ +public: + void handleJoinCommand(Client *client, const std::string &channelName, Server *server); + +private: + std::string getUsersList(Channel *channel); +}; + +#endif // JOIN_HPP diff --git a/ft_irc3/includes/Server.hpp b/ft_irc3/includes/Server.hpp index a66c868..4074a42 100644 --- a/ft_irc3/includes/Server.hpp +++ b/ft_irc3/includes/Server.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 12:15:13 by fgras-ca #+# #+# */ -/* Updated: 2024/05/19 21:13:24 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 19:44:24 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -38,6 +38,7 @@ class Client; class Channel; class ClientManager; class CommandHandler; +class AdditionalCommands; class Server { @@ -56,6 +57,8 @@ public: Client* getClientByName(const std::string &name); // Ajoutez cette méthode void sendChannelListToClient(Client *client); void disconnectClient(int clientFd); + bool MatchFd(const pollfd& pfd, int clientFd); + void removePollFd(int clientFd); protected: diff --git a/ft_irc3/includes/Welcome.hpp b/ft_irc3/includes/Welcome.hpp new file mode 100644 index 0000000..5e42c00 --- /dev/null +++ b/ft_irc3/includes/Welcome.hpp @@ -0,0 +1,27 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Welcome.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 19:53:17 by fgras-ca #+# #+# */ +/* Updated: 2024/05/21 19:53:24 by fgras-ca ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef WELCOME_HPP +#define WELCOME_HPP + +#include "Client.hpp" +#include "Server.hpp" +#include + +class WelcomeHandler +{ +public: + void sendWelcomeMessages(Client *client, Server *server); + void sendMotd(Client *client, Server *server); +}; + +#endif // WELCOME_HPP diff --git a/ft_irc3/includes/Who.hpp b/ft_irc3/includes/Who.hpp index 4335875..f8d0fe3 100644 --- a/ft_irc3/includes/Who.hpp +++ b/ft_irc3/includes/Who.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/17 16:08:48 by fgras-ca #+# #+# */ -/* Updated: 2024/05/21 13:47:28 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 18:04:10 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/ft_irc3/ircserv b/ft_irc3/ircserv new file mode 100755 index 0000000..c76a5a2 Binary files /dev/null and b/ft_irc3/ircserv differ diff --git a/ft_irc3/logs/irc_server.log b/ft_irc3/logs/irc_server.log new file mode 100644 index 0000000..e69de29 diff --git a/ft_irc3/obj/AdditionalCommands.o b/ft_irc3/obj/AdditionalCommands.o index 24556f2..8dcc784 100644 Binary files a/ft_irc3/obj/AdditionalCommands.o and b/ft_irc3/obj/AdditionalCommands.o differ diff --git a/ft_irc3/obj/Channel.o b/ft_irc3/obj/Channel.o index a5a03f3..c094f8c 100644 Binary files a/ft_irc3/obj/Channel.o and b/ft_irc3/obj/Channel.o differ diff --git a/ft_irc3/obj/ClientManager.o b/ft_irc3/obj/ClientManager.o index cbfef1a..ebac5d8 100644 Binary files a/ft_irc3/obj/ClientManager.o and b/ft_irc3/obj/ClientManager.o differ diff --git a/ft_irc3/obj/CommandHandler.o b/ft_irc3/obj/CommandHandler.o index b8d83fc..fbf5ce4 100644 Binary files a/ft_irc3/obj/CommandHandler.o and b/ft_irc3/obj/CommandHandler.o differ diff --git a/ft_irc3/obj/Join.o b/ft_irc3/obj/Join.o new file mode 100644 index 0000000..fa48cda Binary files /dev/null and b/ft_irc3/obj/Join.o differ diff --git a/ft_irc3/obj/Server.o b/ft_irc3/obj/Server.o new file mode 100644 index 0000000..cb1f310 Binary files /dev/null and b/ft_irc3/obj/Server.o differ diff --git a/ft_irc3/obj/Utils.o b/ft_irc3/obj/Utils.o new file mode 100644 index 0000000..4853158 Binary files /dev/null and b/ft_irc3/obj/Utils.o differ diff --git a/ft_irc3/obj/Welcome.o b/ft_irc3/obj/Welcome.o new file mode 100644 index 0000000..f1c1eb9 Binary files /dev/null and b/ft_irc3/obj/Welcome.o differ diff --git a/ft_irc3/obj/Who.o b/ft_irc3/obj/Who.o new file mode 100644 index 0000000..abd8ca3 Binary files /dev/null and b/ft_irc3/obj/Who.o differ diff --git a/ft_irc3/src/AdditionalCommands.cpp b/ft_irc3/src/AdditionalCommands.cpp index 4d71dfb..6790b51 100644 --- a/ft_irc3/src/AdditionalCommands.cpp +++ b/ft_irc3/src/AdditionalCommands.cpp @@ -6,44 +6,47 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/16 15:27:29 by fgras-ca #+# #+# */ -/* Updated: 2024/05/21 13:52:54 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 20:22:22 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ #include "AdditionalCommands.hpp" -void sendWelcomeMessages(Client *client, Server *server) -{ - server->sendToClient(client->getFd(), RPL_WELCOME(client)); - server->sendToClient(client->getFd(), RPL_YOURHOST(client)); - server->sendToClient(client->getFd(), RPL_CREATED(client)); - server->sendToClient(client->getFd(), RPL_MYINFO(client)); - server->sendToClient(client->getFd(), RPL_ISUPPORT(client, "MODES=EXAMPLE")); +AdditionalCommands::AdditionalCommands(Server *server) : _server(server) +{} - sendMotd(client, server); +void AdditionalCommands::processCommand(Client *client, const std::string &command) +{ + if (command.find("PART") == 0) + { + handlePartCommand(_server, client, command); + } + else if (command.find("PRIVMSG") == 0) + { + handlePrivmsgCommand(_server, client, command); + } + else if (command.find("WHO") == 0) + { + WhoHandler whoHandler(_server); + whoHandler.handleWhoCommand(client, command); + } + else if (command.find("WHOIS") == 0) + { + WhoHandler whoHandler(_server); + whoHandler.handleWhoisCommand(client, command); + } + else if (command.find("LIST") == 0) + { + broadcastChannelList(client, _server); + } + else + { + _server->sendToClient(client->getFd(), ERR_UNKNOWNCOMMAND(client, command)); + _server->log("Message from client " + client->getNickname() + ": " + command, MAGENTA); + } } -void sendMotd(Client *client, Server *server) -{ - std::ifstream motdFile("motd.txt"); - if (motdFile.is_open()) - { - std::string line; - server->sendToClient(client->getFd(), RPL_MOTDSTART(client)); - while (std::getline(motdFile, line)) - { - server->sendToClient(client->getFd(), RPL_MOTD(client, line)); - } - server->sendToClient(client->getFd(), RPL_ENDOFMOTD(client)); - motdFile.close(); - } - else - { - server->sendToClient(client->getFd(), ERR_NOMOTD(client)); - } -} - -void broadcastChannelList(Client *client, Server *server) +void AdditionalCommands::broadcastChannelList(Client *client, Server *server) { std::map &channels = server->getChannels(); for (std::map::iterator it = channels.begin(); it != channels.end(); ++it) @@ -54,7 +57,7 @@ void broadcastChannelList(Client *client, Server *server) } // Fonction pour gérer la commande PART -void handlePartCommand(Server *server, Client *client, const std::string &command) +void AdditionalCommands::handlePartCommand(Server *server, Client *client, const std::string &command) { std::istringstream iss(command); std::string cmd, channelName; @@ -87,25 +90,7 @@ void handlePartCommand(Server *server, Client *client, const std::string &comman } } -// Fonction pour gérer la commande NICK -void handleNickCommand(Server *server, Client *client, const std::string &command) -{ - std::istringstream iss(command); - std::string cmd, newNick; - iss >> cmd >> newNick; - - std::stringstream nickMsg; - nickMsg << ":" << client->getNickname() << " NICK " << newNick << "\r\n"; - server->sendToClient(client->getFd(), nickMsg.str()); - - client->setNickname(newNick); - - std::stringstream ss; - ss << "Client " << client->getFd() << " changed nickname to " << newNick; - server->log(ss.str(), GREEN); -} - -void handlePrivmsgCommand(Server *server, Client *client, const std::string &command) +void AdditionalCommands::handlePrivmsgCommand(Server *server, Client *client, const std::string &command) { std::istringstream iss(command); std::string cmd, target, message; diff --git a/ft_irc3/src/Channel.cpp b/ft_irc3/src/Channel.cpp index 1f5b010..82b91b4 100644 --- a/ft_irc3/src/Channel.cpp +++ b/ft_irc3/src/Channel.cpp @@ -6,21 +6,15 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 12:42:57 by fgras-ca #+# #+# */ -/* Updated: 2024/05/17 20:08:28 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 19:27:42 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ #include "Channel.hpp" -#include "Client.hpp" -Channel::Channel(const std::string &name) - : _name(name) -{ -} +Channel::Channel(const std::string &name) : _name(name) {} -Channel::~Channel() -{ -} +Channel::~Channel() {} const std::string &Channel::getName() const { @@ -49,13 +43,27 @@ const std::vector &Channel::getClients() const void Channel::addOperator(Client *client) { - if (std::find(_operators.begin(), _operators.end(), client) == _operators.end()) - { - _operators.push_back(client); - } + _operators.push_back(client); } bool Channel::isOperator(Client *client) const { return std::find(_operators.begin(), _operators.end(), client) != _operators.end(); } + +bool Channel::hasClient(Client *client) const +{ + return std::find(_clients.begin(), _clients.end(), client) != _clients.end(); +} + +void Channel::broadcast(const std::string &message, Client *_client, Server *server) +{ + for (std::vector::iterator it = _clients.begin(); it != _clients.end(); ++it) + { + if (*it != _client) + { + // Send message to each client except the sender + server->sendToClient((*it)->getFd(), message); + } + } +} diff --git a/ft_irc3/src/ClientManager.cpp b/ft_irc3/src/ClientManager.cpp index 7473188..6a42f71 100644 --- a/ft_irc3/src/ClientManager.cpp +++ b/ft_irc3/src/ClientManager.cpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 18:32:23 by fgras-ca #+# #+# */ -/* Updated: 2024/05/21 14:09:07 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 20:28:41 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -43,30 +43,50 @@ void ClientManager::handleClient(int client_fd) char buffer[1024]; std::memset(buffer, 0, sizeof(buffer)); int bytes_received = recv(client_fd, buffer, sizeof(buffer), 0); + if (bytes_received <= 0) { + std::ostringstream oss; + oss << "Client disconnected: " << client_fd; + _server->log(oss.str(), RED); removeClient(client_fd); return; } - std::string message(buffer); - std::stringstream ss; - ss << "Received from client " << client_fd << ": " << message; - _server->log(ss.str(), BLUE); + std::string message(buffer, bytes_received); + std::ostringstream oss; + oss << "Received from client " << client_fd << ": " << message; + _server->log(oss.str(), BLUE); + + Client* client = _server->getClients()[client_fd]; + if (!client) + { + std::ostringstream oss; + oss << "Client not found for fd: " << client_fd; + _server->log(oss.str(), RED); + return; + } - Client *client = _server->_clients[client_fd]; std::istringstream message_stream(message); std::string line; while (std::getline(message_stream, line)) { + // Remove trailing '\r' and '\n' line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); line.erase(std::remove(line.begin(), line.end(), '\n'), line.end()); - _server->_commandHandler->handleCommand(client, line); + if (!line.empty()) + { + std::ostringstream oss; + oss << "Processing command from client " << client_fd << ": " << line; + _server->log(oss.str(), BLUE); + _server->_commandHandler->handleCommand(client, line); + } } } + void ClientManager::removeClient(int clientFd) { Client* client = _server->_clients[clientFd]; @@ -109,4 +129,3 @@ void ClientManager::removeClient(int clientFd) ss << "Client disconnected: " << clientFd; _server->log(ss.str(), YELLOW); } - diff --git a/ft_irc3/src/CommandHandler.cpp b/ft_irc3/src/CommandHandler.cpp index 14e1309..df45dfb 100644 --- a/ft_irc3/src/CommandHandler.cpp +++ b/ft_irc3/src/CommandHandler.cpp @@ -6,16 +6,22 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 18:26:34 by fgras-ca #+# #+# */ -/* Updated: 2024/05/21 14:19:19 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 20:24:52 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ #include "CommandHandler.hpp" CommandHandler::CommandHandler(Server *server) - : _server(server) -{ -} + : _server(server), _additionalCommands(new AdditionalCommands(server)) + { + // Ensure that _server is not null + if (!_server) + { + std::cerr << "Server pointer is null in CommandHandler constructor." << std::endl; + exit(EXIT_FAILURE); + } + } void CommandHandler::handleCommand(Client* client, const std::string& command) { @@ -34,12 +40,27 @@ void CommandHandler::handleCommand(Client* client, const std::string& command) handleNick(client, tokens); } else if (commandType == "USER") { handleUser(client, tokens); - } else { + } else if (commandType == "QUIT") { + handleQuitCommand(client, tokens); + } else if (commandType == "PING") + { + handlePingCommand(client, tokens); + } + else if (commandType == "ERROR") { + if (tokens.size() > 1) { + handleErrorCommand(client, tokens[1]); + } + } + else if (commandType == "JOIN") { + JoinHandler joinHandler; + joinHandler.handleJoinCommand(client, tokens[1], _server); + } + else { if (!client->isAuthenticated()) { _server->sendToClient(client->getFd(), ERR_NOTREGISTERED(client)); _server->log("Client " + client->getNickname() + " attempted to send a command before registering.", RED); } else { - processCommand(client, command); + _additionalCommands->processCommand(client, command); } } std::cout << "Client " << client->getFd() << " " << client->getNickname() << " " << client->getUser() << " " << client->getPassword() << " " << client->getRealName() << std::endl; @@ -145,145 +166,106 @@ void CommandHandler::handleNick(Client* client, const std::vector& _server->sendToClient(client->getFd(), ERR_NICKNAMEINUSE(client, newNick)); return; } - + + std::string oldNick = client->getNickname(); client->setNickname(newNick); - _server->sendToClient(client->getFd(), ":" + newNick + " NICK " + newNick + "\r\n"); + // Envoyer le message NICK à tous les clients connectés + std::string nickMessage = ":" + oldNick + " NICK " + newNick + "\r\n"; + for (std::map::iterator it = _server->_clients.begin(); it != _server->_clients.end(); ++it) { + _server->sendToClient(it->second->getFd(), nickMessage); + } std::ostringstream oss; - oss << "Client " << client->getFd() << " changed nickname to " << newNick; + oss << "Client " << client->getFd() << " changed nickname from " << oldNick << " to " << newNick; _server->log(oss.str(), GREEN); } + void CommandHandler::handleUser(Client* client, const std::vector& tokens) { - // Set the user and realname fields - client->setUser(tokens[1]); - std::string realname = tokens[4]; - if (realname[0] == ':') - { - realname = realname.substr(1); // Remove leading ':' + if (tokens.size() < 5) { + _server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client->getFd(), "USER")); + + std::ostringstream oss; + oss << "Client " << client->getFd() << ": USER command failed - not enough parameters."; + _server->log(oss.str(), RED); + + return; } + + if (client->isAuthenticated()) { + _server->sendToClient(client->getFd(), ERR_ALREADYREGISTERED(client)); + + std::ostringstream oss; + oss << "Client " << client->getFd() << ": USER command failed - already registered."; + _server->log(oss.str(), RED); + + return; + } + + std::string username = tokens[1]; + std::string realname = tokens[4].substr(1); // remove leading ':' + + client->setUser(username); client->setRealName(realname); - // Log the values for debugging - std::ostringstream logMsg; - logMsg << "Client " << client->getFd() << ": USER command set username to " << tokens[1] << " and real name to " << realname; - _server->log(logMsg.str(), BLUE); + std::ostringstream oss; + oss << "Client " << client->getFd() << ": USER command set username to " << username << " and real name to " << realname; + _server->log(oss.str(), BLUE); - // Authenticate if password and nickname are already set - if (client->getPassword() == _server->_password && !client->getNickname().empty()) - { + if (client->getPassword() == _server->_password && !client->getNickname().empty()) { client->authenticate(); - sendWelcomeMessages(client, _server); - _server->log("Client " + client->getNickname() + " authenticated successfully.", GREEN); + WelcomeHandler welcomeHandler; + welcomeHandler.sendWelcomeMessages(client, _server); + _server->log("Client " + client->getNickname() + " authenticated.", GREEN); + } else { + std::ostringstream oss; + oss << "Client " << client->getFd() << ": USER command failed - authentication conditions not met."; + _server->log(oss.str(), RED); } - else - { - std::ostringstream authFailMsg; - authFailMsg << "Client " << client->getFd() << ": USER command failed - authentication conditions not met."; - _server->log(authFailMsg.str(), RED); - } -} - - - -void CommandHandler::processCommand(Client *client, const std::string &command) -{ - if (command.find("JOIN") == 0) - { - std::string channelName = command.substr(5); - handleJoinCommand(client, channelName); - } - else if (command.find("PART") == 0) - { - handlePartCommand(_server, client, command); - } - /*else if (command.find("NICK") == 0) - { - handleNickCommand(_server, client, command); - }*/ - else if (command.find("PRIVMSG") == 0) - { - handlePrivmsgCommand(_server, client, command); - } - else if (command.find("WHO") == 0) - { - WhoHandler whoHandler(_server); - whoHandler.handleWhoCommand(client, command); - } - else if (command.find("WHOIS") == 0) - { - WhoHandler whoHandler(_server); - whoHandler.handleWhoisCommand(client, command); - } - else if (command.find("PING") == 0) - { - std::vector tokens = split(command, " "); - handlePingCommand(client, tokens); - } - else if (command.find("LIST") == 0) - { - broadcastChannelList(client, _server); - } - else - { - _server->sendToClient(client->getFd(), ERR_UNKNOWNCOMMAND(client, command)); - _server->log("Message from client " + client->getNickname() + ": " + command, MAGENTA); - } -} - -void CommandHandler::handleJoinCommand(Client *client, const std::string &channelName) -{ - if (_server->getChannels().find(channelName) == _server->getChannels().end()) - { - _server->getChannels()[channelName] = new Channel(channelName); - _server->log("Channel created: " + channelName, GREEN); - - // Notifier tous les clients de la création du canal - _server->broadcast(":server NOTICE * :New channel created: " + channelName + "\r\n"); - } - Channel *channel = _server->getChannels()[channelName]; - channel->addClient(client); - - std::stringstream joinMsg; - joinMsg << ":" << client->getNickname() << " JOIN :" << channelName << "\r\n"; - _server->sendToClient(client->getFd(), joinMsg.str()); - - std::string usersList = getUsersList(channel); - _server->sendToClient(client->getFd(), usersList); - - std::stringstream endOfNamesMsg; - endOfNamesMsg << ":server 366 " << client->getNickname() << " " << channelName << " :End of /NAMES list.\r\n"; - _server->sendToClient(client->getFd(), endOfNamesMsg.str()); - - std::stringstream ss; - ss << "Client " << client->getNickname() << " joined channel " << channelName; - _server->log(ss.str(), MAGENTA); -} - -std::string CommandHandler::getUsersList(Channel *channel) -{ - std::vector clients = channel->getClients(); - std::stringstream ss; - ss << ":server 353 " << clients[0]->getNickname() << " = " << channel->getName() << " :"; - for (size_t i = 0; i < clients.size(); ++i) - { - if (i > 0) - ss << " "; - ss << clients[i]->getNickname(); - } - ss << "\r\n"; - return ss.str(); } void CommandHandler::handlePingCommand(Client* client, const std::vector& tokens) { - if (tokens.size() < 2) { - _server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "PING")); + if (tokens.size() < 2) + { + _server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client->getFd(), "PING")); return; } - std::string token = tokens[1]; - _server->sendToClient(client->getFd(), RPL_PONG(token)); + std::string serverName = tokens[1]; + std::string pongMessage = ":" + serverName + " PONG " + serverName + "\r\n"; + _server->sendToClient(client->getFd(), pongMessage); +} + + +void CommandHandler::handleQuitCommand(Client* client, const std::vector& tokens) +{ + std::string reason = "Quit: "; + if (tokens.size() > 1) + { + reason += tokens[1]; + } + + std::string quitMessage = ":" + client->getNickname() + " QUIT :" + reason + "\r\n"; + + std::map::iterator it; + for (it = _server->getChannels().begin(); it != _server->getChannels().end(); ++it) + { + if (it->second->hasClient(client)) + { + it->second->broadcast(quitMessage, client, _server); + it->second->removeClient(client); + } + } + + _server->sendToClient(client->getFd(), "ERROR :" + reason + "\r\n"); + _server->disconnectClient(client->getFd()); +} + +void CommandHandler::handleErrorCommand(Client* client, const std::string &message) +{ + _server->sendToClient(client->getFd(), "ERROR :" + message + "\r\n"); + _server->disconnectClient(client->getFd()); } diff --git a/ft_irc3/src/Join.cpp b/ft_irc3/src/Join.cpp new file mode 100644 index 0000000..da1bca5 --- /dev/null +++ b/ft_irc3/src/Join.cpp @@ -0,0 +1,47 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Join.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 19:51:31 by fgras-ca #+# #+# */ +/* Updated: 2024/05/21 20:13:30 by fgras-ca ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "Join.hpp" + +void JoinHandler::handleJoinCommand(Client *client, const std::string &channelName, Server *server) +{ + std::map &channels = server->getChannels(); + Channel *channel; + if (channels.find(channelName) == channels.end()) + { + channel = new Channel(channelName); + channels[channelName] = channel; + } + else + { + channel = channels[channelName]; + } + + channel->addClient(client); + std::string joinMessage = ":" + client->getNickname() + " JOIN " + channelName + "\r\n"; + server->sendToClient(client->getFd(), joinMessage); + + std::string usersList = getUsersList(channel); + server->sendToClient(client->getFd(), usersList); +} + +std::string JoinHandler::getUsersList(Channel *channel) +{ + std::vector clients = channel->getClients(); + std::string usersList = ":server 353 " + clients[0]->getNickname() + " = " + channel->getName() + " :"; + for (std::vector::iterator it = clients.begin(); it != clients.end(); ++it) + { + usersList += (*it)->getNickname() + " "; + } + usersList += "\r\n:server 366 " + clients[0]->getNickname() + " " + channel->getName() + " :End of /NAMES list.\r\n"; + return usersList; +} diff --git a/ft_irc3/src/Server.cpp b/ft_irc3/src/Server.cpp index 8c93d55..e69acc4 100644 --- a/ft_irc3/src/Server.cpp +++ b/ft_irc3/src/Server.cpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 12:17:12 by fgras-ca #+# #+# */ -/* Updated: 2024/05/21 14:18:03 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 20:31:51 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -183,6 +183,10 @@ void Server::sendToClient(int client_fd, const std::string &message) log(ss.str(), BLUE); } } +std::map &Server::getClients() +{ + return _clients; +} void Server::broadcast(const std::string &message) { @@ -214,26 +218,31 @@ void Server::sendChannelListToClient(Client *client) sendToClient(client->getFd(), RPL_LISTEND(client->getFd())); } +bool Server::MatchFd(const pollfd& pfd, int clientFd) +{ + return pfd.fd == clientFd; +} + +void Server::removePollFd(int clientFd) +{ + for (std::vector::iterator it = _poll_fds.begin(); it != _poll_fds.end(); ++it) + { + if (MatchFd(*it, clientFd)) + { + _poll_fds.erase(it); + break; + } + } +} + void Server::disconnectClient(int clientFd) { - Client* client = _clients[clientFd]; - if (client) - { - log("Disconnecting client: " + client->getNickname(), YELLOW); - _clients.erase(clientFd); - delete client; - } + close(clientFd); - struct MatchFd - { - int fd; - MatchFd(int fd) : fd(fd) {} - bool operator()(const pollfd& pfd) const { return pfd.fd == fd; } - }; + _clients.erase(clientFd); + removePollFd(clientFd); - _poll_fds.erase(std::remove_if(_poll_fds.begin(), _poll_fds.end(), MatchFd(clientFd)), _poll_fds.end()); - - std::ostringstream oss; - oss << "Client disconnected: " << clientFd; - log(oss.str(), YELLOW); + std::ostringstream oss; + oss << "Client disconnected: " << clientFd; + log(oss.str(), YELLOW); } diff --git a/ft_irc3/src/Welcome.cpp b/ft_irc3/src/Welcome.cpp new file mode 100644 index 0000000..e99839e --- /dev/null +++ b/ft_irc3/src/Welcome.cpp @@ -0,0 +1,44 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Welcome.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 17:53:52 by fgras-ca #+# #+# */ +/* Updated: 2024/05/21 19:54:48 by fgras-ca ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "Welcome.hpp" + +void WelcomeHandler::sendWelcomeMessages(Client *client, Server *server) +{ + server->sendToClient(client->getFd(), RPL_WELCOME(client)); + server->sendToClient(client->getFd(), RPL_YOURHOST(client)); + server->sendToClient(client->getFd(), RPL_CREATED(client)); + server->sendToClient(client->getFd(), RPL_MYINFO(client)); + server->sendToClient(client->getFd(), RPL_ISUPPORT(client, "MODES=EXAMPLE")); + + sendMotd(client, server); +} + +void WelcomeHandler::sendMotd(Client *client, Server *server) +{ + std::ifstream motdFile("motd.txt"); + if (motdFile.is_open()) + { + std::string line; + server->sendToClient(client->getFd(), RPL_MOTDSTART(client)); + while (std::getline(motdFile, line)) + { + server->sendToClient(client->getFd(), RPL_MOTD(client, line)); + } + server->sendToClient(client->getFd(), RPL_ENDOFMOTD(client)); + motdFile.close(); + } + else + { + server->sendToClient(client->getFd(), ERR_NOMOTD(client)); + } +} diff --git a/ft_irc3/src/Who.cpp b/ft_irc3/src/Who.cpp index bdef91d..5247b7d 100644 --- a/ft_irc3/src/Who.cpp +++ b/ft_irc3/src/Who.cpp @@ -6,14 +6,11 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/17 16:09:20 by fgras-ca #+# #+# */ -/* Updated: 2024/05/21 13:48:51 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/21 18:03:56 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ #include "Who.hpp" -#include "Channel.hpp" -#include "RPL.hpp" -#include WhoHandler::WhoHandler(Server *server) : _server(server)