diff --git a/ft_irc3/.vscode/settings.json b/ft_irc3/.vscode/settings.json index 4649905..08b6cd5 100644 --- a/ft_irc3/.vscode/settings.json +++ b/ft_irc3/.vscode/settings.json @@ -1,65 +1,65 @@ { "files.associations": { - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "*.tcc": "cpp", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "compare": "cpp", - "concepts": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "map": "cpp", - "string": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "random": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "fstream": "cpp", - "initializer_list": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "new": "cpp", - "numbers": "cpp", - "ostream": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "typeinfo": "cpp", - "list": "cpp", - "chrono": "cpp", - "condition_variable": "cpp", - "ctime": "cpp", - "set": "cpp", - "ratio": "cpp", - "mutex": "cpp", - "semaphore": "cpp", - "stop_token": "cpp", - "thread": "cpp", - "cinttypes": "cpp" -}, + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "map": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp", + "list": "cpp", + "chrono": "cpp", + "condition_variable": "cpp", + "ctime": "cpp", + "set": "cpp", + "ratio": "cpp", + "mutex": "cpp", + "semaphore": "cpp", + "stop_token": "cpp", + "thread": "cpp", + "cinttypes": "cpp" + }, "C_Cpp_Runner.cCompilerPath": "gcc", "C_Cpp_Runner.cppCompilerPath": "g++", "C_Cpp_Runner.debuggerPath": "gdb", diff --git a/ft_irc3/includes/AdditionalCommands.hpp b/ft_irc3/includes/AdditionalCommands.hpp index e5ecb10..9786d3d 100644 --- a/ft_irc3/includes/AdditionalCommands.hpp +++ b/ft_irc3/includes/AdditionalCommands.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/16 15:23:58 by fgras-ca #+# #+# */ -/* Updated: 2024/05/16 16:03:22 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 19:18:11 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,16 +17,21 @@ #include "Server.hpp" #include "Channel.hpp" #include "Utils.hpp" - +#include "RPL.hpp" #include #include +#include +// Forward declarations class Server; class Client; class Channel; +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); -#endif +#endif // ADDITIONALCOMMANDS_HPP diff --git a/ft_irc3/includes/Channel.hpp b/ft_irc3/includes/Channel.hpp index 66f689c..40e1514 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/17 20:08:13 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 15:14:50 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,6 +17,7 @@ #include #include #include +#include "RPL.hpp" class Client; diff --git a/ft_irc3/includes/Client.hpp b/ft_irc3/includes/Client.hpp index 0f7a33e..9462e8e 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/17 17:21:39 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 15:38:28 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,13 +18,15 @@ class Client { public: - Client(int fd, const std::string &nickname, const std::string &user); + Client(int fd, const std::string &nickname, const std::string &user, const std::string &host, const std::string &password, const std::string &realname); int getFd() const; const std::string &getNickname() const; void setNickname(const std::string &nickname); const std::string &getUser() const; void setUser(const std::string &user); + const std::string &getHost() const; + void setHost(const std::string &host); const std::string &getPassword() const; void setPassword(const std::string &password); const std::string &getRealName() const; @@ -38,10 +40,11 @@ private: int _fd; std::string _nickname; std::string _user; + std::string _host; std::string _password; std::string _realname; bool _authenticated; bool _operator; }; -#endif +#endif // CLIENT_HPP diff --git a/ft_irc3/includes/ClientManager.hpp b/ft_irc3/includes/ClientManager.hpp index 4e6a1d9..57342ad 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/17 18:51:44 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 18:56:44 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,24 +18,31 @@ #include "Client.hpp" #include "Channel.hpp" #include "Server.hpp" -#include #include "CommandHandler.hpp" +#include "AdditionalCommands.hpp" +#include "RPL.hpp" #include "Utils.hpp" + +#include #include #include #include #include #include #include +#include +#include +#include +#include class Server; +class Client; class ClientManager { public: ClientManager(Server *server); void acceptClient(); - void broadcastChannelList(Client *client); void handleClient(int client_fd); void removeClient(int client_fd); diff --git a/ft_irc3/includes/CommandHandler.hpp b/ft_irc3/includes/CommandHandler.hpp index 1ae423b..303c6e6 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/17 17:10:38 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 19:13:53 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -20,6 +20,7 @@ #include "AdditionalCommands.hpp" #include "ModeWhoHandler.hpp" #include "CommandHandler.hpp" +#include "RPL.hpp" #include #include @@ -27,6 +28,7 @@ class Server; class ModeWhoHandler; +class AdditinalCommands; class CommandHandler { @@ -35,7 +37,16 @@ private: public: CommandHandler(Server *server); + 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 handleCommand(Client *client, const std::string &command); + void handleCapCommand(Client* client, const std::vector& tokens); + void handlePassCommand(Client* client, const std::vector& tokens); + void processCommand(Client *client, const std::string &command); void handleJoinCommand(Client *client, const std::string &channelName); std::string getUsersList(Channel *channel); diff --git a/ft_irc3/includes/ModeWhoHandler.hpp b/ft_irc3/includes/ModeWhoHandler.hpp index 6aa083b..711ccd9 100644 --- a/ft_irc3/includes/ModeWhoHandler.hpp +++ b/ft_irc3/includes/ModeWhoHandler.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/17 16:08:48 by fgras-ca #+# #+# */ -/* Updated: 2024/05/17 18:08:06 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 15:15:39 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,6 +17,10 @@ #include "Client.hpp" #include "Channel.hpp" #include "Utils.hpp" +#include "RPL.hpp" + +#include +#include class Server; diff --git a/ft_irc3/includes/RPL.hpp b/ft_irc3/includes/RPL.hpp new file mode 100644 index 0000000..52990b2 --- /dev/null +++ b/ft_irc3/includes/RPL.hpp @@ -0,0 +1,221 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* RPL.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/19 15:12:47 by fgras-ca #+# #+# */ +/* Updated: 2024/05/19 19:07:25 by fgras-ca ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef RPL_HPP +#define RPL_HPP + +#include +#include +#include "Client.hpp" + +#define SERVER_NAME "IRC_Server" +#define SERVER_VERSION "1.0" +#define USER_MODES "iw" +#define CHANNEL_MODES "nt" +#define CHANNEL_MODES_WITH_PARAMS "kl" + + + +// Macros pour accéder aux champs du client +#define CLIENT_FD(client) (client->getFd()) +#define CLIENT_NICK(client) ((client)->getNickname()) +#define CLIENT_USER(client) ((client)->getUser()) +#define CLIENT_HOST(client) ((client)->getHost()) + +// Fonctions pour générer les réponses RPL +inline std::string RPL_WELCOME(Client* client) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 001 " << CLIENT_FD(client) + << " :Welcome to the Internet Relay Network " << CLIENT_NICK(client) + << "!" << CLIENT_USER(client) << "@" << CLIENT_HOST(client) << "\r\n"; + return oss.str(); +} + +inline std::string RPL_YOURHOST(Client* client) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 002 " << CLIENT_FD(client) + << " :Your host is " << SERVER_NAME << ", running version " << SERVER_VERSION << "\r\n"; + return oss.str(); +} + +inline std::string RPL_CREATED(Client* client) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 003 " << CLIENT_FD(client) + << " :This server was created " << __DATE__ << "\r\n"; + return oss.str(); +} + +inline std::string RPL_MYINFO(Client* client) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 004 " << CLIENT_FD(client) << " " + << SERVER_NAME << " " << SERVER_VERSION << " " + << USER_MODES << " " << CHANNEL_MODES << " " + << CHANNEL_MODES_WITH_PARAMS << "\r\n"; + return oss.str(); +} + +inline std::string RPL_ISUPPORT(Client* client, const std::string& tokens) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 005 " << CLIENT_FD(client) + << " " << tokens << " :are supported by this server\r\n"; + return oss.str(); +} + +inline std::string RPL_MOTDSTART(Client* client) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 375 " << CLIENT_FD(client) + << " :- " << SERVER_NAME << " Message of the day - \r\n"; + return oss.str(); +} + +inline std::string RPL_MOTD(Client* client, const std::string& line) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 372 " << CLIENT_FD(client) + << " :- " << line << "\r\n"; + return oss.str(); +} + +inline std::string RPL_ENDOFMOTD(Client* client) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 376 " << CLIENT_FD(client) + << " :End of /MOTD command.\r\n"; + return oss.str(); +} + +inline std::string ERR_NOMOTD(Client* client) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 422 " << CLIENT_FD(client) + << " :MOTD File is missing\r\n"; + return oss.str(); +} + +// RPL Channel List Messages +inline std::string RPL_LIST(Client* client, const std::string& channel, int numVisible, const std::string& topic) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 322 " << CLIENT_FD(client) << " " << channel + << " " << numVisible << " :" << topic << "\r\n"; + return oss.str(); +} + +inline std::string RPL_LISTEND(Client* client) { + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 323 " << CLIENT_FD(client) + << " :End of /LIST\r\n"; + return oss.str(); +} + +//RPL Password +// RPL Error Messages +inline std::string ERR_NEEDMOREPARAMS(Client* client, const std::string& command) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 461 " << CLIENT_FD(client) << " " << command << " :Not enough parameters\r\n"; + return oss.str(); +} + +inline std::string ERR_ALREADYREGISTERED(Client* client) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 462 " << CLIENT_FD(client) << " :You may not reregister\r\n"; + return oss.str(); +} + +inline std::string ERR_PASSWDMISMATCH(Client* client) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 464 " << CLIENT_FD(client) << " :Password incorrect\r\n"; + return oss.str(); +} + +inline std::string ERR_NOTREGISTERED(Client* client) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 451 " << CLIENT_FD(client) << " :You have not registered\r\n"; + return oss.str(); +} + +inline std::string ERR_NONICKNAMEGIVEN(Client* client) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 431 " << CLIENT_FD(client) << " :No nickname given\r\n"; + return oss.str(); +} + +inline std::string ERR_ERRONEUSNICKNAME(Client* client, const std::string& nickname) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 432 " << CLIENT_FD(client) << " " << nickname << " :Erroneous nickname\r\n"; + return oss.str(); +} + +inline std::string ERR_NICKNAMEINUSE(Client* client, const std::string& nickname) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 433 " << CLIENT_FD(client) << " " << nickname << " :Nickname is already in use\r\n"; + return oss.str(); +} + +// RPL Error Messages +inline std::string ERR_NOORIGIN(Client* client) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 409 " << CLIENT_FD(client) << " :No origin specified\r\n"; + return oss.str(); +} + +// PONG Reply +inline std::string RPL_PONG(const std::string& token) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " PONG " << SERVER_NAME << " " << token << "\r\n"; + return oss.str(); +} + +// ERR_UNKNOWNCOMMAND (421) +inline std::string ERR_UNKNOWNCOMMAND(Client* client, const std::string& command) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 421 " << CLIENT_FD(client) << " " << command << " :Unknown command\r\n"; + return oss.str(); +} + +// RPL Channel List Messages +inline std::string RPL_LIST(int clientFd, const std::string& channel, int numVisible, const std::string& topic) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 322 " << clientFd << " " << channel << " " << numVisible << " :" << topic << "\r\n"; + return oss.str(); +} + +inline std::string RPL_LISTEND(int clientFd) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 323 " << clientFd << " :End of /LIST\r\n"; + return oss.str(); +} + +inline std::string ERR_NEEDMOREPARAMS(int clientFd, const std::string& command) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 461 " << clientFd << " " << command << " :Not enough parameters\r\n"; + return oss.str(); +} + +inline std::string ERR_UNKNOWNCOMMAND(int clientFd, const std::string& command) +{ + std::ostringstream oss; + oss << ":" << SERVER_NAME << " 421 " << clientFd << " " << command << " :Unknown command\r\n"; + return oss.str(); +} + + +#endif // RPL_HPP diff --git a/ft_irc3/includes/Server.hpp b/ft_irc3/includes/Server.hpp index 3dd93e3..0d071dc 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/17 20:03:06 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 16:30:56 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -19,6 +19,7 @@ #include "ClientManager.hpp" #include "CommandHandler.hpp" #include "AdditionalCommands.hpp" +#include "RPL.hpp" #include #include diff --git a/ft_irc3/ircserv b/ft_irc3/ircserv new file mode 100755 index 0000000..7508ad6 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 new file mode 100644 index 0000000..d3fed42 Binary files /dev/null and b/ft_irc3/obj/AdditionalCommands.o differ diff --git a/ft_irc3/obj/Channel.o b/ft_irc3/obj/Channel.o new file mode 100644 index 0000000..a5a03f3 Binary files /dev/null and b/ft_irc3/obj/Channel.o differ diff --git a/ft_irc3/obj/Client.o b/ft_irc3/obj/Client.o new file mode 100644 index 0000000..ce15eca Binary files /dev/null and b/ft_irc3/obj/Client.o differ diff --git a/ft_irc3/obj/ClientManager.o b/ft_irc3/obj/ClientManager.o new file mode 100644 index 0000000..d4b69bf Binary files /dev/null and b/ft_irc3/obj/ClientManager.o differ diff --git a/ft_irc3/obj/CommandHandler.o b/ft_irc3/obj/CommandHandler.o new file mode 100644 index 0000000..3a5713e Binary files /dev/null and b/ft_irc3/obj/CommandHandler.o differ diff --git a/ft_irc3/obj/ModeWhoHandler.o b/ft_irc3/obj/ModeWhoHandler.o new file mode 100644 index 0000000..30531d0 Binary files /dev/null and b/ft_irc3/obj/ModeWhoHandler.o differ diff --git a/ft_irc3/obj/Server.o b/ft_irc3/obj/Server.o new file mode 100644 index 0000000..b0c9ebd 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/main.o b/ft_irc3/obj/main.o new file mode 100644 index 0000000..3beabb4 Binary files /dev/null and b/ft_irc3/obj/main.o differ diff --git a/ft_irc3/src/AdditionalCommands.cpp b/ft_irc3/src/AdditionalCommands.cpp index ddec897..3655143 100644 --- a/ft_irc3/src/AdditionalCommands.cpp +++ b/ft_irc3/src/AdditionalCommands.cpp @@ -6,12 +6,47 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/16 15:27:29 by fgras-ca #+# #+# */ -/* Updated: 2024/05/17 20:15:14 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 19:22:28 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")); + + sendMotd(client, server); +} + +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) +{ + std::map &channels = server->getChannels(); + for (std::map::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_LISTEND(client->getFd())); +} + // Fonction pour gérer la commande PART void handlePartCommand(Server *server, Client *client, const std::string &command) { diff --git a/ft_irc3/src/Client.cpp b/ft_irc3/src/Client.cpp index caaa524..8216760 100644 --- a/ft_irc3/src/Client.cpp +++ b/ft_irc3/src/Client.cpp @@ -6,17 +6,16 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 12:17:42 by fgras-ca #+# #+# */ -/* Updated: 2024/05/17 17:20:02 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 15:38:46 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ #include "Client.hpp" -Client::Client(int fd, const std::string &nickname, const std::string &user) - : _fd(fd), _nickname(nickname), _user(user), _authenticated(false), _operator(false) +Client::Client(int fd, const std::string &nickname, const std::string &user, const std::string &host, const std::string &password, const std::string &realname) + : _fd(fd), _nickname(nickname), _user(user), _host(host), _password(password), _realname(realname), _authenticated(false), _operator(false) { } - int Client::getFd() const { return _fd; @@ -42,6 +41,16 @@ void Client::setUser(const std::string &user) _user = user; } +const std::string &Client::getHost() const +{ + return _host; +} + +void Client::setHost(const std::string &host) +{ + _host = host; +} + const std::string &Client::getPassword() const { return _password; @@ -86,6 +95,8 @@ void Client::setOperator(bool isOperator) + + /*Client::Client(int fd) Description: Constructeur de la classe Client. Initialise le client avec le descripteur de fichier fourni. diff --git a/ft_irc3/src/ClientManager.cpp b/ft_irc3/src/ClientManager.cpp index 9f39981..426e767 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/17 18:53:09 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 18:55:55 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -26,7 +26,8 @@ void ClientManager::acceptClient() return; } - _server->_clients[client_fd] = new Client(client_fd, "", ""); // Initialize with default values + Client *newClient = new Client(client_fd, "", "", "", "", ""); // Fournir six arguments + _server->_clients[client_fd] = newClient; struct pollfd client_pollfd; client_pollfd.fd = client_fd; client_pollfd.events = POLLIN; @@ -35,16 +36,8 @@ void ClientManager::acceptClient() std::stringstream ss; ss << "Client connected: " << client_fd; _server->log(ss.str(), GREEN); -} -void ClientManager::broadcastChannelList(Client *client) { - std::map &channels = _server->getChannels(); - for (std::map::iterator it = channels.begin(); it != channels.end(); ++it) { - std::stringstream channelMsg; - channelMsg << ":server 322 " << client->getNickname() << " " << it->first << " :Existing channel\r\n"; - _server->sendToClient(client->getFd(), channelMsg.str()); - } - _server->sendToClient(client->getFd(), ":server 323 " + client->getNickname() + " :End of /LIST\r\n"); + sendWelcomeMessages(newClient, _server); } void ClientManager::handleClient(int client_fd) @@ -69,12 +62,10 @@ void ClientManager::handleClient(int client_fd) while (std::getline(message_stream, line)) { - // Suppression des caractères de fin de ligne 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); - broadcastChannelList(_server->_clients[client_fd]); } } @@ -83,7 +74,6 @@ void ClientManager::removeClient(int client_fd) Client *client = _server->_clients[client_fd]; if (client) { - // Retirer le client de tous les canaux auxquels il appartient std::map::iterator it = _server->_channels.begin(); while (it != _server->_channels.end()) { diff --git a/ft_irc3/src/CommandHandler.cpp b/ft_irc3/src/CommandHandler.cpp index 36d3a07..480b1b8 100644 --- a/ft_irc3/src/CommandHandler.cpp +++ b/ft_irc3/src/CommandHandler.cpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/15 18:26:34 by fgras-ca #+# #+# */ -/* Updated: 2024/05/17 20:05:16 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 19:13:14 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,77 +17,191 @@ CommandHandler::CommandHandler(Server *server) { } -void CommandHandler::handleCommand(Client *client, const std::string &command) +void CommandHandler::handleCommand(Client* client, const std::string& command) { std::vector tokens = split(command, " \n\r\t"); - if (tokens.empty()) - { + if (tokens.empty()) { return; } std::string commandType = tokens[0]; - if (commandType == "CAP") - {} - else if (commandType == "PASS") - { - if (tokens.size() > 1 && tokens[1] == _server->_password) - { - client->setPassword(tokens[1]); - _server->sendToClient(client->getFd(), ":server 001 " + client->getNickname() + " :Password accepted!\r\n"); - _server->log("Client " + client->getNickname() + " provided correct password.", GREEN); - _server->sendChannelListToClient(client); - } - else - { - _server->sendToClient(client->getFd(), ":server 464 " + client->getNickname() + " :Invalid password\r\n"); - _server->log("Client " + client->getNickname() + " failed authentication password.", RED); - } - } - else if (commandType == "NICK") - { - if (tokens.size() > 1) - { - client->setNickname(tokens[1]); - std::stringstream ss; - ss << "Client " << client->getFd() << " Nickname: " << tokens[1]; - _server->log(ss.str(), GREEN); - _server->sendToClient(client->getFd(), ":" + tokens[1] + " NICK " + tokens[1] + "\r\n"); - } - } - else if (commandType == "USER") - { - if (tokens.size() > 4) - { - client->setUser(tokens[1]); - client->setRealName(tokens[4].substr(1)); // remove leading ':' - if (client->getPassword() == _server->_password && !client->getNickname().empty()) - { - client->authenticate(); - std::stringstream welcomeMsg; - welcomeMsg << ":server 001 " << client->getNickname() << " :Welcome to the IRC server!\r\n"; - _server->sendToClient(client->getFd(), welcomeMsg.str()); - - _server->log("Client " + client->getNickname() + " authenticated.", GREEN); - _server->sendChannelListToClient(client); - } - } - } - else - { - if (!client->isAuthenticated()) - { - _server->sendToClient(client->getFd(), ":server 451 " + client->getNickname() + " :Please provide the password first\r\n"); - _server->log("Client " + client->getNickname() + " failed authentication.", RED); - } - else - { + if (commandType == "CAP") { + handleCapCommand(client, tokens); + } else if (commandType == "PASS") { + handlePassCommand(client, tokens); + } else if (commandType == "NICK") { + handleNick(client, tokens); + } else if (commandType == "USER") { + handleUser(client, tokens); + } 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); } } std::cout << "Client " << client->getFd() << " " << client->getNickname() << " " << client->getUser() << " " << client->getPassword() << " " << client->getRealName() << std::endl; } +void CommandHandler::handleCapCommand(Client* client, const std::vector& tokens) +{ + if (tokens.size() < 2) + { + _server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client->getFd(), "CAP")); + return; + } + + std::string subcommand = tokens[1]; + + if (subcommand == "LS") + { + // Example for CAP LS response + std::vector 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()); + } + } + 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()); + } + else if (subcommand == "REQ") + { + if (tokens.size() < 3) + { + _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()); + } + else if (subcommand == "END") + { + // Example for CAP END response + _server->sendToClient(client->getFd(), ":irc.example.com CAP " + client->getNickname() + " END\r\n"); + } + else + { + // Unknown CAP subcommand + _server->sendToClient(client->getFd(), ERR_UNKNOWNCOMMAND(client->getFd(), "CAP")); + } +} + +void CommandHandler::handlePassCommand(Client* client, const std::vector& tokens) +{ + if (tokens.size() < 2) { + _server->sendToClient(client->getFd(), ERR_NEEDMOREPARAMS(client, "PASS")); + return; + } + + if (client->isAuthenticated()) { + _server->sendToClient(client->getFd(), ERR_ALREADYREGISTERED(client)); + return; + } + + if (tokens[1] == _server->_password) { + client->setPassword(tokens[1]); + _server->sendToClient(client->getFd(), ":server NOTICE * :Password accepted\r\n"); + _server->log("Client " + client->getNickname() + " provided correct password.", GREEN); + } else { + _server->sendToClient(client->getFd(), ERR_PASSWDMISMATCH(client)); + _server->log("Client " + client->getNickname() + " failed authentication password.", RED); + // Optionally disconnect the client here + } +} + +bool CommandHandler::isValidNickname(const std::string& nickname) +{ + // Implement nickname validation according to IRC protocol + if (nickname.empty() || nickname[0] == '#' || nickname[0] == ':' || nickname.find(' ') != std::string::npos) { + return false; + } + return true; +} + +bool CommandHandler::isNicknameInUse(const std::string& nickname) +{ + for (std::map::iterator it = _server->_clients.begin(); it != _server->_clients.end(); ++it) { + if (it->second->getNickname() == nickname) { + return true; + } + } + return false; +} + +void CommandHandler::handleNick(Client* client, const std::vector& tokens) +{ + if (tokens.size() < 2) { + _server->sendToClient(client->getFd(), ERR_NONICKNAMEGIVEN(client)); + return; + } + + std::string newNick = tokens[1]; + + if (!isValidNickname(newNick)) { + _server->sendToClient(client->getFd(), ERR_ERRONEUSNICKNAME(client, newNick)); + return; + } + + if (isNicknameInUse(newNick)) { + _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); +} + +void CommandHandler::handleUser(Client* client, const std::vector& 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; + } + + client->setUser(tokens[1]); + client->setRealName(tokens[4].substr(1)); // remove leading ':' + + if (client->getPassword() == _server->_password && !client->getNickname().empty()) { + client->authenticate(); + sendWelcomeMessages(client, _server); + _server->log("Client " + client->getNickname() + " authenticated.", GREEN); + } +} + void CommandHandler::processCommand(Client *client, const std::string &command) { if (command.find("JOIN") == 0) @@ -116,12 +230,19 @@ void CommandHandler::processCommand(Client *client, const std::string &command) { ModeWhoHandler whoHandler(_server); whoHandler.handleWhoCommand(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 { - std::stringstream ss; - ss << ":server 421 " << client->getNickname() << " " << command << " :Unknown command\r\n"; - _server->sendToClient(client->getFd(), ss.str()); + _server->sendToClient(client->getFd(), ERR_UNKNOWNCOMMAND(client, command)); _server->log("Message from client " + client->getNickname() + ": " + command, MAGENTA); } } @@ -155,9 +276,6 @@ void CommandHandler::handleJoinCommand(Client *client, const std::string &channe _server->log(ss.str(), MAGENTA); } - - - std::string CommandHandler::getUsersList(Channel *channel) { std::vector clients = channel->getClients(); @@ -172,3 +290,14 @@ std::string CommandHandler::getUsersList(Channel *channel) 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")); + return; + } + + std::string token = tokens[1]; + _server->sendToClient(client->getFd(), RPL_PONG(token)); +} diff --git a/ft_irc3/src/ModeWhoHandler.cpp b/ft_irc3/src/ModeWhoHandler.cpp index cbc98a2..ef39134 100644 --- a/ft_irc3/src/ModeWhoHandler.cpp +++ b/ft_irc3/src/ModeWhoHandler.cpp @@ -6,22 +6,12 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/17 16:09:20 by fgras-ca #+# #+# */ -/* Updated: 2024/05/17 18:24:34 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/18 16:41:10 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ #include "ModeWhoHandler.hpp" #include "Channel.hpp" -#include -#include - -// Couleurs ANSI pour les logs -#define RESET "\033[0m" -#define GREEN "\033[32m" -#define YELLOW "\033[33m" -#define RED "\033[31m" -#define BLUE "\033[34m" -#define MAGENTA "\033[35m" ModeWhoHandler::ModeWhoHandler(Server *server) : _server(server) @@ -37,7 +27,7 @@ void ModeWhoHandler::handleModeCommand(Client *client, const std::string &comman std::map &channels = _server->getChannels(); if (channels.find(channelName) == channels.end()) { - _server->sendToClient(client->getFd(), ":server 403 " + client->getNickname() + " " + channelName + " :No such channel\r\n"); + _server->sendToClient(client->getFd(), ":" SERVER_NAME " 403 " + client->getNickname() + " " + channelName + " :No such channel\r\n"); return; } @@ -55,12 +45,12 @@ void ModeWhoHandler::handleModeCommand(Client *client, const std::string &comman } else { - _server->sendToClient(client->getFd(), ":server 401 " + client->getNickname() + " " + user + " :No such nick/channel\r\n"); + _server->sendToClient(client->getFd(), ":" SERVER_NAME " 401 " + client->getNickname() + " " + user + " :No such nick/channel\r\n"); } } else { - _server->sendToClient(client->getFd(), ":server 482 " + client->getNickname() + " " + channelName + " :You're not channel operator\r\n"); + _server->sendToClient(client->getFd(), ":" SERVER_NAME " 482 " + client->getNickname() + " " + channelName + " :You're not channel operator\r\n"); } } } @@ -74,7 +64,7 @@ void ModeWhoHandler::handleWhoCommand(Client *client, const std::string &command std::map &channels = _server->getChannels(); if (channels.find(channelName) == channels.end()) { - _server->sendToClient(client->getFd(), ":server 403 " + client->getNickname() + " " + channelName + " :No such channel\r\n"); + _server->sendToClient(client->getFd(), ":" SERVER_NAME " 403 " + client->getNickname() + " " + channelName + " :No such channel\r\n"); return; } @@ -84,12 +74,12 @@ void ModeWhoHandler::handleWhoCommand(Client *client, const std::string &command for (size_t i = 0; i < channelClients.size(); ++i) { std::stringstream whoMsg; - whoMsg << ":server 352 " << client->getNickname() << " " << channelName << " " << channelClients[i]->getNickname() << " " - << channelClients[i]->getUser() << " " << _server->getPassword() << " " << channelClients[i]->getRealName() << "\r\n"; + 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()); } std::stringstream endOfWhoMsg; - endOfWhoMsg << ":server 315 " << client->getNickname() << " " << channelName << " :End of /WHO list.\r\n"; + endOfWhoMsg << ":" SERVER_NAME " 315 " << client->getNickname() << " " << channelName << " :End of /WHO list.\r\n"; _server->sendToClient(client->getFd(), endOfWhoMsg.str()); -} +} \ No newline at end of file diff --git a/ft_irc3/src/Server.cpp b/ft_irc3/src/Server.cpp index 9f7d52e..d41bd4e 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/17 20:03:44 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/19 19:21:54 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -72,6 +72,13 @@ void Server::run() server_pollfd.revents = 0; _poll_fds.push_back(server_pollfd); + // Ajout de l'entrée pour les commandes serveur + struct pollfd stdin_pollfd; + stdin_pollfd.fd = STDIN_FILENO; + stdin_pollfd.events = POLLIN; + stdin_pollfd.revents = 0; + _poll_fds.push_back(stdin_pollfd); + while (true) { int poll_count = poll(&_poll_fds[0], _poll_fds.size(), -1); @@ -89,57 +96,59 @@ void Server::run() { _clientManager->acceptClient(); } + else if (_poll_fds[i].fd == STDIN_FILENO) + { + handleServerCommands(); + } else { _clientManager->handleClient(_poll_fds[i].fd); } } } - - handleServerCommands(); } } +std::map &Server::getChannels() +{ + return _channels; +} + +const std::string &Server::getPassword() const +{ + return _password; +} + void Server::handleServerCommands() { - fd_set readfds; - FD_ZERO(&readfds); - FD_SET(STDIN_FILENO, &readfds); - struct timeval tv = {0, 0}; // non-blocking + std::string command; + std::getline(std::cin, command); - int activity = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv); - - if (activity > 0 && FD_ISSET(STDIN_FILENO, &readfds)) + if (command == "quit") { - std::string command; - std::getline(std::cin, command); - - if (command == "quit") + log("Server shutting down.", YELLOW); + exit(EXIT_SUCCESS); + } + else if (command == "channels") + { + log("Listing all channels:", BLUE); + for (std::map::iterator it = _channels.begin(); it != _channels.end(); ++it) { - log("Server shutting down.", YELLOW); - exit(EXIT_SUCCESS); + log(it->first, BLUE); } - else if (command == "channels") + } + else if (command == "clients") + { + log("Listing all clients:", BLUE); + for (std::map::iterator it = _clients.begin(); it != _clients.end(); ++it) { - log("Listing all channels:", BLUE); - for (std::map::iterator it = _channels.begin(); it != _channels.end(); ++it) - { - log(it->first, BLUE); - } - } - else if (command == "clients") - { - log("Listing all clients:", BLUE); - for (std::map::iterator it = _clients.begin(); it != _clients.end(); ++it) - { - log(it->second->getNickname(), BLUE); - } - } - else - { - log("Unknown server command.", RED); + log(it->second->getNickname(), BLUE); } } + else + { + log("Unknown server command.", RED); + } } void Server::log(const std::string &message, const std::string &color) @@ -147,7 +156,6 @@ void Server::log(const std::string &message, const std::string &color) std::cout << color << message << "\033[0m" << std::endl; } - void Server::sendToClient(int client_fd, const std::string &message) { int result = send(client_fd, message.c_str(), message.length(), 0); @@ -165,11 +173,6 @@ void Server::sendToClient(int client_fd, const std::string &message) } } -const std::string &Server::getPassword() const -{ - return _password; -} - void Server::broadcast(const std::string &message) { for (std::map::iterator it = _clients.begin(); it != _clients.end(); ++it) @@ -178,16 +181,6 @@ void Server::broadcast(const std::string &message) } } -std::map &Server::getChannels() -{ - return _channels; -} - -std::map &Server::getClients() -{ - return _clients; -} - Client* Server::getClientByName(const std::string &name) { for (std::map::iterator it = _clients.begin(); it != _clients.end(); ++it) @@ -205,17 +198,11 @@ void Server::sendChannelListToClient(Client *client) std::map &channels = getChannels(); for (std::map::iterator it = channels.begin(); it != channels.end(); ++it) { - std::stringstream channelMsg; - channelMsg << ":server 322 " << client->getNickname() << " " << it->first << " :" << it->second->getClients().size() << "\r\n"; - sendToClient(client->getFd(), channelMsg.str()); + sendToClient(client->getFd(), RPL_LIST(client->getFd(), it->first, it->second->getClients().size(), "Existing channel")); } - std::stringstream endOfListMsg; - endOfListMsg << ":server 323 " << client->getNickname() << " :End of /LIST\r\n"; - sendToClient(client->getFd(), endOfListMsg.str()); + sendToClient(client->getFd(), RPL_LISTEND(client->getFd())); } - - /* Explications des Fonctions Server::Server(int port, const std::string &password)