This commit is contained in:
Ladebeze66 2024-05-21 14:45:16 +02:00
parent 4c13e1b349
commit 0dc9f5c940
17 changed files with 324 additions and 427 deletions

View File

@ -6,7 +6,7 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */ /* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/15 18:14:12 by fgras-ca #+# #+# */ /* Created: 2024/05/15 18:14:12 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 19:13:53 by fgras-ca ### ########.fr */ /* Updated: 2024/05/21 13:47:12 by fgras-ca ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@ -18,7 +18,7 @@
#include "Client.hpp" #include "Client.hpp"
#include "Channel.hpp" #include "Channel.hpp"
#include "AdditionalCommands.hpp" #include "AdditionalCommands.hpp"
#include "ModeWhoHandler.hpp" #include "Who.hpp"
#include "CommandHandler.hpp" #include "CommandHandler.hpp"
#include "RPL.hpp" #include "RPL.hpp"

View File

@ -6,7 +6,7 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */ /* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/19 15:12:47 by fgras-ca #+# #+# */ /* Created: 2024/05/19 15:12:47 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 22:27:05 by fgras-ca ### ########.fr */ /* Updated: 2024/05/21 12:41:51 by fgras-ca ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@ -19,9 +19,9 @@
#define SERVER_NAME "IRC_Server" #define SERVER_NAME "IRC_Server"
#define SERVER_VERSION "1.0" #define SERVER_VERSION "1.0"
#define USER_MODES "iw" #define USER_MODES ""
#define CHANNEL_MODES "nt" #define CHANNEL_MODES ""
#define CHANNEL_MODES_WITH_PARAMS "kl" #define CHANNEL_MODES_WITH_PARAMS ""
@ -35,7 +35,7 @@
// Fonctions pour générer les réponses RPL // Fonctions pour générer les réponses RPL
inline std::string RPL_WELCOME(Client* client) { inline std::string RPL_WELCOME(Client* client) {
std::ostringstream oss; std::ostringstream oss;
oss << ":" << SERVER_NAME << " 001 " << CLIENT_FD(client) oss << ":" << SERVER_NAME << " 001 " << CLIENT_NICK(client)
<< " :Welcome to the Internet Relay Network " << CLIENT_NICK(client) << " :Welcome to the Internet Relay Network " << CLIENT_NICK(client)
<< "!" << CLIENT_USER(client) << "@" << CLIENT_HOST(client) << "\r\n"; << "!" << CLIENT_USER(client) << "@" << CLIENT_HOST(client) << "\r\n";
return oss.str(); return oss.str();

View File

@ -1,17 +1,17 @@
/* ************************************************************************** */ /* ************************************************************************** */
/* */ /* */
/* ::: :::::::: */ /* ::: :::::::: */
/* ModeWhoHandler.hpp :+: :+: :+: */ /* Who.hpp :+: :+: :+: */
/* +:+ +:+ +:+ */ /* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */ /* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/17 16:08:48 by fgras-ca #+# #+# */ /* Created: 2024/05/17 16:08:48 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 20:36:23 by fgras-ca ### ########.fr */ /* Updated: 2024/05/21 13:47:28 by fgras-ca ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#ifndef MODEWHOHANDLER_HPP #ifndef WHO_HPP
#define MODEWHOHANDLER_HPP #define WHO_HPP
#include "Server.hpp" #include "Server.hpp"
#include "Client.hpp" #include "Client.hpp"
@ -24,11 +24,10 @@
class Server; class Server;
class ModeWhoHandler class WhoHandler
{ {
public: public:
ModeWhoHandler(Server *server); WhoHandler(Server *server);
void handleModeCommand(Client *client, const std::string &command);
void handleWhoCommand(Client *client, const std::string &command); void handleWhoCommand(Client *client, const std::string &command);
void handleWhoisCommand(Client *client, const std::string &command); void handleWhoisCommand(Client *client, const std::string &command);

Binary file not shown.

9
ft_irc3/motd Normal file
View File

@ -0,0 +1,9 @@
░▒▓████████▓▒░▒▓████████▓▒░▒▓█▓▒░▒▓███████▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓███████▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
░▒▓██████▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓████████▓▒░░▒▓██████▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░ ░▒▓█▓▒░▒▓████████▓▒░

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -6,147 +6,153 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */ /* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/16 15:27:29 by fgras-ca #+# #+# */ /* Created: 2024/05/16 15:27:29 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 19:22:28 by fgras-ca ### ########.fr */ /* Updated: 2024/05/21 13:52:54 by fgras-ca ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "AdditionalCommands.hpp" #include "AdditionalCommands.hpp"
void sendWelcomeMessages(Client *client, Server *server) { 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_WELCOME(client));
server->sendToClient(client->getFd(), RPL_CREATED(client)); server->sendToClient(client->getFd(), RPL_YOURHOST(client));
server->sendToClient(client->getFd(), RPL_MYINFO(client)); server->sendToClient(client->getFd(), RPL_CREATED(client));
server->sendToClient(client->getFd(), RPL_ISUPPORT(client, "MODES=EXAMPLE")); server->sendToClient(client->getFd(), RPL_MYINFO(client));
server->sendToClient(client->getFd(), RPL_ISUPPORT(client, "MODES=EXAMPLE"));
sendMotd(client, server); sendMotd(client, server);
} }
void sendMotd(Client *client, Server *server) { void sendMotd(Client *client, Server *server)
std::ifstream motdFile("motd.txt"); {
if (motdFile.is_open()) { std::ifstream motdFile("motd.txt");
std::string line; if (motdFile.is_open())
server->sendToClient(client->getFd(), RPL_MOTDSTART(client)); {
while (std::getline(motdFile, line)) { std::string line;
server->sendToClient(client->getFd(), RPL_MOTD(client, line)); server->sendToClient(client->getFd(), RPL_MOTDSTART(client));
} while (std::getline(motdFile, line))
server->sendToClient(client->getFd(), RPL_ENDOFMOTD(client)); {
motdFile.close(); server->sendToClient(client->getFd(), RPL_MOTD(client, line));
} else { }
server->sendToClient(client->getFd(), ERR_NOMOTD(client)); server->sendToClient(client->getFd(), RPL_ENDOFMOTD(client));
} motdFile.close();
}
else
{
server->sendToClient(client->getFd(), ERR_NOMOTD(client));
}
} }
void broadcastChannelList(Client *client, Server *server) void broadcastChannelList(Client *client, Server *server)
{ {
std::map<std::string, Channel *> &channels = server->getChannels(); std::map<std::string, Channel *> &channels = server->getChannels();
for (std::map<std::string, Channel *>::iterator it = channels.begin(); it != channels.end(); ++it) for (std::map<std::string, Channel *>::iterator it = channels.begin(); it != channels.end(); ++it)
{ {
server->sendToClient(client->getFd(), RPL_LIST(client->getFd(), it->first, it->second->getClients().size(), "Existing channel")); server->sendToClient(client->getFd(), RPL_LIST(client->getFd(), it->first, it->second->getClients().size(), "Existing channel"));
} }
server->sendToClient(client->getFd(), RPL_LISTEND(client->getFd())); server->sendToClient(client->getFd(), RPL_LISTEND(client->getFd()));
} }
// Fonction pour gérer la commande PART // Fonction pour gérer la commande PART
void handlePartCommand(Server *server, Client *client, const std::string &command) void handlePartCommand(Server *server, Client *client, const std::string &command)
{ {
std::istringstream iss(command); std::istringstream iss(command);
std::string cmd, channelName; std::string cmd, channelName;
iss >> cmd >> channelName; iss >> cmd >> channelName;
std::map<std::string, Channel *> &channels = server->getChannels(); std::map<std::string, Channel *> &channels = server->getChannels();
if (channels.find(channelName) != channels.end()) if (channels.find(channelName) != channels.end())
{ {
Channel *channel = channels[channelName]; Channel *channel = channels[channelName];
channel->removeClient(client); channel->removeClient(client);
std::stringstream partMsg; std::stringstream partMsg;
partMsg << ":" << client->getNickname() << " PART " << channelName << "\r\n"; partMsg << ":" << client->getNickname() << " PART " << channelName << "\r\n";
server->sendToClient(client->getFd(), partMsg.str()); server->sendToClient(client->getFd(), partMsg.str());
if (channel->isEmpty()) if (channel->isEmpty())
{ {
delete channel; delete channel;
channels.erase(channelName); channels.erase(channelName);
} }
server->log("Client " + client->getNickname() + " left channel " + channelName, MAGENTA); server->log("Client " + client->getNickname() + " left channel " + channelName, MAGENTA);
} }
else else
{ {
std::stringstream ss; std::stringstream ss;
ss << ":server 403 " << client->getNickname() << " " << channelName << " :No such channel\r\n"; ss << ":server 403 " << client->getNickname() << " " << channelName << " :No such channel\r\n";
server->sendToClient(client->getFd(), ss.str()); server->sendToClient(client->getFd(), ss.str());
} }
} }
// Fonction pour gérer la commande NICK // Fonction pour gérer la commande NICK
void handleNickCommand(Server *server, Client *client, const std::string &command) void handleNickCommand(Server *server, Client *client, const std::string &command)
{ {
std::istringstream iss(command); std::istringstream iss(command);
std::string cmd, newNick; std::string cmd, newNick;
iss >> cmd >> newNick; iss >> cmd >> newNick;
std::stringstream nickMsg; std::stringstream nickMsg;
nickMsg << ":" << client->getNickname() << " NICK " << newNick << "\r\n"; nickMsg << ":" << client->getNickname() << " NICK " << newNick << "\r\n";
server->sendToClient(client->getFd(), nickMsg.str()); server->sendToClient(client->getFd(), nickMsg.str());
client->setNickname(newNick); client->setNickname(newNick);
std::stringstream ss; std::stringstream ss;
ss << "Client " << client->getFd() << " changed nickname to " << newNick; ss << "Client " << client->getFd() << " changed nickname to " << newNick;
server->log(ss.str(), GREEN); server->log(ss.str(), GREEN);
} }
void handlePrivmsgCommand(Server *server, Client *client, const std::string &command) void handlePrivmsgCommand(Server *server, Client *client, const std::string &command)
{ {
std::istringstream iss(command); std::istringstream iss(command);
std::string cmd, target, message; std::string cmd, target, message;
iss >> cmd >> target; iss >> cmd >> target;
getline(iss, message); getline(iss, message);
// Enlever le ':' initial dans le message si présent // Enlever le ':' initial dans le message si présent
if (!message.empty() && message[0] == ':') if (!message.empty() && message[0] == ':')
message = message.substr(1); message = message.substr(1);
// Récupérer les canaux du serveur // Récupérer les canaux du serveur
std::map<std::string, Channel *> &channels = server->getChannels(); std::map<std::string, Channel *> &channels = server->getChannels();
// Si la cible est un canal // Si la cible est un canal
if (channels.find(target) != channels.end()) if (channels.find(target) != channels.end())
{ {
Channel *channel = channels[target]; Channel *channel = channels[target];
std::vector<Client *> channelClients = channel->getClients(); std::vector<Client *> channelClients = channel->getClients();
for (size_t i = 0; i < channelClients.size(); ++i) for (size_t i = 0; i < channelClients.size(); ++i)
{ {
// Envoyer le message à tous les clients du canal sauf l'émetteur // Envoyer le message à tous les clients du canal sauf l'émetteur
if (channelClients[i] != client) if (channelClients[i] != client)
{ {
std::stringstream privMsg; std::stringstream privMsg;
privMsg << ":" << client->getNickname() << " PRIVMSG " << target << " :" << message << "\r\n"; privMsg << ":" << client->getNickname() << " PRIVMSG " << target << " :" << message << "\r\n";
server->sendToClient(channelClients[i]->getFd(), privMsg.str()); server->sendToClient(channelClients[i]->getFd(), privMsg.str());
} }
} }
} }
// Si la cible est un utilisateur // Si la cible est un utilisateur
else else
{ {
Client *targetClient = server->getClientByName(target); // Utiliser getClientByName pour trouver le client par nom Client *targetClient = server->getClientByName(target); // Utiliser getClientByName pour trouver le client par nom
if (targetClient) if (targetClient)
{ {
std::stringstream privMsg; std::stringstream privMsg;
privMsg << ":" << client->getNickname() << " PRIVMSG " << target << " :" << message << "\r\n"; privMsg << ":" << client->getNickname() << " PRIVMSG " << target << " :" << message << "\r\n";
server->sendToClient(targetClient->getFd(), privMsg.str()); server->sendToClient(targetClient->getFd(), privMsg.str());
} }
else else
{ {
// Si la cible n'est ni un canal ni un utilisateur existant, envoyer un message d'erreur // Si la cible n'est ni un canal ni un utilisateur existant, envoyer un message d'erreur
std::stringstream errorMsg; std::stringstream errorMsg;
errorMsg << ":server 401 " << client->getNickname() << " " << target << " :No such nick/channel\r\n"; errorMsg << ":server 401 " << client->getNickname() << " " << target << " :No such nick/channel\r\n";
server->sendToClient(client->getFd(), errorMsg.str()); server->sendToClient(client->getFd(), errorMsg.str());
} }
} }
} }

View File

@ -6,7 +6,7 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */ /* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/15 18:32:23 by fgras-ca #+# #+# */ /* Created: 2024/05/15 18:32:23 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 22:09:39 by fgras-ca ### ########.fr */ /* Updated: 2024/05/21 14:09:07 by fgras-ca ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@ -67,19 +67,22 @@ void ClientManager::handleClient(int client_fd)
} }
} }
void ClientManager::removeClient(int client_fd) void ClientManager::removeClient(int clientFd)
{ {
Client *client = _server->_clients[client_fd]; Client* client = _server->_clients[clientFd];
if (client) if (client)
{ {
std::map<std::string, Channel *>::iterator it = _server->_channels.begin(); // Log the nickname being freed
_server->log("Removing client: " + client->getNickname(), YELLOW);
std::map<std::string, Channel*>::iterator it = _server->_channels.begin();
while (it != _server->_channels.end()) while (it != _server->_channels.end())
{ {
it->second->removeClient(client); it->second->removeClient(client);
if (it->second->isEmpty()) if (it->second->isEmpty())
{ {
delete it->second; delete it->second;
std::map<std::string, Channel *>::iterator it_to_delete = it++; std::map<std::string, Channel*>::iterator it_to_delete = it++;
_server->_channels.erase(it_to_delete); _server->_channels.erase(it_to_delete);
} }
else else
@ -88,13 +91,13 @@ void ClientManager::removeClient(int client_fd)
} }
} }
delete client; delete client;
_server->_clients.erase(client_fd); _server->_clients.erase(clientFd);
} }
std::vector<struct pollfd>::iterator it_poll = _server->_poll_fds.begin(); std::vector<struct pollfd>::iterator it_poll = _server->_poll_fds.begin();
while (it_poll != _server->_poll_fds.end()) while (it_poll != _server->_poll_fds.end())
{ {
if (it_poll->fd == client_fd) if (it_poll->fd == clientFd)
{ {
_server->_poll_fds.erase(it_poll); _server->_poll_fds.erase(it_poll);
break; break;
@ -103,6 +106,7 @@ void ClientManager::removeClient(int client_fd)
} }
std::stringstream ss; std::stringstream ss;
ss << "Client disconnected: " << client_fd; ss << "Client disconnected: " << clientFd;
_server->log(ss.str(), YELLOW); _server->log(ss.str(), YELLOW);
} }

View File

@ -6,7 +6,7 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */ /* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/15 18:26:34 by fgras-ca #+# #+# */ /* Created: 2024/05/15 18:26:34 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 23:47:26 by fgras-ca ### ########.fr */ /* Updated: 2024/05/21 14:19:19 by fgras-ca ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@ -145,10 +145,14 @@ void CommandHandler::handleNick(Client* client, const std::vector<std::string>&
_server->sendToClient(client->getFd(), ERR_NICKNAMEINUSE(client, newNick)); _server->sendToClient(client->getFd(), ERR_NICKNAMEINUSE(client, newNick));
return; return;
} }
client->setNickname(newNick); client->setNickname(newNick);
_server->sendToClient(client->getFd(), ":" + newNick + " NICK " + newNick + "\r\n"); _server->sendToClient(client->getFd(), ":" + newNick + " NICK " + newNick + "\r\n");
_server->log("Client NickName is " + newNick, GREEN);
std::ostringstream oss;
oss << "Client " << client->getFd() << " changed nickname to " << newNick;
_server->log(oss.str(), GREEN);
} }
void CommandHandler::handleUser(Client* client, const std::vector<std::string>& tokens) void CommandHandler::handleUser(Client* client, const std::vector<std::string>& tokens)
@ -156,7 +160,8 @@ void CommandHandler::handleUser(Client* client, const std::vector<std::string>&
// Set the user and realname fields // Set the user and realname fields
client->setUser(tokens[1]); client->setUser(tokens[1]);
std::string realname = tokens[4]; std::string realname = tokens[4];
if (realname[0] == ':') { if (realname[0] == ':')
{
realname = realname.substr(1); // Remove leading ':' realname = realname.substr(1); // Remove leading ':'
} }
client->setRealName(realname); client->setRealName(realname);
@ -167,11 +172,14 @@ void CommandHandler::handleUser(Client* client, const std::vector<std::string>&
_server->log(logMsg.str(), BLUE); _server->log(logMsg.str(), BLUE);
// Authenticate if password and nickname are already set // 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(); client->authenticate();
sendWelcomeMessages(client, _server); sendWelcomeMessages(client, _server);
_server->log("Client " + client->getNickname() + " authenticated successfully.", GREEN); _server->log("Client " + client->getNickname() + " authenticated successfully.", GREEN);
} else { }
else
{
std::ostringstream authFailMsg; std::ostringstream authFailMsg;
authFailMsg << "Client " << client->getFd() << ": USER command failed - authentication conditions not met."; authFailMsg << "Client " << client->getFd() << ": USER command failed - authentication conditions not met.";
_server->log(authFailMsg.str(), RED); _server->log(authFailMsg.str(), RED);
@ -191,27 +199,22 @@ void CommandHandler::processCommand(Client *client, const std::string &command)
{ {
handlePartCommand(_server, client, command); handlePartCommand(_server, client, command);
} }
else if (command.find("NICK") == 0) /*else if (command.find("NICK") == 0)
{ {
handleNickCommand(_server, client, command); handleNickCommand(_server, client, command);
} }*/
else if (command.find("PRIVMSG") == 0) else if (command.find("PRIVMSG") == 0)
{ {
handlePrivmsgCommand(_server, client, command); handlePrivmsgCommand(_server, client, command);
} }
else if (command.find("MODE") == 0)
{
ModeWhoHandler modeHandler(_server);
modeHandler.handleModeCommand(client, command);
}
else if (command.find("WHO") == 0) else if (command.find("WHO") == 0)
{ {
ModeWhoHandler whoHandler(_server); WhoHandler whoHandler(_server);
whoHandler.handleWhoCommand(client, command); whoHandler.handleWhoCommand(client, command);
} }
else if (command.find("WHOIS") == 0) else if (command.find("WHOIS") == 0)
{ {
ModeWhoHandler whoHandler(_server); WhoHandler whoHandler(_server);
whoHandler.handleWhoisCommand(client, command); whoHandler.handleWhoisCommand(client, command);
} }
else if (command.find("PING") == 0) else if (command.find("PING") == 0)

