diff --git a/Makefile b/Makefile index adde70c..7c8ef78 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ # By: omoudni +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2025/05/02 15:40:00 by rparodi #+# #+# # -# Updated: 2025/05/24 16:48:43 by rparodi ### ########.fr # +# Updated: 2025/05/26 18:22:38 by rparodi ### ########.fr # # # #******************************************************************************# @@ -24,17 +24,19 @@ CXXFLAGS = -Werror -Wextra -Wall -std=c++98 SESSION = test-irc # Sources -SRC = sources/core/logs.cpp \ - sources/core/check.cpp \ +SRC = sources/channel/channel.cpp \ sources/core/PollManager.cpp \ - sources/core/parser.cpp \ - sources/core/main.cpp \ sources/core/Server.cpp \ + sources/core/check.cpp \ + sources/core/main.cpp \ + sources/core/parser.cpp \ sources/user/user.cpp \ - sources/channel/channel.cpp + sources/commands/commands.cpp \ + sources/commands/invite.cpp -INC_DIR = include/core \ - include +INC_DIR = include/core \ + include/commands \ + include CPPFLAGS = $(addprefix -I, $(INC_DIR)) -MMD -MP @@ -72,7 +74,7 @@ re: header fclean all $(NAME): $(OBJ) @mkdir -p $(OBJDIRNAME) @printf '$(GREY) Creating $(END)$(GREEN)$(OBJDIRNAME)$(END)\n' - @$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $(NAME) $(OBJ) + @$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $(NAME) $(OBJ) -fuse-ld=lld # Creating the objects $(OBJDIRNAME)/%.o: %.cpp diff --git a/flake.nix b/flake.nix index bacb72c..b27d8ca 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,7 @@ clang-tools irssi tmux + lld ] ++ ( if pkgs.stdenv.isLinux then [ valgrind diff --git a/include/channel.hpp b/include/channel.hpp index 0d7cb2f..a2ace76 100644 --- a/include/channel.hpp +++ b/include/channel.hpp @@ -6,7 +6,7 @@ /* By: rparodi +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/20 22:18:17 by rparodi #+# #+# */ -/* Updated: 2025/05/20 22:53:57 by rparodi ### ########.fr */ +/* Updated: 2025/05/26 22:54:58 by rparodi ### ########.fr */ /* */ /* ************************************************************************** */ @@ -24,6 +24,7 @@ class Channel { User *_owner; std::list _operators; std::list _users; + std::list _invited; public: // getters std::string getName() const; @@ -31,6 +32,7 @@ class Channel { User *getOwner() const; std::list getOperators() const; std::list getUsers() const; + std::list getInvited() const; bool isOperator(User *user) const; bool isUserInChannel(User *user) const; diff --git a/include/commands.hpp b/include/commands.hpp index 486fa83..a5c8965 100644 --- a/include/commands.hpp +++ b/include/commands.hpp @@ -6,7 +6,7 @@ /* By: rparodi +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/20 23:31:58 by rparodi #+# #+# */ -/* Updated: 2025/05/20 23:49:46 by rparodi ### ########.fr */ +/* Updated: 2025/05/26 18:25:49 by rparodi ### ########.fr */ /* */ /* ************************************************************************** */ @@ -16,28 +16,32 @@ #include #include "user.hpp" #include "channel.hpp" +#include "server.hpp" +#include "logs.hpp" namespace cmd { - /** - * @brief To send the line where a command is invoqued to execute - * - * @param user user who send the command - * @param channel channel where the command is sent - * @param line line send by the user - */ - void dispatch(User *user, Channel *channel, const std::string &line); + void dispatch(User *user, Channel *channel, Server *server, const std::string &line); std::vector split(const std::string &line); + template + T searchList(const std::list &list, const std::string &name); - class ICommand { - private: + class ACommand { + protected: + User* _sender; + User* _uTarget; + Channel *_channel; + Channel *_cTarget; + Server *_server; + std::list _channels; + std::list _users; std::string _command; std::vector _args; - User _user; public: virtual void execute() = 0; - ~ICommand(); - ICommand(User *user, Channel *channel, const std::string &line); + virtual bool checkArgs() = 0; + ~ACommand(); + ACommand(User *user, Channel *channel, Server *server, const std::string &line); }; class Invite; @@ -56,5 +60,7 @@ namespace cmd class Quit; class Topic; class Unknown; - class User; + class cmdUser; }; + +#include "./commands/commands.tpp" diff --git a/include/commands/commands.tpp b/include/commands/commands.tpp new file mode 100644 index 0000000..94dc22e --- /dev/null +++ b/include/commands/commands.tpp @@ -0,0 +1,30 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* commands.tpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: rparodi +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/24 17:34:30 by rparodi #+# #+# */ +/* Updated: 2025/05/26 18:20:34 by rparodi ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "commands.hpp" + +/** + * @brief Return the element searched in a list + * + * @tparam T Type of the list have to be search (have to get an getName() method) + * @param list list to search in + * @param name name of the element to search + * @return pointer to the element found or NULL if not found + */ +template +T cmd::searchList(const std::list &list, const std::string &name) { + for (typename std::list::const_iterator it = list.begin(); it != list.end(); ++it) { + if ((*it)->getName() == name) + return *it; + } + return NULL; +} diff --git a/include/commands/invite.hpp b/include/commands/invite.hpp new file mode 100644 index 0000000..11973ed --- /dev/null +++ b/include/commands/invite.hpp @@ -0,0 +1,21 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* invite.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: rparodi +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/24 17:17:31 by rparodi #+# #+# */ +/* Updated: 2025/05/26 16:27:42 by rparodi ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#pragma once + +#include "commands.hpp" + +class cmd::Invite : public ACommand { + public: + virtual void execute(void); + virtual bool checkArgs(); +}; diff --git a/include/commands/join.hpp b/include/commands/join.hpp new file mode 100644 index 0000000..135d235 --- /dev/null +++ b/include/commands/join.hpp @@ -0,0 +1,21 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* join.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: rparodi +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/24 17:17:31 by rparodi #+# #+# */ +/* Updated: 2025/05/26 22:43:47 by rparodi ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#pragma once + +#include "commands.hpp" + +class cmd::Join : public ACommand { + public: + virtual void execute(void); + virtual bool checkArgs(); +}; diff --git a/include/core/logs.hpp b/include/core/logs.hpp index d7efc90..ed02e7d 100644 --- a/include/core/logs.hpp +++ b/include/core/logs.hpp @@ -6,7 +6,7 @@ /* By: rparodi +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/15 12:25:58 by rparodi #+# #+# */ -/* Updated: 2025/05/15 12:38:10 by rparodi ### ########.fr */ +/* Updated: 2025/05/26 18:08:50 by rparodi ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,20 +15,14 @@ #include #include "color.hpp" -#define DEBUG_MSG(str) "print_debug(str, __FILE__, __LINE__)" -#define ERROR_MSG(str) "print_error(str, __FILE__, __LINE__)" -#define WARNING_MSG(str) "print_warning(str, __FILE__, __LINE__)" -#define INFO_MSG(str) "print_info(str, __FILE__, __LINE__)" -#define SUCCESS_MSG(str) "print_success(str, __FILE__, __LINE__)" +#define DEBUG_MSG(str) std::cerr << CLR_CYAN << "\tDebug: " << str << "(" << __FILE__ << ":" << __LINE__ << ")" << CLR_RESET << std::endl; +#define ERROR_MSG(str) std::cerr << CLR_RED << "\tError: " << str << "(" << __FILE__ << ":" << __LINE__ << ")" << CLR_RESET << std::endl; +#define WARNING_MSG(str) std::cerr << CLR_YELLOW << "\tWarning: " << str << "(" << __FILE__ << ":" << __LINE__ << ")" << CLR_RESET << std::endl; +#define INFO_MSG(str) std::cerr << CLR_GREY << "\tInfo: " << str << "(" << __FILE__ << ":" << __LINE__ << ")" << CLR_RESET << std::endl; +#define SUCCESS_MSG(str) std::cerr << CLR_GREEN << "\tSuccess: " << str << "(" << __FILE__ << ":" << __LINE__ << ")" << CLR_RESET << std::endl; #ifndef DEBUG #define DEBUG 0 #define LOG "" #endif - -void print_debug(const char *str, const char *file, int line); -void print_error(const char *str, const char *file, int line); -void print_warning(const char *str, const char *file, int line); -void print_info(const char *str, const char *file, int line); -void print_success(const char *str, const char *file, int line); diff --git a/include/server.hpp b/include/server.hpp index 05de211..9424bcb 100644 --- a/include/server.hpp +++ b/include/server.hpp @@ -6,7 +6,7 @@ /* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/20 21:50:32 by rparodi #+# #+# */ -/* Updated: 2025/05/25 12:57:29 by rparodi ### ########.fr */ +/* Updated: 2025/05/26 22:26:04 by rparodi ### ########.fr */ /* */ /******************************************************************************/ @@ -16,6 +16,7 @@ #include "core.hpp" #include "channel.hpp" #include "user.hpp" +#include "logs.hpp" class User; class Channel; @@ -27,13 +28,14 @@ private: std::string _password; PollManager _pollManager; std::map _users; + std::list _channels; public: Server(int port, const std::string &password); ~Server(); void start(); unsigned short int getPort() const; - std::list getUsersList() const; + std::list getUsersList() const; std::list getChannelsList() const; void showInfo() const; void printUsers() const; diff --git a/include/user.hpp b/include/user.hpp index 866ca37..a1188ce 100644 --- a/include/user.hpp +++ b/include/user.hpp @@ -6,37 +6,37 @@ /* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/20 21:57:49 by rparodi #+# #+# */ -/* Updated: 2025/05/21 21:16:56 by omoudni ### ########.fr */ +/* Updated: 2025/05/26 18:10:24 by rparodi ### ########.fr */ /* */ /******************************************************************************/ #pragma once -#include "core.hpp" +#include class User { -private: - short unsigned int _fd; - bool _registered; - std::string _nickname; - std::string _hostname; - std::string _read_buffer; - std::string _write_buffer; - std::string _username; - bool _hasNick; - bool _hasUser; - -public: - User(short unsigned fd); - short unsigned int getFd() const; - bool isReadyToSend() const; - bool isRegistered() const; - std::string getName() const; - std::string extractFullCommand(); - void appendToReadBuffer(const std::string &data); - void appendToWriteBuffer(const std::string &data); - void setNickname(const std::string &nickname); - void setUsername(const std::string &username); - void checkRegistration(); + private: + short unsigned int _fd; + bool _registered; + std::string _nickname; + std::string _hostname; + std::string _read_buffer; + std::string _write_buffer; + std::string _username; + bool _hasNick; + bool _hasUser; + + public: + User(short unsigned fd); + short unsigned int getFd() const; + bool isReadyToSend() const; + bool isRegistered() const; + std::string getName() const; + std::string extractFullCommand(); + void appendToReadBuffer(const std::string &data); + void appendToWriteBuffer(const std::string &data); + void setNickname(const std::string &nickname); + void setUsername(const std::string &username); + void checkRegistration(); }; diff --git a/sources/channel/channel.cpp b/sources/channel/channel.cpp index da8d51c..b1b38ac 100644 --- a/sources/channel/channel.cpp +++ b/sources/channel/channel.cpp @@ -6,11 +6,12 @@ /* By: rparodi +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/20 22:43:24 by rparodi #+# #+# */ -/* Updated: 2025/05/20 22:55:20 by rparodi ### ########.fr */ +/* Updated: 2025/05/26 22:55:45 by rparodi ### ########.fr */ /* */ /* ************************************************************************** */ #include "channel.hpp" +#include /** * @brief Get the name of the channel @@ -57,6 +58,15 @@ std::list Channel::getOperators() const { return this->_operators; } +/** + * @brief Get the list of the Invited in the channel + * + * @return list of Invited in the channel + */ +std::list Channel::getInvited() const { + return this->_invited; +} + /** * @brief Check if the user is an operator * diff --git a/sources/commands/commands.cpp b/sources/commands/commands.cpp new file mode 100644 index 0000000..0798e62 --- /dev/null +++ b/sources/commands/commands.cpp @@ -0,0 +1,119 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* commands.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: rparodi +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/24 16:11:56 by rparodi #+# #+# */ +/* Updated: 2025/05/26 18:25:18 by rparodi ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "commands.hpp" +#include "logs.hpp" + +/** + * @brief To send the line where a command is invoqued to execute + * + * @param user user who send the command + * @param channel channel where the command is sent + * @param line line send by the user + */ +std::vector cmd::split(const std::string &line) { + std::vector args; + std::string arg; + size_t pos = line.find(' '); + while (pos != std::string::npos) { + arg = line.substr(0, pos); + if (!arg.empty()) { + args.push_back(arg); + } + pos = line.find(' '); + } + if (!line.empty()) { + args.push_back(line); + } + return args; +} + +/** + * @brief recieve the input of the user and execute the command asked + * + * @param user User how send the command + * @param channel Channel where the command is sent + * @param server Server where the command is sent + * @param line input line from the user + */ +void cmd::dispatch(::User *user, Channel *channel, Server *server, const std::string &line) { + std::string command_name = cmd::split(line).at(0); + if (command_name.empty()) { + WARNING_MSG("No command found in line: " << line); + return; + } + if (command_name[0] == '/') { + command_name.erase(0, 1); + } else { + WARNING_MSG("Command does not start with '/': " << command_name); + return; + } + switch (command_name[0]) { + case 'i': + // if (command_name == "invite") { + // Invite(user, channel, server, line).execute(); + // } + break; + case 'j': + // if (command_name == "join") { + // Join(user, channel, server, line).execute(); + // } + break; + case 'k': + // if (command_name == "kick") { + // Kick(user, channel, server, line).execute(); + // } + break; + case 'l': + // if (command_name == "list") { + // List(user, channel, server, line).execute(); + // } + break; + case 'm': + // if (command_name == "mode") { + // Mode(user, channel, server, line).execute(); + // } + break; + case 'n': + // if (command_name == "nick") { + // Nick(user, channel, server, line).execute(); + // } else if (command_name == "notice") { + // Notice(user, channel, server, line).execute(); + // } + break; + case 'p': + // if (command_name == "part") { + // Part(user, channel, server, line).execute(); + // } + break; + default: + WARNING_MSG("Unknown command: " << command_name); + } + (void)user; + (void)server; + (void)channel; + (void)line; +} + +cmd::ACommand::ACommand(::User *user, ::Channel *channel, ::Server *server, const std::string &line) : _sender(user), _channel(channel), _server(server) { + DEBUG_MSG("ACommand constructor called"); + _args = split(line); + _command = _args.at(0); + _channels = server->getChannelsList(); + _users = server->getUsersList(); + _uTarget = NULL; + _cTarget = NULL; +} + +cmd::ACommand::~ACommand() { + DEBUG_MSG("ACommand destructor called"); +} diff --git a/sources/commands/invite.cpp b/sources/commands/invite.cpp new file mode 100644 index 0000000..b2e4612 --- /dev/null +++ b/sources/commands/invite.cpp @@ -0,0 +1,64 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* invite.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: rparodi +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/24 17:29:48 by rparodi #+# #+# */ +/* Updated: 2025/05/26 22:50:04 by rparodi ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "invite.hpp" +#include "commands.hpp" +#include "logs.hpp" + +using namespace cmd; + +bool Invite::checkArgs() { + if (_args.size() < 3) { + WARNING_MSG("Not enough arguments for INVITE command"); + return false; + } + if (_args.at(1).at(0) != '#') { + WARNING_MSG("Invalid channel name for INVITE command"); + INFO_MSG("Channel names must start with a '#' character"); + return false; + } + _cTarget = searchList(_channels, _args.at(1)); + if (_cTarget == NULL) { + WARNING_MSG("Channel not found for INVITE command"); + INFO_MSG("You can only invite users to channels you are in"); + return false; + } else + _args.at(1).erase(0, 1); + if (searchList(_cTarget->getOperators(), _sender->getName()) != NULL) { + WARNING_MSG("You are not an operator in the channel for INVITE command"); + return false; + } + _uTarget = searchList(this->_users, _args.at(2)); + if (this->_uTarget == NULL) { + WARNING_MSG("User not found"); + return false; + } + if (this->_uTarget->isRegistered() == false) { + WARNING_MSG("User is not registered for INVITE command"); + INFO_MSG("You can only invite registered users"); + return false; + } + if (searchList(this->_cTarget->getUsers(), this->_uTarget->getName())) { + WARNING_MSG("User is already in the channel for INVITE command"); + INFO_MSG("You cannot invite a user who is already in the channel"); + return false; + } + return true; +} + +void Invite::execute() { + if (checkArgs() == false) { + ERROR_MSG("Invalid arguments for INVITE command (see warning message)"); + return; + } + // check how the com +} diff --git a/sources/commands/join.cpp b/sources/commands/join.cpp new file mode 100644 index 0000000..031e676 --- /dev/null +++ b/sources/commands/join.cpp @@ -0,0 +1,52 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* join.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: rparodi +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/24 17:29:48 by rparodi #+# #+# */ +/* Updated: 2025/05/26 22:56:16 by rparodi ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "join.hpp" +#include "commands.hpp" +#include "logs.hpp" + +using namespace cmd; + +bool Join::checkArgs() { + if (_args.size() < 2) { + WARNING_MSG("Not enough arguments for Join command"); + return false; + } + if (_args.at(1).at(0) != '#') { + WARNING_MSG("Invalid channel name for Join command"); + INFO_MSG("Channel names must start with a '#' character"); + return false; + } else + _args.at(1).erase(0, 1); + _cTarget = searchList(_channels, _args.at(1)); + if (_cTarget == NULL) { + WARNING_MSG("Channel not found for Join command"); + INFO_MSG("You can only Join users to channels you are in"); + return false; + } + if (searchList(_cTarget->getOperators(), _sender->getName()) != NULL) { + WARNING_MSG("You are not an operator in the channel for Join command"); + return false; + } + if (searchList(_cTarget->getInvited(), _sender->getName()) != NULL) { + WARNING_MSG("This channel is private and ur not invited"); + return false; + } + return true; +} + +void Join::execute() { + if (checkArgs() == false) { + ERROR_MSG("Invalid arguments for Join command (see warning message)"); + return; + } +} diff --git a/sources/core/Server.cpp b/sources/core/Server.cpp index 2e365f2..0bd410a 100644 --- a/sources/core/Server.cpp +++ b/sources/core/Server.cpp @@ -6,7 +6,7 @@ /* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/13 11:11:07 by rparodi #+# #+# */ -/* Updated: 2025/05/22 18:45:41 by omoudni ### ########.fr */ +/* Updated: 2025/05/26 22:30:07 by rparodi ### ########.fr */ /* */ /******************************************************************************/ @@ -14,6 +14,7 @@ #include "server.hpp" #include "core.hpp" #include "PollManager.hpp" +#include "logs.hpp" #include #include #include @@ -146,3 +147,17 @@ void Server::printUsers() const std::cout << "Nickname: " << it->second->getName() << std::endl; } } + +std::list Server::getUsersList() const { + // to_delete when done + WARNING_MSG("TO DO FILL") + std::list userList; + for (std::map::const_iterator it = _users.begin(); it != _users.end(); ++it) { + userList.push_back(it->second); + } + return userList; +} + +std::list Server::getChannelsList() const { + return this->_channels; +} diff --git a/sources/core/logs.cpp b/sources/core/logs.cpp deleted file mode 100644 index 8b75ec8..0000000 --- a/sources/core/logs.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* logs.cpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: rparodi +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2025/05/15 12:29:56 by rparodi #+# #+# */ -/* Updated: 2025/05/15 12:38:56 by rparodi ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "logs.hpp" - -void print_debug(const char *str, const char *file, int line) -{ - if (DEBUG) - std::cout << CLR_CYAN << "\tDebug: " << str << "(" << file << ":" << line << ")" << CLR_RESET << std::endl; -} - -void print_error(const char *str, const char *file, int line) -{ - std::cerr << CLR_RED << "\tError: " << str << "(" << file << ":" << line << ")" << CLR_RESET << std::endl; -} - -void print_warning(const char *str, const char *file, int line) -{ - std::cerr << CLR_YELLOW << "\tWarning: " << str << "(" << file << ":" << line << ")" << CLR_RESET << std::endl; -} - -void print_info(const char *str, const char *file, int line) -{ - std::cout << CLR_GREY << "\tInfo: " << str << "(" << file << ":" << line << ")" << CLR_RESET << std::endl; -} - -void print_success(const char *str, const char *file, int line) -{ - std::cout << CLR_GREEN << "\tSuccess: " << str << "(" << file << ":" << line << ")" << CLR_RESET << std::endl; -}