This commit is contained in:
Ladebeze66 2024-05-20 20:28:15 +02:00
parent f2725946e0
commit 4c13e1b349
12 changed files with 237 additions and 81 deletions

View File

@ -6,7 +6,7 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/17 16:08:48 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 15:15:39 by fgras-ca ### ########.fr */
/* Updated: 2024/05/19 20:36:23 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
@ -30,6 +30,7 @@ public:
ModeWhoHandler(Server *server);
void handleModeCommand(Client *client, const std::string &command);
void handleWhoCommand(Client *client, const std::string &command);
void handleWhoisCommand(Client *client, const std::string &command);
private:
Server *_server;

View File

@ -6,7 +6,7 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/19 15:12:47 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 19:07:25 by fgras-ca ### ########.fr */
/* Updated: 2024/05/19 22:27:05 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
@ -30,6 +30,7 @@
#define CLIENT_NICK(client) ((client)->getNickname())
#define CLIENT_USER(client) ((client)->getUser())
#define CLIENT_HOST(client) ((client)->getHost())
#define CLIENT_REALNAME(client) ((client)->getRealName())
// Fonctions pour générer les réponses RPL
inline std::string RPL_WELCOME(Client* client) {
@ -217,5 +218,120 @@ inline std::string ERR_UNKNOWNCOMMAND(int clientFd, const std::string& command)
return oss.str();
}
// RPL Mode Messages
inline std::string RPL_CHANNELMODEIS(int clientFd, const std::string& channel, const std::string& mode)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 324 " << clientFd << " " << channel << " " << mode << "\r\n";
return oss.str();
}
inline std::string RPL_NOCHANMODES(int clientFd, const std::string& channel)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 477 " << clientFd << " " << channel << " :Channel doesn't support modes\r\n";
return oss.str();
}
inline std::string ERR_NOSUCHCHANNEL(int clientFd, const std::string& channel)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 403 " << clientFd << " " << channel << " :No such channel\r\n";
return oss.str();
}
inline std::string ERR_CHANOPRIVSNEEDED(int clientFd, const std::string& channel)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 482 " << clientFd << " " << channel << " :You're not channel operator\r\n";
return oss.str();
}
inline std::string ERR_NOSUCHNICK(int clientFd, const std::string& nick)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 401 " << clientFd << " " << nick << " :No such nick/channel\r\n";
return oss.str();
}
// WHO Command RPLs
inline std::string RPL_WHOREPLY(const std::string& channel, Client* target)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 352 " << CLIENT_NICK(target) << " " << channel << " "
<< CLIENT_USER(target) << " " << CLIENT_HOST(target) << " " << SERVER_NAME << " "
<< CLIENT_NICK(target) << " H :0 " << CLIENT_REALNAME(target) << "\r\n";
return oss.str();
}
inline std::string RPL_ENDOFWHO(int clientFd, const std::string& channel)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 315 " << clientFd << " " << channel << " :End of /WHO list.\r\n";
return oss.str();
}
// WHOIS Command RPLs
inline std::string RPL_WHOISUSER(int clientFd, Client* target)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 311 " << clientFd << " " << CLIENT_NICK(target) << " "
<< CLIENT_USER(target) << " " << CLIENT_HOST(target) << " * :" << CLIENT_REALNAME(target) << "\r\n";
return oss.str();
}
inline std::string RPL_WHOISSERVER(int clientFd, const std::string& targetNick, const std::string& serverInfo)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 312 " << clientFd << " " << targetNick << " " << SERVER_NAME
<< " :" << serverInfo << "\r\n";
return oss.str();
}
inline std::string RPL_ENDOFWHOIS(int clientFd, const std::string& targetNick)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 318 " << clientFd << " " << targetNick << " :End of /WHOIS list.\r\n";
return oss.str();
}
inline std::string ERR_NONICKNAMEGIVEN(int clientFd)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 431 " << clientFd << " :No nickname given\r\n";
return oss.str();
}
// CAP Command RPLs
inline std::string RPL_CAP(int clientFd, const std::string& subcommand, const std::string& capabilities)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " CAP " << clientFd << " " << subcommand << " :" << capabilities << "\r\n";
return oss.str();
}
// ERR_NOTREGISTERED
inline std::string ERR_NOTREGISTERED(int clientFd)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " 451 " << clientFd << " :You have not registered\r\n";
return oss.str();
}
inline std::string RPL_PASSACCEPTED(Client* client)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " NOTICE " << CLIENT_FD(client)
<< " :Password accepted!\r\n";
return oss.str();
}
// Add this function to handle the CAP END response
inline std::string RPL_CAPEND(int clientFd)
{
std::ostringstream oss;
oss << ":" << SERVER_NAME << " CAP " << clientFd << " END\r\n";
return oss.str();
}
#endif // RPL_HPP

View File

@ -6,7 +6,7 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/15 12:15:13 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 16:30:56 by fgras-ca ### ########.fr */
/* Updated: 2024/05/19 21:13:24 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
@ -55,6 +55,7 @@ public:
void broadcast(const std::string &message);
Client* getClientByName(const std::string &name); // Ajoutez cette méthode
void sendChannelListToClient(Client *client);
void disconnectClient(int clientFd);
protected:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -6,7 +6,7 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/15 18:32:23 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 18:55:55 by fgras-ca ### ########.fr */
/* Updated: 2024/05/19 22:09:39 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
@ -34,10 +34,8 @@ void ClientManager::acceptClient()
_server->_poll_fds.push_back(client_pollfd);
std::stringstream ss;
ss << "Client connected: " << client_fd;
_server->log(ss.str(), GREEN);
sendWelcomeMessages(newClient, _server);
ss << "Client attempting connection: " << client_fd;
_server->log(ss.str(), YELLOW);
}
void ClientManager::handleClient(int client_fd)

View File

@ -6,7 +6,7 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/15 18:26:34 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 19:13:14 by fgras-ca ### ########.fr */
/* Updated: 2024/05/19 23:47:26 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
@ -54,33 +54,15 @@ void CommandHandler::handleCapCommand(Client* client, const std::vector<std::str
}
std::string subcommand = tokens[1];
std::string capabilities = "multi-prefix extended-join account-notify batch invite-notify";
if (subcommand == "LS")
{
// Example for CAP LS response
std::vector<std::string> capLines;
capLines.push_back("multi-prefix extended-join account-notify batch invite-notify tls");
capLines.push_back("cap-notify server-time example.org/dummy-cap=dummyvalue example.org/second-dummy-cap");
capLines.push_back("userhost-in-names sasl=EXTERNAL,DH-AES,DH-BLOWFISH,ECDSA-NIST256P-CHALLENGE,PLAIN");
for (size_t i = 0; i < capLines.size(); ++i)
{
std::ostringstream oss;
oss << ":irc.example.com CAP " << client->getNickname() << " LS";
if (i != capLines.size() - 1)
oss << " * :";
else
oss << " :";
oss << capLines[i] << "\r\n";
_server->sendToClient(client->getFd(), oss.str());
}
_server->sendToClient(client->getFd(), RPL_CAP(client->getFd(), "LS", capabilities));
}
else if (subcommand == "LIST")
{
// Example for CAP LIST response
std::ostringstream oss;
oss << ":irc.example.com CAP " << client->getNickname() << " LIST :example.org/example-cap example.org/second-example-cap account-notify invite-notify batch example.org/third-example-cap\r\n";
_server->sendToClient(client->getFd(), oss.str());
_server->sendToClient(client->getFd(), RPL_CAP(client->getFd(), "LIST", capabilities));
}
else if (subcommand == "REQ")
{
@ -89,21 +71,16 @@ void CommandHandler::handleCapCommand(Client* client, const std::vector<std::str
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client->getFd(), "CAP"));
return;
}
// Example for CAP REQ response
std::string requestedCaps = tokens[2];
std::ostringstream ackResponse;
ackResponse << ":irc.example.com CAP " << client->getNickname() << " ACK :" << requestedCaps << "\r\n";
_server->sendToClient(client->getFd(), ackResponse.str());
std::string requestedCapabilities = tokens[2];
// For simplicity, we assume all requested capabilities are accepted
_server->sendToClient(client->getFd(), RPL_CAP(client->getFd(), "ACK", requestedCapabilities));
}
else if (subcommand == "END")
{
// Example for CAP END response
_server->sendToClient(client->getFd(), ":irc.example.com CAP " + client->getNickname() + " END\r\n");
_server->sendToClient(client->getFd(), RPL_CAPEND(client->getFd()));
}
else
{
// Unknown CAP subcommand
_server->sendToClient(client->getFd(), ERR_UNKNOWNCOMMAND(client->getFd(), "CAP"));
}
}
@ -168,40 +145,41 @@ void CommandHandler::handleNick(Client* client, const std::vector<std::string>&
_server->sendToClient(client->getFd(), ERR_NICKNAMEINUSE(client, newNick));
return;
}
std::string oldNick = client->getNickname();
client->setNickname(newNick);
if (!oldNick.empty()) {
_server->broadcast(":" + oldNick + " NICK " + newNick + "\r\n");
}
_server->sendToClient(client->getFd(), ":" + newNick + " NICK " + newNick + "\r\n");
_server->log("Client " + oldNick + " changed nickname to " + newNick, GREEN);
_server->log("Client NickName is " + newNick, GREEN);
}
void CommandHandler::handleUser(Client* client, const std::vector<std::string>& tokens)
{
if (tokens.size() < 5) {
_server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "USER"));
return;
}
if (client->isAuthenticated()) {
_server->sendToClient(client->getFd(), ERR_ALREADYREGISTERED(client));
return;
}
// Set the user and realname fields
client->setUser(tokens[1]);
client->setRealName(tokens[4].substr(1)); // remove leading ':'
std::string realname = tokens[4];
if (realname[0] == ':') {
realname = realname.substr(1); // Remove leading ':'
}
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);
// Authenticate if password and nickname are already set
if (client->getPassword() == _server->_password && !client->getNickname().empty()) {
client->authenticate();
sendWelcomeMessages(client, _server);
_server->log("Client " + client->getNickname() + " authenticated.", GREEN);
_server->log("Client " + client->getNickname() + " authenticated successfully.", GREEN);
} 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)
@ -230,6 +208,11 @@ void CommandHandler::processCommand(Client *client, const std::string &command)
{
ModeWhoHandler whoHandler(_server);
whoHandler.handleWhoCommand(client, command);
}
else if (command.find("WHOIS") == 0)
{
ModeWhoHandler whoHandler(_server);
whoHandler.handleWhoisCommand(client, command);
}
else if (command.find("PING") == 0)
{

View File

@ -6,12 +6,14 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/17 16:09:20 by fgras-ca #+# #+# */
/* Updated: 2024/05/18 16:41:10 by fgras-ca ### ########.fr */
/* Updated: 2024/05/19 20:52:30 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "ModeWhoHandler.hpp"
#include "Channel.hpp"
#include "RPL.hpp"
#include <sstream>
ModeWhoHandler::ModeWhoHandler(Server *server)
: _server(server)
@ -27,7 +29,7 @@ void ModeWhoHandler::handleModeCommand(Client *client, const std::string &comman
std::map<std::string, Channel *> &channels = _server->getChannels();
if (channels.find(channelName) == channels.end())
{
_server->sendToClient(client->getFd(), ":" SERVER_NAME " 403 " + client->getNickname() + " " + channelName + " :No such channel\r\n");
_server->sendToClient(client->getFd(), ERR_NOSUCHCHANNEL(client->getFd(), channelName));
return;
}
@ -40,17 +42,17 @@ void ModeWhoHandler::handleModeCommand(Client *client, const std::string &comman
if (targetClient)
{
channel->addOperator(targetClient);
_server->sendToClient(client->getFd(), ":" + client->getNickname() + " MODE " + channelName + " +o " + user + "\r\n");
_server->log(GREEN "Client " + user + " is now an operator in channel " + channelName + RESET, GREEN);
_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(), ":" SERVER_NAME " 401 " + client->getNickname() + " " + user + " :No such nick/channel\r\n");
_server->sendToClient(client->getFd(), ERR_NOSUCHNICK(client->getFd(), user));
}
}
else
{
_server->sendToClient(client->getFd(), ":" SERVER_NAME " 482 " + client->getNickname() + " " + channelName + " :You're not channel operator\r\n");
_server->sendToClient(client->getFd(), ERR_CHANOPRIVSNEEDED(client->getFd(), channelName));
}
}
}
@ -58,28 +60,52 @@ void ModeWhoHandler::handleModeCommand(Client *client, const std::string &comman
void ModeWhoHandler::handleWhoCommand(Client *client, const std::string &command)
{
std::istringstream iss(command);
std::string cmd, channelName;
iss >> cmd >> channelName;
std::string cmd, mask;
iss >> cmd >> mask;
std::map<std::string, Channel *> &channels = _server->getChannels();
if (channels.find(channelName) == channels.end())
if (channels.find(mask) != channels.end())
{
_server->sendToClient(client->getFd(), ":" SERVER_NAME " 403 " + client->getNickname() + " " + channelName + " :No such channel\r\n");
Channel *channel = channels[mask];
std::vector<Client *> channelClients = channel->getClients();
for (size_t i = 0; i < channelClients.size(); ++i)
{
_server->sendToClient(client->getFd(), RPL_WHOREPLY(mask, channelClients[i]));
}
}
else
{
Client *targetClient = _server->getClientByName(mask);
if (targetClient)
{
_server->sendToClient(client->getFd(), RPL_WHOREPLY("*", targetClient));
}
}
_server->sendToClient(client->getFd(), RPL_ENDOFWHO(client->getFd(), mask));
}
void ModeWhoHandler::handleWhoisCommand(Client *client, const std::string &command)
{
std::istringstream iss(command);
std::string cmd, target;
iss >> cmd >> target;
if (target.empty())
{
_server->sendToClient(client->getFd(), ERR_NONICKNAMEGIVEN(client->getFd()));
return;
}
Channel *channel = channels[channelName];
std::vector<Client *> channelClients = channel->getClients();
for (size_t i = 0; i < channelClients.size(); ++i)
Client *targetClient = _server->getClientByName(target);
if (!targetClient)
{
std::stringstream whoMsg;
whoMsg << ":" SERVER_NAME " 352 " << client->getNickname() << " " << channelName << " " << channelClients[i]->getNickname() << " "
<< channelClients[i]->getUser() << " " << channelClients[i]->getHost() << " " << _server->getPassword() << " " << channelClients[i]->getRealName() << "\r\n";
_server->sendToClient(client->getFd(), whoMsg.str());
_server->sendToClient(client->getFd(), ERR_NOSUCHNICK(client->getFd(), target));
return;
}
std::stringstream endOfWhoMsg;
endOfWhoMsg << ":" SERVER_NAME " 315 " << client->getNickname() << " " << channelName << " :End of /WHO list.\r\n";
_server->sendToClient(client->getFd(), endOfWhoMsg.str());
_server->sendToClient(client->getFd(), RPL_WHOISUSER(client->getFd(), targetClient));
_server->sendToClient(client->getFd(), RPL_WHOISSERVER(client->getFd(), target, "IRC server info"));
_server->sendToClient(client->getFd(), RPL_ENDOFWHOIS(client->getFd(), target));
}

View File

@ -6,7 +6,7 @@
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/15 12:17:12 by fgras-ca #+# #+# */
/* Updated: 2024/05/19 19:21:54 by fgras-ca ### ########.fr */
/* Updated: 2024/05/19 22:16:03 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
@ -43,6 +43,14 @@ void Server::initServer()
exit(EXIT_FAILURE);
}
int opt = 1;
if (setsockopt(_server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1)
{
log("Failed to set socket options.", RED);
close(_server_fd);
exit(EXIT_FAILURE);
}
struct sockaddr_in server_addr;
std::memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
@ -52,12 +60,14 @@ void Server::initServer()
if (bind(_server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{
log("Failed to bind socket.", RED);
close(_server_fd); // Close the socket if bind fails
exit(EXIT_FAILURE);
}
if (listen(_server_fd, SOMAXCONN) == -1)
{
log("Failed to listen on socket.", RED);
close(_server_fd); // Close the socket if listen fails
exit(EXIT_FAILURE);
}
@ -109,6 +119,7 @@ void Server::run()
}
}
std::map<std::string, Channel *> &Server::getChannels()
{
return _channels;
@ -203,6 +214,26 @@ void Server::sendChannelListToClient(Client *client)
sendToClient(client->getFd(), RPL_LISTEND(client->getFd()));
}
void Server::disconnectClient(int clientFd)
{
close(clientFd);
_clients.erase(clientFd);
for (std::vector<struct pollfd>::iterator it = _poll_fds.begin(); it != _poll_fds.end(); ++it)
{
if (it->fd == clientFd)
{
_poll_fds.erase(it);
break;
}
}
std::ostringstream oss;
oss << "Client disconnected: " << clientFd;
log(oss.str(), YELLOW);
}
/* Explications des Fonctions
Server::Server(int port, const std::string &password)