View File

@ -6,321 +6,234 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */ /* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/15 12:17:12 by fgras-ca #+# #+# */ /* Created: 2024/05/15 12:17:12 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 22:16:03 by fgras-ca ### ########.fr */ /* Updated: 2024/05/21 14:18:03 by fgras-ca ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "Server.hpp" #include "Server.hpp"
Server::Server(int port, const std::string &password) Server::Server(int port, const std::string &password)
: _port(port), _password(password), _clientManager(new ClientManager(this)), _commandHandler(new CommandHandler(this)) : _port(port), _password(password), _clientManager(new ClientManager(this)), _commandHandler(new CommandHandler(this))
{ {
initServer(); initServer();
} }
Server::~Server() Server::~Server()
{ {
delete _clientManager; delete _clientManager;
delete _commandHandler; delete _commandHandler;
for (std::map<int, Client*>::iterator it = _clients.begin(); it != _clients.end(); ++it) for (std::map<int, Client*>::iterator it = _clients.begin(); it != _clients.end(); ++it)
{ {
delete it->second; delete it->second;
} }
for (std::map<std::string, Channel*>::iterator it = _channels.begin(); it != _channels.end(); ++it) for (std::map<std::string, Channel*>::iterator it = _channels.begin(); it != _channels.end(); ++it)
{ {
delete it->second; delete it->second;
} }
close(_server_fd); close(_server_fd);
} }
void Server::initServer() void Server::initServer()
{ {
_server_fd = socket(AF_INET, SOCK_STREAM, 0); _server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (_server_fd == -1) if (_server_fd == -1)
{ {
log("Failed to create socket.", RED); log("Failed to create socket.", RED);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
int opt = 1; int opt = 1;
if (setsockopt(_server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) if (setsockopt(_server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1)
{ {
log("Failed to set socket options.", RED); log("Failed to set socket options.", RED);
close(_server_fd); close(_server_fd);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct sockaddr_in server_addr; struct sockaddr_in server_addr;
std::memset(&server_addr, 0, sizeof(server_addr)); std::memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(_port); server_addr.sin_port = htons(_port);
if (bind(_server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) if (bind(_server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{ {
log("Failed to bind socket.", RED); log("Failed to bind socket.", RED);
close(_server_fd); // Close the socket if bind fails close(_server_fd); // Close the socket if bind fails
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (listen(_server_fd, SOMAXCONN) == -1) if (listen(_server_fd, SOMAXCONN) == -1)
{ {
log("Failed to listen on socket.", RED); log("Failed to listen on socket.", RED);
close(_server_fd); // Close the socket if listen fails close(_server_fd); // Close the socket if listen fails
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
log("Server initialized.", GREEN); log("Server initialized.", GREEN);
} }
void Server::run() void Server::run()
{ {
struct pollfd server_pollfd; struct pollfd server_pollfd;
server_pollfd.fd = _server_fd; server_pollfd.fd = _server_fd;
server_pollfd.events = POLLIN; server_pollfd.events = POLLIN;
server_pollfd.revents = 0; server_pollfd.revents = 0;
_poll_fds.push_back(server_pollfd); _poll_fds.push_back(server_pollfd);
// Ajout de l'entrée pour les commandes serveur // Ajout de l'entrée pour les commandes serveur
struct pollfd stdin_pollfd; struct pollfd stdin_pollfd;
stdin_pollfd.fd = STDIN_FILENO; stdin_pollfd.fd = STDIN_FILENO;
stdin_pollfd.events = POLLIN; stdin_pollfd.events = POLLIN;
stdin_pollfd.revents = 0; stdin_pollfd.revents = 0;
_poll_fds.push_back(stdin_pollfd); _poll_fds.push_back(stdin_pollfd);
while (true) while (true)
{ {
int poll_count = poll(&_poll_fds[0], _poll_fds.size(), -1); int poll_count = poll(&_poll_fds[0], _poll_fds.size(), -1);
if (poll_count == -1) if (poll_count == -1)
{ {
log("Poll error.", RED); log("Poll error.", RED);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
for (size_t i = 0; i < _poll_fds.size(); ++i) for (size_t i = 0; i < _poll_fds.size(); ++i)
{ {
if (_poll_fds[i].revents & POLLIN) if (_poll_fds[i].revents & POLLIN)
{ {
if (_poll_fds[i].fd == _server_fd) if (_poll_fds[i].fd == _server_fd)
{ {
_clientManager->acceptClient(); _clientManager->acceptClient();
} }
else if (_poll_fds[i].fd == STDIN_FILENO) else if (_poll_fds[i].fd == STDIN_FILENO)
{ {
handleServerCommands(); handleServerCommands();
} }
else else
{ {
_clientManager->handleClient(_poll_fds[i].fd); _clientManager->handleClient(_poll_fds[i].fd);
} }
} }
} }
} }
} }
std::map<std::string, Channel *> &Server::getChannels() std::map<std::string, Channel *> &Server::getChannels()
{ {
return _channels; return _channels;
} }
const std::string &Server::getPassword() const const std::string &Server::getPassword() const
{ {
return _password; return _password;
} }
void Server::handleServerCommands() void Server::handleServerCommands()
{ {
std::string command; std::string command;
std::getline(std::cin, command); std::getline(std::cin, command);
if (command == "quit") if (command == "quit")
{ {
log("Server shutting down.", YELLOW); log("Server shutting down.", YELLOW);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
else if (command == "channels") else if (command == "channels")
{ {
log("Listing all channels:", BLUE); log("Listing all channels:", BLUE);
for (std::map<std::string, Channel*>::iterator it = _channels.begin(); it != _channels.end(); ++it) for (std::map<std::string, Channel*>::iterator it = _channels.begin(); it != _channels.end(); ++it)
{ {
log(it->first, BLUE); log(it->first, BLUE);
} }
} }
else if (command == "clients") else if (command == "clients")
{ {
log("Listing all clients:", BLUE); log("Listing all clients:", BLUE);
for (std::map<int, Client*>::iterator it = _clients.begin(); it != _clients.end(); ++it) for (std::map<int, Client*>::iterator it = _clients.begin(); it != _clients.end(); ++it)
{ {
log(it->second->getNickname(), BLUE); log(it->second->getNickname(), BLUE);
} }
} }
else else
{ {
log("Unknown server command.", RED); log("Unknown server command.", RED);
} }
} }
void Server::log(const std::string &message, const std::string &color) void Server::log(const std::string &message, const std::string &color)
{ {
std::cout << color << message << "\033[0m" << std::endl; std::cout << color << message << "\033[0m" << std::endl;
} }
void Server::sendToClient(int client_fd, const std::string &message) void Server::sendToClient(int client_fd, const std::string &message)
{ {
int result = send(client_fd, message.c_str(), message.length(), 0); int result = send(client_fd, message.c_str(), message.length(), 0);
if (result < 0) if (result < 0)
{ {
std::stringstream ss; std::stringstream ss;
ss << "Failed to send message to client " << client_fd; ss << "Failed to send message to client " << client_fd;
log(ss.str(), RED); log(ss.str(), RED);
} }
else else
{ {
std::stringstream ss; std::stringstream ss;
ss << "Sent message to client " << client_fd << ": " << message; ss << "Sent message to client " << client_fd << ": " << message;
log(ss.str(), BLUE); log(ss.str(), BLUE);
} }
} }
void Server::broadcast(const std::string &message) void Server::broadcast(const std::string &message)
{ {
for (std::map<int, Client *>::iterator it = _clients.begin(); it != _clients.end(); ++it) for (std::map<int, Client *>::iterator it = _clients.begin(); it != _clients.end(); ++it)
{ {
sendToClient(it->first, message); sendToClient(it->first, message);
} }
} }
Client* Server::getClientByName(const std::string &name) Client* Server::getClientByName(const std::string &name)
{ {
for (std::map<int, Client *>::iterator it = _clients.begin(); it != _clients.end(); ++it) for (std::map<int, Client *>::iterator it = _clients.begin(); it != _clients.end(); ++it)
{ {
if (it->second->getNickname() == name) if (it->second->getNickname() == name)
{ {
return it->second; return it->second;
} }
} }
return NULL; // Remplacez nullptr par NULL return NULL; // Remplacez nullptr par NULL
} }
void Server::sendChannelListToClient(Client *client) void Server::sendChannelListToClient(Client *client)
{ {
std::map<std::string, Channel *> &channels = getChannels(); std::map<std::string, Channel *> &channels = getChannels();
for (std::map<std::string, Channel *>::iterator it = channels.begin(); it != channels.end(); ++it) for (std::map<std::string, Channel *>::iterator it = channels.begin(); it != channels.end(); ++it)
{ {
sendToClient(client->getFd(), RPL_LIST(client->getFd(), it->first, it->second->getClients().size(), "Existing channel")); sendToClient(client->getFd(), RPL_LIST(client->getFd(), it->first, it->second->getClients().size(), "Existing channel"));
} }
sendToClient(client->getFd(), RPL_LISTEND(client->getFd())); sendToClient(client->getFd(), RPL_LISTEND(client->getFd()));
} }
void Server::disconnectClient(int clientFd) void Server::disconnectClient(int clientFd)
{ {
close(clientFd); Client* client = _clients[clientFd];
_clients.erase(clientFd); if (client)
for (std::vector<struct pollfd>::iterator it = _poll_fds.begin(); it != _poll_fds.end(); ++it)
{ {
if (it->fd == clientFd) log("Disconnecting client: " + client->getNickname(), YELLOW);
{ _clients.erase(clientFd);
_poll_fds.erase(it); delete client;
break;
}
} }
struct MatchFd
{
int fd;
MatchFd(int fd) : fd(fd) {}
bool operator()(const pollfd& pfd) const { return pfd.fd == fd; }
};
_poll_fds.erase(std::remove_if(_poll_fds.begin(), _poll_fds.end(), MatchFd(clientFd)), _poll_fds.end());
std::ostringstream oss; std::ostringstream oss;
oss << "Client disconnected: " << clientFd; oss << "Client disconnected: " << clientFd;
log(oss.str(), YELLOW); log(oss.str(), YELLOW);
} }
/* Explications des Fonctions
Server::Server(int port, const std::string &password)
Description: Constructeur de la classe Server. Initialise le serveur avec le port et le mot de passe fournis.
Paramètres:
int port: Le port sur lequel le serveur écoute.
const std::string &password: Le mot de passe requis pour se connecter au serveur.
Détails: Appelle initServer() pour initialiser les paramètres du socket et commencer l'écoute des connexions.
Server::~Server()
Description: Destructeur de la classe Server. Ferme le socket du serveur et libère la mémoire des clients.
Détails: Parcourt la map _clients et delete chaque objet Client.
void Server::initServer()
Description: Initialise le socket du serveur et configure le binding et l'écoute.
Détails: Crée un socket avec socket(), lie le socket à une adresse avec bind(), et met le socket en mode écoute avec listen().
void Server::run()
Description: Boucle principale du serveur qui gère les connexions entrantes et les communications avec les clients.
Détails: Utilise poll() pour surveiller les événements sur les sockets. Accepte les nouvelles connexions avec acceptClient() et gère les communications avec handleClient().
void Server::acceptClient()
Description: Accepte une nouvelle connexion client et l'ajoute à la liste des clients.
Détails: Crée un nouvel objet Client et l'ajoute à la map _clients. Ajoute le descripteur de fichier du client à _poll_fds.
void Server::handleClient(int client_fd)
Description: Gère les messages entrants des clients.
Paramètres:
int client_fd: Le descripteur de fichier du client.
Détails: Reçoit les messages du client et vérifie l'authentification. Si le client n'est pas authentifié, vérifie le mot de passe. Si le client est authentifié, répond au message.
void Server::removeClient(int client_fd)
Description: Supprime un client de la liste et ferme la connexion.
Paramètres:
int client_fd: Le descripteur de fichier du client.
Détails: Ferme le socket du client et le supprime de la map _clients et du vecteur _poll_fds.
void Server::log(const std::string &message, const std::string &color)
Description: Enregistre un message dans les logs et l'affiche avec des couleurs dans la console.
Paramètres:
const std::string &message: Le message à enregistrer.
const std::string &color: La couleur du message.
Détails: Utilise logMessage() pour enregistrer et afficher le message.
void Server::sendToClient(int client_fd, const std::string &message)
Description: Envoie un message à un client.
Paramètres:
int client_fd: Le descripteur de fichier du client.
const std::string &message: Le message à envoyer.
Détails: Utilise send() pour envoyer le message au client.
Lecture Ligne par Ligne : Utilisez std::istringstream pour lire le message ligne par ligne et traiter chaque commande séparément.
Suppression des Caractères de Fin de Ligne : Utilisez erase et std::remove pour supprimer les caractères \r et \n de chaque ligne avant de traiter la commande.
Vérification du Mot de Passe : Si le client n'est pas authentifié, vérifiez s'il envoie la commande PASS et validez le mot de passe. Sinon, répondez avec un message demandant le mot de passe.
Explications des Modifications
Notification de Jonction : Lorsque le client rejoint un canal, le serveur envoie une notification de jonction avec la commande JOIN.
std::stringstream joinMsg;
joinMsg << ":" << client->getFd() << " JOIN " << channelName << "\r\n";
sendToClient(client->getFd(), joinMsg.str());
Liste des Utilisateurs : Le serveur envoie la liste des utilisateurs dans le canal en utilisant le code de réponse 353.
std::string usersList = getUsersList(channel);
sendToClient(client->getFd(), usersList);
Fin de la Liste des Utilisateurs : Le serveur envoie un message de fin de liste des utilisateurs avec le code de réponse 366.
std::stringstream endOfNamesMsg;
endOfNamesMsg << ":server 366 " << client->getFd() << " " << channelName << " :End of /NAMES list.\r\n";
sendToClient(client->getFd(), endOfNamesMsg.str());
Fonction getUsersList : Cette fonction génère la liste des utilisateurs dans le canal en utilisant le format correct.
std::string Server::getUsersList(Channel *channel)
{
std::vector<Client *> clients = channel->getClients();
std::stringstream ss;
ss << ":server 353 " << clients[0]->getFd() << " = " << channel->getName() << " :";
for (size_t i = 0; i < clients.size(); ++i)
{
if (i > 0)
ss << " ";
ss << clients[i]->getFd();
}
ss << "\r\n";
return ss.str();
}
Avec ces modifications, votre serveur IRC devrait maintenant informer correctement le client HexChat des utilisateurs présents dans un canal, ce qui devrait faire apparaître les canaux et leurs utilisateurs correctement dans l'interface du client.
*/

View File

@ -1,63 +1,26 @@
/* ************************************************************************** */ /* ************************************************************************** */
/* */ /* */
/* ::: :::::::: */ /* ::: :::::::: */
/* ModeWhoHandler.cpp :+: :+: :+: */ /* Who.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */ /* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */ /* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/17 16:09:20 by fgras-ca #+# #+# */ /* Created: 2024/05/17 16:09:20 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 20:52:30 by fgras-ca ### ########.fr */ /* Updated: 2024/05/21 13:48:51 by fgras-ca ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "ModeWhoHandler.hpp" #include "Who.hpp"
#include "Channel.hpp" #include "Channel.hpp"
#include "RPL.hpp" #include "RPL.hpp"
#include <sstream> #include <sstream>
ModeWhoHandler::ModeWhoHandler(Server *server) WhoHandler::WhoHandler(Server *server)
: _server(server) : _server(server)
{ {
} }
void ModeWhoHandler::handleModeCommand(Client *client, const std::string &command) void WhoHandler::handleWhoCommand(Client *client, const std::string &command)
{
std::istringstream iss(command);
std::string cmd, channelName, mode, user;
iss >> cmd >> channelName >> mode >> user;
std::map<std::string, Channel *> &channels = _server->getChannels();
if (channels.find(channelName) == channels.end())
{
_server->sendToClient(client->getFd(), ERR_NOSUCHCHANNEL(client->getFd(), channelName));
return;
}
Channel *channel = channels[channelName];
if (mode == "+o")
{
if (client->isOperator())
{
Client *targetClient = _server->getClientByName(user);
if (targetClient)
{
channel->addOperator(targetClient);
_server->sendToClient(client->getFd(), RPL_CHANNELMODEIS(client->getFd(), channelName, "+o"));
_server->log("Client " + user + " is now an operator in channel " + channelName, GREEN);
}
else
{
_server->sendToClient(client->getFd(), ERR_NOSUCHNICK(client->getFd(), user));
}
}
else
{
_server->sendToClient(client->getFd(), ERR_CHANOPRIVSNEEDED(client->getFd(), channelName));
}
}
}
void ModeWhoHandler::handleWhoCommand(Client *client, const std::string &command)
{ {
std::istringstream iss(command); std::istringstream iss(command);
std::string cmd, mask; std::string cmd, mask;
@ -86,7 +49,7 @@ void ModeWhoHandler::handleWhoCommand(Client *client, const std::string &command
_server->sendToClient(client->getFd(), RPL_ENDOFWHO(client->getFd(), mask)); _server->sendToClient(client->getFd(), RPL_ENDOFWHO(client->getFd(), mask));
} }
void ModeWhoHandler::handleWhoisCommand(Client *client, const std::string &command) void WhoHandler::handleWhoisCommand(Client *client, const std::string &command)
{ {
std::istringstream iss(command); std::istringstream iss(command);
std::string cmd, target; std::string cmd, target;